blob: ca5d3b8d213caee1af4eb6ca0e36c596f5cfbb11 [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
Duncan Laurie1f7fd722015-06-22 11:14:48 -070031static int ifd_version;
Bill XIEb3e15a22017-09-07 18:34:50 +080032static int chipset;
Bill XIEfa5f9942017-09-12 11:22:29 +080033static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010034static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070035static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050036
Duncan Laurie1f7fd722015-06-22 11:14:48 -070037static const struct region_name region_names[MAX_REGIONS] = {
Mathew Kingc7ddc992019-08-08 14:59:25 -060038 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin", "SI_DESC" },
39 { "BIOS", "bios", "flashregion_1_bios.bin", "SI_BIOS" },
40 { "Intel ME", "me", "flashregion_2_intel_me.bin", "SI_ME" },
41 { "GbE", "gbe", "flashregion_3_gbe.bin", "SI_GBE" },
42 { "Platform Data", "pd", "flashregion_4_platform_data.bin", "SI_PDR" },
43 { "Reserved", "res1", "flashregion_5_reserved.bin", NULL },
44 { "Reserved", "res2", "flashregion_6_reserved.bin", NULL },
45 { "Reserved", "res3", "flashregion_7_reserved.bin", NULL },
46 { "EC", "ec", "flashregion_8_ec.bin", "SI_EC" },
Chris Douglass03ce0142014-02-26 13:30:13 -050047};
48
Bill XIEb3e15a22017-09-07 18:34:50 +080049/* port from flashrom */
50static const char *const ich_chipset_names[] = {
51 "Unknown ICH",
52 "ICH",
53 "ICH2345",
54 "ICH6",
55 "SCH U",
56 "Atom E6xx",
57 "Atom S1220 S1240 S1260",
58 "ICH7",
59 "ICH8",
60 "ICH9",
61 "ICH10",
Subrata Banik89db2252020-08-26 14:49:17 +053062 "Unknown PCH",
Bill XIEb3e15a22017-09-07 18:34:50 +080063 "5 series Ibex Peak",
64 "6 series Cougar Point",
65 "7 series Panther Point",
66 "8 series Lynx Point",
67 "Baytrail",
68 "8 series Lynx Point LP",
69 "8 series Wellsburg",
70 "9 series Wildcat Point",
71 "9 series Wildcat Point LP",
Subrata Banik8c082e52021-06-10 23:02:29 +053072 "Apollo Lake: N3xxx, J3xxx",
Subrata Banik89db2252020-08-26 14:49:17 +053073 "Gemini Lake: N5xxx, J5xxx, N4xxx, J4xxx",
Subrata Banik8c082e52021-06-10 23:02:29 +053074 "Jasper Lake: N6xxx, N51xx, N45xx",
75 "Elkhart Lake: x6000 series Atom",
Subrata Banik89db2252020-08-26 14:49:17 +053076 "100/200 series Sunrise Point",
Subrata Banik8c082e52021-06-10 23:02:29 +053077 "300 series Cannon Point",
78 "400 series Ice Point",
Subrata Banika5f47812020-09-29 11:43:01 +053079 "500 series Tiger Point/ 600 series Alder Point",
Bill XIEb3e15a22017-09-07 18:34:50 +080080 "C620 series Lewisburg",
81 NULL
82};
83
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070084static fdbar_t *find_fd(char *image, int size)
85{
86 int i, found = 0;
87
88 /* Scan for FD signature */
89 for (i = 0; i < (size - 4); i += 4) {
90 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
91 found = 1;
92 break; // signature found.
93 }
94 }
95
96 if (!found) {
97 printf("No Flash Descriptor found in this image\n");
98 return NULL;
99 }
100
Bill XIE612ec0e2017-08-30 16:10:27 +0800101 fdbar_t *fdb = (fdbar_t *) (image + i);
102 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
103}
104
Stefan Tauner0d226142018-08-05 18:56:53 +0200105static char *find_flumap(char *image, int size)
106{
107 /* The upper map is located in the word before the 256B-long OEM section
108 * at the end of the 4kB-long flash descriptor. In the official
109 * documentation this is defined as FDBAR + 0xEFC. However, starting
110 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
111 * has moved 16 bytes back to offset 0x10 of the image. Although
112 * official documentation still maintains the offset relative to FDBAR
113 * this is wrong and a simple fixed offset from the start of the image
114 * works.
115 */
116 char *flumap = image + 4096 - 256 - 4;
117 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
118}
119
Bill XIE612ec0e2017-08-30 16:10:27 +0800120static fcba_t *find_fcba(char *image, int size)
121{
122 fdbar_t *fdb = find_fd(image, size);
123 if (!fdb)
124 return NULL;
125 fcba_t *fcba = (fcba_t *) (image + ((fdb->flmap0 & 0xff) << 4));
126 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
127
128}
129
130static fmba_t *find_fmba(char *image, int size)
131{
132 fdbar_t *fdb = find_fd(image, size);
133 if (!fdb)
134 return NULL;
135 fmba_t *fmba = (fmba_t *) (image + ((fdb->flmap1 & 0xff) << 4));
136 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
137}
138
139static frba_t *find_frba(char *image, int size)
140{
141 fdbar_t *fdb = find_fd(image, size);
142 if (!fdb)
143 return NULL;
144 frba_t *frba =
145 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
146 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
147}
148
149static fpsba_t *find_fpsba(char *image, int size)
150{
151 fdbar_t *fdb = find_fd(image, size);
152 if (!fdb)
153 return NULL;
154 fpsba_t *fpsba =
155 (fpsba_t *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200156
157 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
158 if ((((char *)fpsba) + SSL) >= (image + size))
159 return NULL;
160 return fpsba;
Bill XIE612ec0e2017-08-30 16:10:27 +0800161}
162
163static fmsba_t *find_fmsba(char *image, int size)
164{
165 fdbar_t *fdb = find_fd(image, size);
166 if (!fdb)
167 return NULL;
168 fmsba_t *fmsba = (fmsba_t *) (image + ((fdb->flmap2 & 0xff) << 4));
169 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700170}
171
Bill XIEb3e15a22017-09-07 18:34:50 +0800172/* port from flashrom */
Subrata Banik8c082e52021-06-10 23:02:29 +0530173static enum ich_chipset ifd1_guess_chipset(char *image, int size)
Bill XIEb3e15a22017-09-07 18:34:50 +0800174{
Subrata Banik8c082e52021-06-10 23:02:29 +0530175 const fdbar_t *fdb = find_fd(image, size);
176 if (!fdb)
177 exit(EXIT_FAILURE);
Bill XIEb3e15a22017-09-07 18:34:50 +0800178 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
179 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
180 uint32_t isl = (fdb->flmap1 >> 24);
181 uint32_t nm = (fdb->flmap1 >> 8) & 0x7;
Subrata Banik89db2252020-08-26 14:49:17 +0530182
183 /* Rest for IFD1 chipset type */
Bill XIEb3e15a22017-09-07 18:34:50 +0800184 if (iccriba == 0x00) {
185 if (msl == 0 && isl <= 2)
186 return CHIPSET_ICH8;
187 else if (isl <= 2)
188 return CHIPSET_ICH9;
189 else if (isl <= 10)
190 return CHIPSET_ICH10;
191 else if (isl <= 16)
192 return CHIPSET_5_SERIES_IBEX_PEAK;
193 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
194 return CHIPSET_5_SERIES_IBEX_PEAK;
195 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
196 if (msl == 0 && isl <= 17)
197 return CHIPSET_BAYTRAIL;
198 else if (msl <= 1 && isl <= 18)
199 return CHIPSET_6_SERIES_COUGAR_POINT;
200 else if (msl <= 1 && isl <= 21)
201 return CHIPSET_8_SERIES_LYNX_POINT;
202 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
203 return CHIPSET_9_SERIES_WILDCAT_POINT;
204 } else if (nm == 6) {
205 return CHIPSET_C620_SERIES_LEWISBURG;
Bill XIEb3e15a22017-09-07 18:34:50 +0800206 }
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200207 return CHIPSET_PCH_UNKNOWN;
Bill XIEb3e15a22017-09-07 18:34:50 +0800208}
209
Subrata Banik8c082e52021-06-10 23:02:29 +0530210static enum ich_chipset ifd2_platform_to_chipset(const int pindex)
211{
212 switch (pindex) {
Subrata Banik6da003c2021-07-14 13:52:03 +0530213 case PLATFORM_APL:
214 return CHIPSET_N_J_SERIES_APOLLO_LAKE;
Subrata Banik8c082e52021-06-10 23:02:29 +0530215 case PLATFORM_GLK:
216 return CHIPSET_N_J_SERIES_GEMINI_LAKE;
217 case PLATFORM_JSL:
218 return CHIPSET_N_SERIES_JASPER_LAKE;
219 case PLATFORM_EHL:
220 return CHIPSET_x6000_SERIES_ELKHART_LAKE;
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200221 case PLATFORM_SKLKBL:
222 return CHIPSET_100_200_SERIES_SUNRISE_POINT;
Subrata Banik8c082e52021-06-10 23:02:29 +0530223 case PLATFORM_CNL:
224 return CHIPSET_300_SERIES_CANNON_POINT;
225 case PLATFORM_TGL:
226 case PLATFORM_ADL:
227 return CHIPSET_500_600_SERIES_TIGER_ALDER_POINT;
228 case PLATFORM_ICL:
229 return CHIPSET_400_SERIES_ICE_POINT;
Johnny Line273a022021-06-22 11:26:46 +0800230 case PLATFORM_LBG:
231 return CHIPSET_C620_SERIES_LEWISBURG;
Subrata Banik8c082e52021-06-10 23:02:29 +0530232 default:
233 return CHIPSET_PCH_UNKNOWN;
234 }
235}
236
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700237/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700238 * Some newer platforms have re-defined the FCBA field that was used to
239 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
240 * have the required FCBA field, but are IFD v2 and return true if current
241 * platform is one of them.
242 */
243static int is_platform_ifd_2(void)
244{
245 static const int ifd_2_platforms[] = {
Subrata Banik6da003c2021-07-14 13:52:03 +0530246 PLATFORM_APL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700247 PLATFORM_GLK,
248 PLATFORM_CNL,
Johnny Line273a022021-06-22 11:26:46 +0800249 PLATFORM_LBG,
Aamir Bohra1018be22018-06-29 15:08:50 +0530250 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700251 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530252 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700253 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530254 PLATFORM_ADL,
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200255 PLATFORM_SKLKBL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700256 };
257 unsigned int i;
258
259 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
260 if (platform == ifd_2_platforms[i])
261 return 1;
262 }
263
264 return 0;
265}
266
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700267static void check_ifd_version(char *image, int size)
268{
Subrata Banik8c082e52021-06-10 23:02:29 +0530269 if (is_platform_ifd_2()) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700270 ifd_version = IFD_VERSION_2;
Subrata Banik8c082e52021-06-10 23:02:29 +0530271 chipset = ifd2_platform_to_chipset(platform);
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700272 max_regions = MAX_REGIONS;
Subrata Banik8c082e52021-06-10 23:02:29 +0530273 } else {
274 ifd_version = IFD_VERSION_1;
275 chipset = ifd1_guess_chipset(image, size);
276 max_regions = MAX_REGIONS_OLD;
277 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700278}
279
Bill XIEfa5f9942017-09-12 11:22:29 +0800280static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700281{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500282 int base_mask;
283 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700284 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700285 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500286
287 if (ifd_version >= IFD_VERSION_2)
288 base_mask = 0x7fff;
289 else
290 base_mask = 0xfff;
291
292 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700293
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400294 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800295 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700296 exit (EXIT_FAILURE);
297 }
298
Bill XIE4651d452017-09-12 11:54:48 +0800299 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700300 region.base = (flreg & base_mask) << 12;
301 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700302 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500303
Chris Douglass03ce0142014-02-26 13:30:13 -0500304 if (region.size < 0)
305 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700306
307 return region;
308}
309
Bill XIEfa5f9942017-09-12 11:22:29 +0800310static void set_region(frba_t *frba, unsigned int region_type,
311 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500312{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400313 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800314 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500315 exit (EXIT_FAILURE);
316 }
Bill XIE4651d452017-09-12 11:54:48 +0800317
318 frba->flreg[region_type] =
319 (((region->limit >> 12) & 0x7fff) << 16) |
320 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500321}
322
Bill XIEfa5f9942017-09-12 11:22:29 +0800323static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700324{
Bill XIEfa5f9942017-09-12 11:22:29 +0800325 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700326 fprintf(stderr, "Invalid region type.\n");
327 exit (EXIT_FAILURE);
328 }
329
Chris Douglass03ce0142014-02-26 13:30:13 -0500330 return region_names[region_type].pretty;
331}
332
Bill XIEfa5f9942017-09-12 11:22:29 +0800333static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500334{
Bill XIEfa5f9942017-09-12 11:22:29 +0800335 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500336 fprintf(stderr, "Invalid region type.\n");
337 exit (EXIT_FAILURE);
338 }
339
340 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700341}
342
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500343static int region_num(const char *name)
344{
Bill XIEfa5f9942017-09-12 11:22:29 +0800345 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500346
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200347 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500348 if (strcasecmp(name, region_names[i].pretty) == 0)
349 return i;
350 if (strcasecmp(name, region_names[i].terse) == 0)
351 return i;
352 }
353
354 return -1;
355}
356
Bill XIEfa5f9942017-09-12 11:22:29 +0800357static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700358{
Bill XIEfa5f9942017-09-12 11:22:29 +0800359 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700360 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700361 exit (EXIT_FAILURE);
362 }
363
Bill XIE1bf65062017-09-12 11:31:37 +0800364 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700365}
366
Bill XIEfa5f9942017-09-12 11:22:29 +0800367static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700368{
369 region_t region = get_region(frba, num);
370 printf(" Flash Region %d (%s): %08x - %08x %s\n",
371 num, region_name(num), region.base, region.limit,
372 region.size < 1 ? "(unused)" : "");
373}
374
Bill XIEfa5f9942017-09-12 11:22:29 +0800375static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
376 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500377{
378 region_t region = get_region(frba, num);
379 snprintf(buf, bufsize, "%08x:%08x %s\n",
380 region.base, region.limit, region_name_short(num));
381}
382
Bill XIEfa5f9942017-09-12 11:22:29 +0800383static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700384{
Bill XIE4651d452017-09-12 11:54:48 +0800385 unsigned int i;
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530386 region_t region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700387 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800388 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530389 region = get_region(frba, i);
390 /* Skip unused & reserved Flash Region */
391 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
392 continue;
393
Bill XIE4651d452017-09-12 11:54:48 +0800394 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
395 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700396 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700397}
398
Bill XIEfa5f9942017-09-12 11:22:29 +0800399static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500400{
401 char buf[LAYOUT_LINELEN];
402 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800403 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500404
405 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
406 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
407 if (layout_fd == -1) {
408 perror("Could not open file");
409 exit(EXIT_FAILURE);
410 }
411
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200412 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200413 region_t region = get_region(frba, i);
414 /* is region invalid? */
415 if (region.size < 1)
416 continue;
417
Chris Douglass03ce0142014-02-26 13:30:13 -0500418 dump_region_layout(buf, bufsize, i, frba);
419 if (write(layout_fd, buf, strlen(buf)) < 0) {
420 perror("Could not write to file");
421 exit(EXIT_FAILURE);
422 }
423 }
424 close(layout_fd);
425 printf("Wrote layout to %s\n", layout_fname);
426}
427
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530428static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700429{
430 switch (freq) {
431 case SPI_FREQUENCY_20MHZ:
432 printf("20MHz");
433 break;
434 case SPI_FREQUENCY_33MHZ:
435 printf("33MHz");
436 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700437 case SPI_FREQUENCY_48MHZ:
438 printf("48MHz");
439 break;
440 case SPI_FREQUENCY_50MHZ_30MHZ:
441 switch (ifd_version) {
442 case IFD_VERSION_1:
443 printf("50MHz");
444 break;
445 case IFD_VERSION_2:
446 printf("30MHz");
447 break;
448 }
449 break;
450 case SPI_FREQUENCY_17MHZ:
451 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700452 break;
453 default:
454 printf("unknown<%x>MHz", freq);
455 }
456}
457
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530458static void _decode_spi_frequency_500_series(unsigned int freq)
459{
460 switch (freq) {
461 case SPI_FREQUENCY_100MHZ:
462 printf("100MHz");
463 break;
464 case SPI_FREQUENCY_50MHZ:
465 printf("50MHz");
466 break;
467 case SPI_FREQUENCY_500SERIES_33MHZ:
468 printf("33MHz");
469 break;
470 case SPI_FREQUENCY_25MHZ:
471 printf("25MHz");
472 break;
473 case SPI_FREQUENCY_14MHZ:
474 printf("14MHz");
475 break;
476 default:
477 printf("unknown<%x>MHz", freq);
478 }
479}
480
481static void decode_spi_frequency(unsigned int freq)
482{
Subrata Banika5f47812020-09-29 11:43:01 +0530483 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530484 _decode_spi_frequency_500_series(freq);
485 else
486 _decode_spi_frequency(freq);
487}
488
Subrata Banike5d39922020-08-26 16:01:42 +0530489static void _decode_espi_frequency(unsigned int freq)
490{
491 switch (freq) {
492 case ESPI_FREQUENCY_20MHZ:
493 printf("20MHz");
494 break;
495 case ESPI_FREQUENCY_24MHZ:
496 printf("24MHz");
497 break;
498 case ESPI_FREQUENCY_30MHZ:
499 printf("30MHz");
500 break;
501 case ESPI_FREQUENCY_48MHZ:
502 printf("48MHz");
503 break;
504 case ESPI_FREQUENCY_60MHZ:
505 printf("60MHz");
506 break;
507 case ESPI_FREQUENCY_17MHZ:
508 printf("17MHz");
509 break;
510 default:
511 printf("unknown<%x>MHz", freq);
512 }
513}
514
515static void _decode_espi_frequency_500_series(unsigned int freq)
516{
517 switch (freq) {
518 case ESPI_FREQUENCY_500SERIES_20MHZ:
519 printf("20MHz");
520 break;
521 case ESPI_FREQUENCY_500SERIES_24MHZ:
522 printf("24MHz");
523 break;
524 case ESPI_FREQUENCY_500SERIES_25MHZ:
525 printf("25MHz");
526 break;
527 case ESPI_FREQUENCY_500SERIES_48MHZ:
528 printf("48MHz");
529 break;
530 case ESPI_FREQUENCY_500SERIES_60MHZ:
531 printf("60MHz");
532 break;
533 default:
534 printf("unknown<%x>MHz", freq);
535 }
536}
537
538static void decode_espi_frequency(unsigned int freq)
539{
Subrata Banika5f47812020-09-29 11:43:01 +0530540 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530541 _decode_espi_frequency_500_series(freq);
542 else
543 _decode_espi_frequency(freq);
544}
545
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700546static void decode_component_density(unsigned int density)
547{
548 switch (density) {
549 case COMPONENT_DENSITY_512KB:
550 printf("512KB");
551 break;
552 case COMPONENT_DENSITY_1MB:
553 printf("1MB");
554 break;
555 case COMPONENT_DENSITY_2MB:
556 printf("2MB");
557 break;
558 case COMPONENT_DENSITY_4MB:
559 printf("4MB");
560 break;
561 case COMPONENT_DENSITY_8MB:
562 printf("8MB");
563 break;
564 case COMPONENT_DENSITY_16MB:
565 printf("16MB");
566 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700567 case COMPONENT_DENSITY_32MB:
568 printf("32MB");
569 break;
570 case COMPONENT_DENSITY_64MB:
571 printf("64MB");
572 break;
573 case COMPONENT_DENSITY_UNUSED:
574 printf("UNUSED");
575 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700576 default:
577 printf("unknown<%x>MB", density);
578 }
579}
580
Subrata Banik26058dc2020-08-26 15:12:16 +0530581static int is_platform_with_pch(void)
582{
583 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
584 return 1;
585
586 return 0;
587}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530588
589/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
590static int is_platform_with_100x_series_pch(void)
591{
592 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530593 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530594 return 1;
595
596 return 0;
597}
598
Subrata Banike5d39922020-08-26 16:01:42 +0530599static void dump_fcba(const fcba_t *fcba, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700600{
Subrata Banike5d39922020-08-26 16:01:42 +0530601 unsigned int freq;
602
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700603 printf("\nFound Component Section\n");
604 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700605 printf(" Dual Output Fast Read Support: %ssupported\n",
606 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700607 printf(" Read ID/Read Status Clock Frequency: ");
608 decode_spi_frequency((fcba->flcomp >> 27) & 7);
609 printf("\n Write/Erase Clock Frequency: ");
610 decode_spi_frequency((fcba->flcomp >> 24) & 7);
611 printf("\n Fast Read Clock Frequency: ");
612 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700613 printf("\n Fast Read Support: %ssupported",
614 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530615 if (is_platform_with_100x_series_pch() &&
616 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
617 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530618 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530619 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
620 else
621 freq = (fcba->flcomp >> 17) & 7;
622 decode_espi_frequency(freq);
623 } else {
624 printf("\n Read Clock Frequency: ");
625 decode_spi_frequency((fcba->flcomp >> 17) & 7);
626 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700627
628 switch (ifd_version) {
629 case IFD_VERSION_1:
630 printf("\n Component 2 Density: ");
631 decode_component_density((fcba->flcomp >> 3) & 7);
632 printf("\n Component 1 Density: ");
633 decode_component_density(fcba->flcomp & 7);
634 break;
635 case IFD_VERSION_2:
636 printf("\n Component 2 Density: ");
637 decode_component_density((fcba->flcomp >> 4) & 0xf);
638 printf("\n Component 1 Density: ");
639 decode_component_density(fcba->flcomp & 0xf);
640 break;
641 }
642
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700643 printf("\n");
644 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700645 printf(" Invalid Instruction 3: 0x%02x\n",
646 (fcba->flill >> 24) & 0xff);
647 printf(" Invalid Instruction 2: 0x%02x\n",
648 (fcba->flill >> 16) & 0xff);
649 printf(" Invalid Instruction 1: 0x%02x\n",
650 (fcba->flill >> 8) & 0xff);
651 printf(" Invalid Instruction 0: 0x%02x\n",
652 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530653 if (is_platform_with_100x_series_pch()) {
654 printf("FLILL1 0x%08x\n", fcba->flpb);
655 printf(" Invalid Instruction 7: 0x%02x\n",
656 (fcba->flpb >> 24) & 0xff);
657 printf(" Invalid Instruction 6: 0x%02x\n",
658 (fcba->flpb >> 16) & 0xff);
659 printf(" Invalid Instruction 5: 0x%02x\n",
660 (fcba->flpb >> 8) & 0xff);
661 printf(" Invalid Instruction 4: 0x%02x\n",
662 fcba->flpb & 0xff);
663 } else {
664 printf("FLPB 0x%08x\n", fcba->flpb);
665 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
666 (fcba->flpb & 0xfff) << 12);
667 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700668}
669
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200670static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700671{
Bill XIE4651d452017-09-12 11:54:48 +0800672 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200673 /* SoC Strap Length, aka PSL, aka ISL */
674 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
675
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700676 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200677 for (i = 0; i < SSL; i++)
678 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800679
680 if (ifd_version >= IFD_VERSION_2) {
681 printf("HAP bit is %sset\n",
682 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
683 } else if (chipset >= CHIPSET_ICH8
684 && chipset <= CHIPSET_ICH10) {
685 printf("ICH_MeDisable bit is %sset\n",
686 fpsba->pchstrp[0] & 1 ? "" : "not ");
687 } else {
688 printf("AltMeDisable bit is %sset\n",
689 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
690 }
691
Bill XIE4651d452017-09-12 11:54:48 +0800692 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700693}
694
695static void decode_flmstr(uint32_t flmstr)
696{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700697 int wr_shift, rd_shift;
698 if (ifd_version >= IFD_VERSION_2) {
699 wr_shift = FLMSTR_WR_SHIFT_V2;
700 rd_shift = FLMSTR_RD_SHIFT_V2;
701 } else {
702 wr_shift = FLMSTR_WR_SHIFT_V1;
703 rd_shift = FLMSTR_RD_SHIFT_V1;
704 }
705
706 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700707 if (ifd_version >= IFD_VERSION_2)
708 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700709 (flmstr & (1 << (wr_shift + 8))) ?
710 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700711 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700712 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700713 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700714 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700715 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700716 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700717 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700718 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700719 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700720 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700721
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700722 if (ifd_version >= IFD_VERSION_2)
723 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700724 (flmstr & (1 << (rd_shift + 8))) ?
725 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700726 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700727 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700728 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700729 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700730 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700731 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700732 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700733 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700734 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700735 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700736
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700737 /* Requestor ID doesn't exist for ifd 2 */
738 if (ifd_version < IFD_VERSION_2)
739 printf(" Requester ID: 0x%04x\n\n",
740 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700741}
742
Bill XIEfa5f9942017-09-12 11:22:29 +0800743static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700744{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700745 printf("Found Master Section\n");
746 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
747 decode_flmstr(fmba->flmstr1);
748 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
749 decode_flmstr(fmba->flmstr2);
750 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
751 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700752 if (ifd_version >= IFD_VERSION_2) {
753 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
754 decode_flmstr(fmba->flmstr5);
755 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700756}
757
Bill XIEfa5f9942017-09-12 11:22:29 +0800758static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700759{
Bill XIE612ec0e2017-08-30 16:10:27 +0800760 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700761 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800762 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
763 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800764
765 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
766 printf("MCH_MeDisable bit is %sset\n",
767 fmsba->data[0] & 1 ? "" : "not ");
768 printf("MCH_AltMeDisable bit is %sset\n",
769 fmsba->data[0] & (1 << 7) ? "" : "not ");
770 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700771}
772
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700773static void dump_jid(uint32_t jid)
774{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100775 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700776 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100777 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200778 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100779 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200780 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700781}
782
783static void dump_vscc(uint32_t vscc)
784{
785 printf(" Lower Erase Opcode: 0x%02x\n",
786 vscc >> 24);
787 printf(" Lower Write Enable on Write Status: 0x%02x\n",
788 vscc & (1 << 20) ? 0x06 : 0x50);
789 printf(" Lower Write Status Required: %s\n",
790 vscc & (1 << 19) ? "Yes" : "No");
791 printf(" Lower Write Granularity: %d bytes\n",
792 vscc & (1 << 18) ? 64 : 1);
793 printf(" Lower Block / Sector Erase Size: ");
794 switch ((vscc >> 16) & 0x3) {
795 case 0:
796 printf("256 Byte\n");
797 break;
798 case 1:
799 printf("4KB\n");
800 break;
801 case 2:
802 printf("8KB\n");
803 break;
804 case 3:
805 printf("64KB\n");
806 break;
807 }
808
809 printf(" Upper Erase Opcode: 0x%02x\n",
810 (vscc >> 8) & 0xff);
811 printf(" Upper Write Enable on Write Status: 0x%02x\n",
812 vscc & (1 << 4) ? 0x06 : 0x50);
813 printf(" Upper Write Status Required: %s\n",
814 vscc & (1 << 3) ? "Yes" : "No");
815 printf(" Upper Write Granularity: %d bytes\n",
816 vscc & (1 << 2) ? 64 : 1);
817 printf(" Upper Block / Sector Erase Size: ");
818 switch (vscc & 0x3) {
819 case 0:
820 printf("256 Byte\n");
821 break;
822 case 1:
823 printf("4KB\n");
824 break;
825 case 2:
826 printf("8KB\n");
827 break;
828 case 3:
829 printf("64KB\n");
830 break;
831 }
832}
833
Bill XIEfa5f9942017-09-12 11:22:29 +0800834static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700835{
836 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200837 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
838 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700839
840 printf("ME VSCC table:\n");
841 for (i = 0; i < num; i++) {
842 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
843 dump_jid(vtba->entry[i].jid);
844 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
845 dump_vscc(vtba->entry[i].vscc);
846 }
847 printf("\n");
848}
849
Bill XIEfa5f9942017-09-12 11:22:29 +0800850static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700851{
852 int i, j;
853 printf("OEM Section:\n");
854 for (i = 0; i < 4; i++) {
855 printf("%02x:", i << 4);
856 for (j = 0; j < 16; j++)
857 printf(" %02x", oem[(i<<4)+j]);
858 printf ("\n");
859 }
860 printf ("\n");
861}
862
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700863static void dump_fd(char *image, int size)
864{
Bill XIE612ec0e2017-08-30 16:10:27 +0800865 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700866 if (!fdb)
867 exit(EXIT_FAILURE);
868
Subrata Banik26058dc2020-08-26 15:12:16 +0530869 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
870 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700871 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530872 if (!is_platform_with_100x_series_pch())
873 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700874 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
875 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
876 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
877
878 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530879 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
880 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700881 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
882 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
883 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
884
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530885 if (!is_platform_with_100x_series_pch()) {
886 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
887 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
888 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
889 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700890
Subrata Banika5f47812020-09-29 11:43:01 +0530891 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530892 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
893 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
894 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
895 }
896
Stefan Tauner0d226142018-08-05 18:56:53 +0200897 char *flumap = find_flumap(image, size);
898 uint32_t flumap1 = *(uint32_t *)flumap;
899 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700900 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200901 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700902 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200903 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700904 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200905 (image + ((flumap1 & 0xff) << 4)),
906 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800907 dump_oem((const uint8_t *)image + 0xf00);
908
909 const frba_t *frba = find_frba(image, size);
910 const fcba_t *fcba = find_fcba(image, size);
911 const fpsba_t *fpsba = find_fpsba(image, size);
912 const fmba_t *fmba = find_fmba(image, size);
913 const fmsba_t *fmsba = find_fmsba(image, size);
914
915 if (frba && fcba && fpsba && fmba && fmsba) {
916 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +0530917 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200918 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800919 dump_fmba(fmba);
920 dump_fmsba(fmsba);
921 } else {
922 printf("FD is corrupted!\n");
923 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700924}
925
Bill XIEfa5f9942017-09-12 11:22:29 +0800926static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500927{
Bill XIE612ec0e2017-08-30 16:10:27 +0800928 const frba_t *frba = find_frba(image, size);
929 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500930 exit(EXIT_FAILURE);
931
Bill XIE612ec0e2017-08-30 16:10:27 +0800932 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500933}
934
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700935static void write_regions(char *image, int size)
936{
Bill XIEfa5f9942017-09-12 11:22:29 +0800937 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800938 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700939
Bill XIE612ec0e2017-08-30 16:10:27 +0800940 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700941 exit(EXIT_FAILURE);
942
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700943 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700944 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700945 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700946 if (region.size > 0) {
947 int region_fd;
948 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600949 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700950 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200951 if (region_fd < 0) {
952 perror("Error while trying to open file");
953 exit(EXIT_FAILURE);
954 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700955 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700956 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700957 close(region_fd);
958 }
959 }
960}
961
Mathew Kingc7ddc992019-08-08 14:59:25 -0600962static void validate_layout(char *image, int size)
963{
964 uint i, errors = 0;
965 struct fmap *fmap;
966 long int fmap_loc = fmap_find((uint8_t *)image, size);
967 const frba_t *frba = find_frba(image, size);
968
969 if (fmap_loc < 0 || !frba)
970 exit(EXIT_FAILURE);
971
972 fmap = (struct fmap *)(image + fmap_loc);
973
974 for (i = 0; i < max_regions; i++) {
975 if (region_names[i].fmapname == NULL)
976 continue;
977
978 region_t region = get_region(frba, i);
979
980 if (region.size == 0)
981 continue;
982
983 const struct fmap_area *area =
984 fmap_find_area(fmap, region_names[i].fmapname);
985
986 if (!area)
987 continue;
988
989 if ((uint)region.base != area->offset ||
990 (uint)region.size != area->size) {
991 printf("Region mismatch between %s and %s\n",
992 region_names[i].terse, area->name);
993 printf(" Descriptor region %s:\n", region_names[i].terse);
994 printf(" offset: 0x%08x\n", region.base);
995 printf(" length: 0x%08x\n", region.size);
996 printf(" FMAP area %s:\n", area->name);
997 printf(" offset: 0x%08x\n", area->offset);
998 printf(" length: 0x%08x\n", area->size);
999 errors++;
1000 }
1001 }
1002
1003 if (errors > 0)
1004 exit(EXIT_FAILURE);
1005}
1006
Bill XIEfa5f9942017-09-12 11:22:29 +08001007static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001008{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001009 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001010 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001011
1012 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001013 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001014 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001015 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001016 if (new_fd < 0) {
1017 perror("Error while trying to open file");
1018 exit(EXIT_FAILURE);
1019 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001020 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001021 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001022 close(new_fd);
1023}
1024
Bill XIEfa5f9942017-09-12 11:22:29 +08001025static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001026 enum spi_frequency freq)
1027{
Bill XIE612ec0e2017-08-30 16:10:27 +08001028 fcba_t *fcba = find_fcba(image, size);
1029 if (!fcba)
1030 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001031
1032 /* clear bits 21-29 */
1033 fcba->flcomp &= ~0x3fe00000;
1034 /* Read ID and Read Status Clock Frequency */
1035 fcba->flcomp |= freq << 27;
1036 /* Write and Erase Clock Frequency */
1037 fcba->flcomp |= freq << 24;
1038 /* Fast Read Clock Frequency */
1039 fcba->flcomp |= freq << 21;
1040
1041 write_image(filename, image, size);
1042}
1043
Bill XIEfa5f9942017-09-12 11:22:29 +08001044static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001045{
Bill XIE612ec0e2017-08-30 16:10:27 +08001046 fcba_t *fcba = find_fcba(image, size);
1047 if (!fcba)
1048 exit(EXIT_FAILURE);
1049
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001050 int freq;
1051
1052 switch (ifd_version) {
1053 case IFD_VERSION_1:
1054 freq = SPI_FREQUENCY_20MHZ;
1055 break;
1056 case IFD_VERSION_2:
1057 freq = SPI_FREQUENCY_17MHZ;
1058 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001059 default:
1060 freq = SPI_FREQUENCY_17MHZ;
1061 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001062 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001063
1064 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001065 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001066}
1067
Bill XIEfa5f9942017-09-12 11:22:29 +08001068static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +01001069 unsigned int density)
1070{
Bill XIE612ec0e2017-08-30 16:10:27 +08001071 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001072 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001073 if (!fcba)
1074 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001075
1076 printf("Setting chip density to ");
1077 decode_component_density(density);
1078 printf("\n");
1079
1080 switch (ifd_version) {
1081 case IFD_VERSION_1:
1082 /* fail if selected density is not supported by this version */
1083 if ( (density == COMPONENT_DENSITY_32MB) ||
1084 (density == COMPONENT_DENSITY_64MB) ||
1085 (density == COMPONENT_DENSITY_UNUSED) ) {
1086 printf("error: Selected density not supported in IFD version 1.\n");
1087 exit(EXIT_FAILURE);
1088 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001089 mask = 0x7;
1090 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001091 break;
1092 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001093 mask = 0xf;
1094 chip2_offset = 4;
1095 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001096 default:
1097 printf("error: Unknown IFD version\n");
1098 exit(EXIT_FAILURE);
1099 break;
1100 }
1101
1102 /* clear chip density for corresponding chip */
1103 switch (selected_chip) {
1104 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001105 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001106 break;
1107 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001108 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001109 break;
1110 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001111 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001112 break;
1113 }
1114
1115 /* set the new density */
1116 if (selected_chip == 1 || selected_chip == 0)
1117 fcba->flcomp |= (density); /* first chip */
1118 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001119 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001120
1121 write_image(filename, image, size);
1122}
1123
Duncan Laurie7775d672019-06-06 13:39:26 -07001124static int check_region(const frba_t *frba, unsigned int region_type)
1125{
1126 region_t region;
1127
1128 if (!frba)
1129 return 0;
1130
1131 region = get_region(frba, region_type);
1132 return !!((region.base < region.limit) && (region.size > 0));
1133}
1134
Bill XIEfa5f9942017-09-12 11:22:29 +08001135static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001136{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001137 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001138 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001139 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001140 if (!fmba)
1141 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001142
1143 if (ifd_version >= IFD_VERSION_2) {
1144 wr_shift = FLMSTR_WR_SHIFT_V2;
1145 rd_shift = FLMSTR_RD_SHIFT_V2;
1146
1147 /* Clear non-reserved bits */
1148 fmba->flmstr1 &= 0xff;
1149 fmba->flmstr2 &= 0xff;
1150 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001151 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001152 } else {
1153 wr_shift = FLMSTR_WR_SHIFT_V1;
1154 rd_shift = FLMSTR_RD_SHIFT_V1;
1155
1156 fmba->flmstr1 = 0;
1157 fmba->flmstr2 = 0;
1158 /* Requestor ID */
1159 fmba->flmstr3 = 0x118;
1160 }
1161
Andrey Petrov96ecb772016-10-31 19:31:54 -07001162 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001163 case PLATFORM_APL:
1164 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001165 /* CPU/BIOS can read descriptor and BIOS */
1166 fmba->flmstr1 |= 0x3 << rd_shift;
1167 /* CPU/BIOS can write BIOS */
1168 fmba->flmstr1 |= 0x2 << wr_shift;
1169 /* TXE can read descriptor, BIOS and Device Expansion */
1170 fmba->flmstr2 |= 0x23 << rd_shift;
1171 /* TXE can only write Device Expansion */
1172 fmba->flmstr2 |= 0x20 << wr_shift;
1173 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001174 case PLATFORM_CNL:
1175 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001176 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001177 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301178 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001179 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301180 case PLATFORM_ADL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001181 /* CPU/BIOS can read descriptor and BIOS. */
1182 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1183 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1184 /* CPU/BIOS can write BIOS. */
1185 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1186 /* ME can read descriptor and ME. */
1187 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1188 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001189 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001190 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1191 if (check_region(frba, REGION_GBE)) {
1192 /* BIOS can read/write GbE. */
1193 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1194 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1195 /* ME can read GbE. */
1196 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1197 /* GbE can read descriptor and read/write GbE.. */
1198 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1199 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1200 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1201 }
1202 if (check_region(frba, REGION_PDR)) {
1203 /* BIOS can read/write PDR. */
1204 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1205 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1206 }
1207 if (check_region(frba, REGION_EC)) {
1208 /* BIOS can read EC. */
1209 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1210 /* EC can read descriptor and read/write EC. */
1211 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1212 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1213 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1214 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001215 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001216 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001217 /* CPU/BIOS can read descriptor and BIOS. */
1218 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1219 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1220 /* CPU/BIOS can write BIOS. */
1221 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1222 /* ME can read descriptor and ME. */
1223 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1224 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1225 /* ME can write ME. */
1226 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1227 if (check_region(frba, REGION_GBE)) {
1228 /* BIOS can read GbE. */
1229 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1230 /* BIOS can write GbE. */
1231 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1232 /* ME can read GbE. */
1233 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1234 /* ME can write GbE. */
1235 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1236 /* GbE can write GbE. */
1237 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1238 /* GbE can read GbE. */
1239 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1240 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001241 break;
1242 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001243
1244 write_image(filename, image, size);
1245}
1246
Usha P412679d2020-10-15 11:25:08 +05301247static void enable_cpu_read_me(const char *filename, char *image, int size)
1248{
1249 int rd_shift;
1250 fmba_t *fmba = find_fmba(image, size);
1251
1252 if (!fmba)
1253 exit(EXIT_FAILURE);
1254
1255 if (ifd_version >= IFD_VERSION_2)
1256 rd_shift = FLMSTR_RD_SHIFT_V2;
1257 else
1258 rd_shift = FLMSTR_RD_SHIFT_V1;
1259
1260 /* CPU/BIOS can read ME. */
1261 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1262
1263 write_image(filename, image, size);
1264}
1265
Bill XIEfa5f9942017-09-12 11:22:29 +08001266static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001267{
Bill XIE612ec0e2017-08-30 16:10:27 +08001268 fmba_t *fmba = find_fmba(image, size);
1269 if (!fmba)
1270 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001271
1272 if (ifd_version >= IFD_VERSION_2) {
1273 /* Access bits for each region are read: 19:8 write: 31:20 */
1274 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1275 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1276 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001277 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001278 } else {
1279 fmba->flmstr1 = 0xffff0000;
1280 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001281 /* Keep chipset specific Requester ID */
1282 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001283 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001284
1285 write_image(filename, image, size);
1286}
1287
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001288static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1289 const unsigned int value)
1290{
1291 if (!fpsba || !fdb) {
1292 fprintf(stderr, "Internal error\n");
1293 exit(EXIT_FAILURE);
1294 }
1295
1296 /* SoC Strap Length, aka PSL, aka ISL */
1297 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1298 if (strap >= SSL) {
1299 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1300 exit(EXIT_FAILURE);
1301 }
1302 fpsba->pchstrp[strap] = value;
1303}
1304
Bill XIEb3e15a22017-09-07 18:34:50 +08001305/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001306static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001307{
1308 if (ifd_version >= IFD_VERSION_2) {
1309 printf("%sting the HAP bit to %s Intel ME...\n",
1310 altmedisable?"Set":"Unset",
1311 altmedisable?"disable":"enable");
1312 if (altmedisable)
1313 fpsba->pchstrp[0] |= (1 << 16);
1314 else
1315 fpsba->pchstrp[0] &= ~(1 << 16);
1316 } else {
1317 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1318 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1319 "and MCH_AltMeDisable to %s Intel ME...\n",
1320 altmedisable?"Set":"Unset",
1321 altmedisable?"disable":"enable");
1322 if (altmedisable) {
1323 /* MCH_MeDisable */
1324 fmsba->data[0] |= 1;
1325 /* MCH_AltMeDisable */
1326 fmsba->data[0] |= (1 << 7);
1327 /* ICH_MeDisable */
1328 fpsba->pchstrp[0] |= 1;
1329 } else {
1330 fmsba->data[0] &= ~1;
1331 fmsba->data[0] &= ~(1 << 7);
1332 fpsba->pchstrp[0] &= ~1;
1333 }
1334 } else {
1335 printf("%sting the AltMeDisable to %s Intel ME...\n",
1336 altmedisable?"Set":"Unset",
1337 altmedisable?"disable":"enable");
1338 if (altmedisable)
1339 fpsba->pchstrp[10] |= (1 << 7);
1340 else
1341 fpsba->pchstrp[10] &= ~(1 << 7);
1342 }
1343 }
1344}
1345
Jacob Garber595d9262019-06-27 17:33:10 -06001346static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001347 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001348{
Bill XIE612ec0e2017-08-30 16:10:27 +08001349 frba_t *frba = find_frba(image, size);
1350 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001351 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001352
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001353 region_t region = get_region(frba, region_type);
1354 if (region.size <= 0xfff) {
1355 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1356 region_name(region_type));
1357 exit(EXIT_FAILURE);
1358 }
1359
Scott Duplichanf2c98372014-12-12 21:03:06 -06001360 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001361 if (region_fd == -1) {
1362 perror("Could not open file");
1363 exit(EXIT_FAILURE);
1364 }
1365 struct stat buf;
1366 if (fstat(region_fd, &buf) == -1) {
1367 perror("Could not stat file");
1368 exit(EXIT_FAILURE);
1369 }
1370 int region_size = buf.st_size;
1371
1372 printf("File %s is %d bytes\n", region_fname, region_size);
1373
1374 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001375 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001376 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1377 " bytes. Not injecting.\n",
1378 region_name(region_type), region.size,
1379 region.size, region_size, region_size);
1380 exit(EXIT_FAILURE);
1381 }
1382
1383 int offset = 0;
1384 if ((region_type == 1) && (region_size < region.size)) {
1385 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1386 " bytes. Padding before injecting.\n",
1387 region_name(region_type), region.size,
1388 region.size, region_size, region_size);
1389 offset = region.size - region_size;
1390 memset(image + region.base, 0xff, offset);
1391 }
1392
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001393 if (size < region.base + offset + region_size) {
1394 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1395 size, region.base + offset + region_size);
1396 exit(EXIT_FAILURE);
1397 }
1398
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001399 if (read(region_fd, image + region.base + offset, region_size)
1400 != region_size) {
1401 perror("Could not read file");
1402 exit(EXIT_FAILURE);
1403 }
1404
1405 close(region_fd);
1406
1407 printf("Adding %s as the %s section of %s\n",
1408 region_fname, region_name(region_type), filename);
1409 write_image(filename, image, size);
1410}
1411
Jacob Garber595d9262019-06-27 17:33:10 -06001412static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001413{
1414 unsigned int y = 1;
1415 if (x == 0)
1416 return 0;
1417 while (y <= x)
1418 y = y << 1;
1419
1420 return y;
1421}
1422
1423/**
1424 * Determine if two memory regions overlap.
1425 *
1426 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001427 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001428 * @return 1 if the two regions overlap
1429 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001430static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001431{
Bill XIEfa5f9942017-09-12 11:22:29 +08001432 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001433 return 0;
1434
Nico Huber844eda02019-01-05 00:06:19 +01001435 /* r1 should be either completely below or completely above r2 */
1436 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001437}
1438
Jacob Garber595d9262019-06-27 17:33:10 -06001439static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001440 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001441{
1442 FILE *romlayout;
1443 char tempstr[256];
1444 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001445 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001446 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001447 region_t current_regions[MAX_REGIONS];
1448 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001449 int new_extent = 0;
1450 char *new_image;
1451
1452 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001453 frba_t *frba = find_frba(image, size);
1454 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001455 exit(EXIT_FAILURE);
1456
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001457 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001458 current_regions[i] = get_region(frba, i);
1459 new_regions[i] = get_region(frba, i);
1460 }
1461
1462 /* read new layout */
1463 romlayout = fopen(layout_fname, "r");
1464
1465 if (!romlayout) {
1466 perror("Could not read layout file.\n");
1467 exit(EXIT_FAILURE);
1468 }
1469
1470 while (!feof(romlayout)) {
1471 char *tstr1, *tstr2;
1472
Patrick Georgi802ad522014-08-09 17:12:23 +02001473 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001474 layout_region_name))
1475 continue;
1476
1477 region_number = region_num(layout_region_name);
1478 if (region_number < 0)
1479 continue;
1480
1481 tstr1 = strtok(tempstr, ":");
1482 tstr2 = strtok(NULL, ":");
1483 if (!tstr1 || !tstr2) {
1484 fprintf(stderr, "Could not parse layout file.\n");
1485 exit(EXIT_FAILURE);
1486 }
1487 new_regions[region_number].base = strtol(tstr1,
1488 (char **)NULL, 16);
1489 new_regions[region_number].limit = strtol(tstr2,
1490 (char **)NULL, 16);
1491 new_regions[region_number].size =
1492 new_regions[region_number].limit -
1493 new_regions[region_number].base + 1;
1494
1495 if (new_regions[region_number].size < 0)
1496 new_regions[region_number].size = 0;
1497 }
1498 fclose(romlayout);
1499
1500 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001501 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001502 if (new_regions[i].size == 0)
1503 continue;
1504
1505 if (new_regions[i].size < current_regions[i].size) {
1506 printf("DANGER: Region %s is shrinking.\n",
1507 region_name(i));
1508 printf(" The region will be truncated to fit.\n");
1509 printf(" This may result in an unusable image.\n");
1510 }
1511
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001512 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001513 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001514 fprintf(stderr, "Regions would overlap.\n");
1515 exit(EXIT_FAILURE);
1516 }
1517 }
1518
1519 /* detect if the image size should grow */
1520 if (new_extent < new_regions[i].limit)
1521 new_extent = new_regions[i].limit;
1522 }
1523
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001524 /* check if the image is actually a Flash Descriptor region */
1525 if (size == new_regions[0].size) {
1526 printf("The image is a single Flash Descriptor:\n");
1527 printf(" Only the descriptor will be modified\n");
1528 new_extent = size;
1529 } else {
1530 new_extent = next_pow2(new_extent - 1);
1531 if (new_extent != size) {
1532 printf("The image has changed in size.\n");
1533 printf("The old image is %d bytes.\n", size);
1534 printf("The new image is %d bytes.\n", new_extent);
1535 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001536 }
1537
1538 /* copy regions to a new image */
1539 new_image = malloc(new_extent);
1540 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001541 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001542 int copy_size = new_regions[i].size;
1543 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001544 const region_t *current = &current_regions[i];
1545 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001546
Bill XIEfa5f9942017-09-12 11:22:29 +08001547 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001548 continue;
1549
Bill XIEfa5f9942017-09-12 11:22:29 +08001550 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001551 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001552 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001553 if (i == REGION_BIOS)
1554 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001555 }
1556
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001557 if ((i == REGION_BIOS) && (new->size < current->size)) {
1558 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001559 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001560 }
1561
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001562 if (size < current->base + offset_current + copy_size) {
1563 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1564 region_name(i));
1565 continue;
1566 };
1567
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001568 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1569 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001570 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1571 offset_current, current->limit, current->size);
1572 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1573 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001574
Bill XIEfa5f9942017-09-12 11:22:29 +08001575 memcpy(new_image + new->base + offset_new,
1576 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001577 copy_size);
1578 }
1579
1580 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001581 frba = find_frba(new_image, new_extent);
1582 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001583 exit(EXIT_FAILURE);
1584
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001585 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001586 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001587 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001588
1589 write_image(filename, new_image, new_extent);
1590 free(new_image);
1591}
1592
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001593static void print_version(void)
1594{
1595 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1596 printf("Copyright (C) 2011 Google Inc.\n\n");
1597 printf
1598 ("This program is free software: you can redistribute it and/or modify\n"
1599 "it under the terms of the GNU General Public License as published by\n"
1600 "the Free Software Foundation, version 2 of the License.\n\n"
1601 "This program is distributed in the hope that it will be useful,\n"
1602 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1603 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001604 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001605}
1606
1607static void print_usage(const char *name)
1608{
1609 printf("usage: %s [-vhdix?] <filename>\n", name);
1610 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001611 " -d | --dump: dump intel firmware descriptor\n"
1612 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1613 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1614 " -x | --extract: extract intel fd modules\n"
1615 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1616 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001617 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001618 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1619 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1620 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1621 " can only be used once per run:\n"
1622 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1623 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1624 " Dual Output Fast Read Support\n"
1625 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301626 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001627 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001628 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1629 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001630 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301631 " adl - Alder Lake\n"
1632 " aplk - Apollo Lake\n"
1633 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08001634 " lbg - Lewisburg PCH\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001635 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301636 " glk - Gemini Lake\n"
1637 " icl - Ice Lake\n"
1638 " jsl - Jasper Lake\n"
1639 " sklkbl - Sky Lake/Kaby Lake\n"
1640 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001641 " -S | --setpchstrap Write a PCH strap\n"
1642 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001643 " -v | --version: print the version\n"
1644 " -h | --help: print this help\n\n"
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001645 "<region> is one of Descriptor, BIOS, ME, GbE, Platform, res1, res2, res3\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001646 "\n");
1647}
1648
1649int main(int argc, char *argv[])
1650{
1651 int opt, option_index = 0;
1652 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001653 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001654 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Usha P412679d2020-10-15 11:25:08 +05301655 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001656 char *region_type_string = NULL, *region_fname = NULL;
1657 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001658 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001659 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001660 unsigned int value = 0;
1661 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001662 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001663 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1664
Bill XIEfa5f9942017-09-12 11:22:29 +08001665 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001666 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001667 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001668 {"extract", 0, NULL, 'x'},
1669 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001670 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001671 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001672 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001673 {"density", 1, NULL, 'D'},
1674 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001675 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001676 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001677 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301678 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001679 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001680 {"version", 0, NULL, 'v'},
1681 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001682 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001683 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001684 {"setpchstrap", 1, NULL, 'S'},
1685 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001686 {0, 0, 0, 0}
1687 };
1688
Usha P412679d2020-10-15 11:25:08 +05301689 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 -07001690 long_options, &option_index)) != EOF) {
1691 switch (opt) {
1692 case 'd':
1693 mode_dump = 1;
1694 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001695 case 'S':
1696 mode_setstrap = 1;
1697 pchstrap = strtoul(optarg, NULL, 0);
1698 break;
1699 case 'V':
1700 value = strtoul(optarg, NULL, 0);
1701 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001702 case 'f':
1703 mode_layout = 1;
1704 layout_fname = strdup(optarg);
1705 if (!layout_fname) {
1706 fprintf(stderr, "No layout file specified\n");
1707 print_usage(argv[0]);
1708 exit(EXIT_FAILURE);
1709 }
1710 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001711 case 'x':
1712 mode_extract = 1;
1713 break;
1714 case 'i':
1715 // separate type and file name
1716 region_type_string = strdup(optarg);
1717 region_fname = strchr(region_type_string, ':');
1718 if (!region_fname) {
1719 print_usage(argv[0]);
1720 exit(EXIT_FAILURE);
1721 }
1722 region_fname[0] = '\0';
1723 region_fname++;
1724 // Descriptor, BIOS, ME, GbE, Platform
1725 // valid type?
1726 if (!strcasecmp("Descriptor", region_type_string))
1727 region_type = 0;
1728 else if (!strcasecmp("BIOS", region_type_string))
1729 region_type = 1;
1730 else if (!strcasecmp("ME", region_type_string))
1731 region_type = 2;
1732 else if (!strcasecmp("GbE", region_type_string))
1733 region_type = 3;
1734 else if (!strcasecmp("Platform", region_type_string))
1735 region_type = 4;
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001736 else if (!strcasecmp("res1", region_type_string))
1737 region_type = 5;
1738 else if (!strcasecmp("res2", region_type_string))
1739 region_type = 6;
1740 else if (!strcasecmp("res3", region_type_string))
1741 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001742 else if (!strcasecmp("EC", region_type_string))
1743 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001744 if (region_type == -1) {
1745 fprintf(stderr, "No such region type: '%s'\n\n",
1746 region_type_string);
1747 print_usage(argv[0]);
1748 exit(EXIT_FAILURE);
1749 }
1750 mode_inject = 1;
1751 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001752 case 'n':
1753 mode_newlayout = 1;
1754 layout_fname = strdup(optarg);
1755 if (!layout_fname) {
1756 fprintf(stderr, "No layout file specified\n");
1757 print_usage(argv[0]);
1758 exit(EXIT_FAILURE);
1759 }
1760 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001761 case 'O':
1762 new_filename = strdup(optarg);
1763 if (!new_filename) {
1764 fprintf(stderr, "No output filename specified\n");
1765 print_usage(argv[0]);
1766 exit(EXIT_FAILURE);
1767 }
1768 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001769 case 'D':
1770 mode_density = 1;
1771 new_density = strtoul(optarg, NULL, 0);
1772 switch (new_density) {
1773 case 512:
1774 new_density = COMPONENT_DENSITY_512KB;
1775 break;
1776 case 1:
1777 new_density = COMPONENT_DENSITY_1MB;
1778 break;
1779 case 2:
1780 new_density = COMPONENT_DENSITY_2MB;
1781 break;
1782 case 4:
1783 new_density = COMPONENT_DENSITY_4MB;
1784 break;
1785 case 8:
1786 new_density = COMPONENT_DENSITY_8MB;
1787 break;
1788 case 16:
1789 new_density = COMPONENT_DENSITY_16MB;
1790 break;
1791 case 32:
1792 new_density = COMPONENT_DENSITY_32MB;
1793 break;
1794 case 64:
1795 new_density = COMPONENT_DENSITY_64MB;
1796 break;
1797 case 0:
1798 new_density = COMPONENT_DENSITY_UNUSED;
1799 break;
1800 default:
1801 printf("error: Unknown density\n");
1802 print_usage(argv[0]);
1803 exit(EXIT_FAILURE);
1804 }
1805 break;
1806 case 'C':
1807 selected_chip = strtol(optarg, NULL, 0);
1808 if (selected_chip > 2) {
1809 fprintf(stderr, "error: Invalid chip selection\n");
1810 print_usage(argv[0]);
1811 exit(EXIT_FAILURE);
1812 }
1813 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001814 case 'M':
1815 mode_altmedisable = 1;
1816 altmedisable = strtol(optarg, NULL, 0);
1817 if (altmedisable > 1) {
1818 fprintf(stderr, "error: Illegal value\n");
1819 print_usage(argv[0]);
1820 exit(EXIT_FAILURE);
1821 }
1822 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001823 case 's':
1824 // Parse the requested SPI frequency
1825 inputfreq = strtol(optarg, NULL, 0);
1826 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001827 case 17:
1828 spifreq = SPI_FREQUENCY_17MHZ;
1829 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001830 case 20:
1831 spifreq = SPI_FREQUENCY_20MHZ;
1832 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001833 case 30:
1834 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1835 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001836 case 33:
1837 spifreq = SPI_FREQUENCY_33MHZ;
1838 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001839 case 48:
1840 spifreq = SPI_FREQUENCY_48MHZ;
1841 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001842 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001843 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001844 break;
1845 default:
1846 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1847 inputfreq);
1848 print_usage(argv[0]);
1849 exit(EXIT_FAILURE);
1850 }
1851 mode_spifreq = 1;
1852 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001853 case 'e':
1854 mode_em100 = 1;
1855 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001856 case 'l':
1857 mode_locked = 1;
1858 if (mode_unlocked == 1) {
1859 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1860 exit(EXIT_FAILURE);
1861 }
1862 break;
Usha P412679d2020-10-15 11:25:08 +05301863 case 'r':
1864 mode_read = 1;
1865 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001866 case 'u':
1867 mode_unlocked = 1;
1868 if (mode_locked == 1) {
1869 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1870 exit(EXIT_FAILURE);
1871 }
1872 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001873 case 'p':
1874 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001875 platform = PLATFORM_APL;
1876 } else if (!strcmp(optarg, "cnl")) {
1877 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08001878 } else if (!strcmp(optarg, "lbg")) {
1879 platform = PLATFORM_LBG;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001880 } else if (!strcmp(optarg, "ehl")) {
1881 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001882 } else if (!strcmp(optarg, "glk")) {
1883 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301884 } else if (!strcmp(optarg, "icl")) {
1885 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301886 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001887 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001888 } else if (!strcmp(optarg, "sklkbl")) {
1889 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001890 } else if (!strcmp(optarg, "tgl")) {
1891 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301892 } else if (!strcmp(optarg, "adl")) {
1893 platform = PLATFORM_ADL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001894 } else {
1895 fprintf(stderr, "Unknown platform: %s\n", optarg);
1896 exit(EXIT_FAILURE);
1897 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001898 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001899 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001900 case 't':
1901 mode_validate = 1;
1902 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001903 case 'v':
1904 print_version();
1905 exit(EXIT_SUCCESS);
1906 break;
1907 case 'h':
1908 case '?':
1909 default:
1910 print_usage(argv[0]);
1911 exit(EXIT_SUCCESS);
1912 break;
1913 }
1914 }
1915
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001916 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001917 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001918 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001919 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001920 print_usage(argv[0]);
1921 exit(EXIT_FAILURE);
1922 }
1923
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001924 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001925 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001926 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001927 fprintf(stderr, "You need to specify a mode.\n\n");
1928 print_usage(argv[0]);
1929 exit(EXIT_FAILURE);
1930 }
1931
1932 if (optind + 1 != argc) {
1933 fprintf(stderr, "You need to specify a file.\n\n");
1934 print_usage(argv[0]);
1935 exit(EXIT_FAILURE);
1936 }
1937
1938 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001939 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001940 if (bios_fd == -1) {
1941 perror("Could not open file");
1942 exit(EXIT_FAILURE);
1943 }
1944 struct stat buf;
1945 if (fstat(bios_fd, &buf) == -1) {
1946 perror("Could not stat file");
1947 exit(EXIT_FAILURE);
1948 }
1949 int size = buf.st_size;
1950
1951 printf("File %s is %d bytes\n", filename, size);
1952
1953 char *image = malloc(size);
1954 if (!image) {
1955 printf("Out of memory.\n");
1956 exit(EXIT_FAILURE);
1957 }
1958
1959 if (read(bios_fd, image, size) != size) {
1960 perror("Could not read file");
1961 exit(EXIT_FAILURE);
1962 }
1963
1964 close(bios_fd);
1965
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001966 // generate new filename
1967 if (new_filename == NULL) {
1968 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1969 if (!new_filename) {
1970 printf("Out of memory.\n");
1971 exit(EXIT_FAILURE);
1972 }
1973 // - 5: leave room for ".new\0"
1974 strcpy(new_filename, filename);
1975 strcat(new_filename, ".new");
1976 }
1977
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001978 check_ifd_version(image, size);
1979
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001980 if (mode_dump)
1981 dump_fd(image, size);
1982
Chris Douglass03ce0142014-02-26 13:30:13 -05001983 if (mode_layout)
1984 dump_layout(image, size, layout_fname);
1985
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001986 if (mode_extract)
1987 write_regions(image, size);
1988
Mathew Kingc7ddc992019-08-08 14:59:25 -06001989 if (mode_validate)
1990 validate_layout(image, size);
1991
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001992 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001993 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001994 region_fname);
1995
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001996 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001997 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001998
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001999 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002000 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002001
Jan Tatjefa317512016-03-11 00:52:07 +01002002 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002003 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002004
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002005 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002006 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002007
Alexander Couzensd12ea112016-09-10 13:33:05 +02002008 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002009 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002010
Usha P412679d2020-10-15 11:25:08 +05302011 if (mode_read)
2012 enable_cpu_read_me(new_filename, image, size);
2013
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002014 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002015 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002016
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002017 if (mode_setstrap) {
2018 fpsba_t *fpsba = find_fpsba(image, size);
2019 const fdbar_t *fdb = find_fd(image, size);
2020 set_pchstrap(fpsba, fdb, pchstrap, value);
2021 write_image(new_filename, image, size);
2022 }
2023
Bill XIEb3e15a22017-09-07 18:34:50 +08002024 if (mode_altmedisable) {
2025 fpsba_t *fpsba = find_fpsba(image, size);
2026 fmsba_t *fmsba = find_fmsba(image, size);
2027 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002028 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002029 }
2030
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002031 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002032 free(image);
2033
2034 return 0;
2035}