blob: b91c90cadca5e4c8cbe08e3a9168bc27b4248871 [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;
Subrata Banik621ed4c2021-06-17 21:13:22 +0530193 else if (isl == 0x13)
194 return CHIPSET_N_J_SERIES_APOLLO_LAKE;
Bill XIEb3e15a22017-09-07 18:34:50 +0800195 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
196 return CHIPSET_5_SERIES_IBEX_PEAK;
197 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
198 if (msl == 0 && isl <= 17)
199 return CHIPSET_BAYTRAIL;
200 else if (msl <= 1 && isl <= 18)
201 return CHIPSET_6_SERIES_COUGAR_POINT;
202 else if (msl <= 1 && isl <= 21)
203 return CHIPSET_8_SERIES_LYNX_POINT;
204 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
205 return CHIPSET_9_SERIES_WILDCAT_POINT;
206 } else if (nm == 6) {
207 return CHIPSET_C620_SERIES_LEWISBURG;
Bill XIEb3e15a22017-09-07 18:34:50 +0800208 }
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200209 return CHIPSET_PCH_UNKNOWN;
Bill XIEb3e15a22017-09-07 18:34:50 +0800210}
211
Subrata Banik8c082e52021-06-10 23:02:29 +0530212static enum ich_chipset ifd2_platform_to_chipset(const int pindex)
213{
214 switch (pindex) {
215 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[] = {
246 PLATFORM_GLK,
247 PLATFORM_CNL,
Johnny Line273a022021-06-22 11:26:46 +0800248 PLATFORM_LBG,
Aamir Bohra1018be22018-06-29 15:08:50 +0530249 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700250 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530251 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700252 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530253 PLATFORM_ADL,
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200254 PLATFORM_SKLKBL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700255 };
256 unsigned int i;
257
258 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
259 if (platform == ifd_2_platforms[i])
260 return 1;
261 }
262
263 return 0;
264}
265
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700266static void check_ifd_version(char *image, int size)
267{
Subrata Banik8c082e52021-06-10 23:02:29 +0530268 if (is_platform_ifd_2()) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700269 ifd_version = IFD_VERSION_2;
Subrata Banik8c082e52021-06-10 23:02:29 +0530270 chipset = ifd2_platform_to_chipset(platform);
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700271 max_regions = MAX_REGIONS;
Subrata Banik8c082e52021-06-10 23:02:29 +0530272 } else {
273 ifd_version = IFD_VERSION_1;
274 chipset = ifd1_guess_chipset(image, size);
275 max_regions = MAX_REGIONS_OLD;
276 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700277}
278
Bill XIEfa5f9942017-09-12 11:22:29 +0800279static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700280{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500281 int base_mask;
282 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700283 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700284 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500285
286 if (ifd_version >= IFD_VERSION_2)
287 base_mask = 0x7fff;
288 else
289 base_mask = 0xfff;
290
291 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700292
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400293 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800294 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700295 exit (EXIT_FAILURE);
296 }
297
Bill XIE4651d452017-09-12 11:54:48 +0800298 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700299 region.base = (flreg & base_mask) << 12;
300 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700301 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500302
Chris Douglass03ce0142014-02-26 13:30:13 -0500303 if (region.size < 0)
304 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700305
306 return region;
307}
308
Bill XIEfa5f9942017-09-12 11:22:29 +0800309static void set_region(frba_t *frba, unsigned int region_type,
310 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500311{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400312 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800313 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500314 exit (EXIT_FAILURE);
315 }
Bill XIE4651d452017-09-12 11:54:48 +0800316
317 frba->flreg[region_type] =
318 (((region->limit >> 12) & 0x7fff) << 16) |
319 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500320}
321
Bill XIEfa5f9942017-09-12 11:22:29 +0800322static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700323{
Bill XIEfa5f9942017-09-12 11:22:29 +0800324 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700325 fprintf(stderr, "Invalid region type.\n");
326 exit (EXIT_FAILURE);
327 }
328
Chris Douglass03ce0142014-02-26 13:30:13 -0500329 return region_names[region_type].pretty;
330}
331
Bill XIEfa5f9942017-09-12 11:22:29 +0800332static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500333{
Bill XIEfa5f9942017-09-12 11:22:29 +0800334 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500335 fprintf(stderr, "Invalid region type.\n");
336 exit (EXIT_FAILURE);
337 }
338
339 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700340}
341
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500342static int region_num(const char *name)
343{
Bill XIEfa5f9942017-09-12 11:22:29 +0800344 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500345
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200346 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500347 if (strcasecmp(name, region_names[i].pretty) == 0)
348 return i;
349 if (strcasecmp(name, region_names[i].terse) == 0)
350 return i;
351 }
352
353 return -1;
354}
355
Bill XIEfa5f9942017-09-12 11:22:29 +0800356static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700357{
Bill XIEfa5f9942017-09-12 11:22:29 +0800358 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700359 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700360 exit (EXIT_FAILURE);
361 }
362
Bill XIE1bf65062017-09-12 11:31:37 +0800363 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700364}
365
Bill XIEfa5f9942017-09-12 11:22:29 +0800366static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700367{
368 region_t region = get_region(frba, num);
369 printf(" Flash Region %d (%s): %08x - %08x %s\n",
370 num, region_name(num), region.base, region.limit,
371 region.size < 1 ? "(unused)" : "");
372}
373
Bill XIEfa5f9942017-09-12 11:22:29 +0800374static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
375 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500376{
377 region_t region = get_region(frba, num);
378 snprintf(buf, bufsize, "%08x:%08x %s\n",
379 region.base, region.limit, region_name_short(num));
380}
381
Bill XIEfa5f9942017-09-12 11:22:29 +0800382static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700383{
Bill XIE4651d452017-09-12 11:54:48 +0800384 unsigned int i;
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530385 region_t region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700386 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800387 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530388 region = get_region(frba, i);
389 /* Skip unused & reserved Flash Region */
390 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
391 continue;
392
Bill XIE4651d452017-09-12 11:54:48 +0800393 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
394 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700395 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700396}
397
Bill XIEfa5f9942017-09-12 11:22:29 +0800398static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500399{
400 char buf[LAYOUT_LINELEN];
401 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800402 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500403
404 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
405 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
406 if (layout_fd == -1) {
407 perror("Could not open file");
408 exit(EXIT_FAILURE);
409 }
410
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200411 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200412 region_t region = get_region(frba, i);
413 /* is region invalid? */
414 if (region.size < 1)
415 continue;
416
Chris Douglass03ce0142014-02-26 13:30:13 -0500417 dump_region_layout(buf, bufsize, i, frba);
418 if (write(layout_fd, buf, strlen(buf)) < 0) {
419 perror("Could not write to file");
420 exit(EXIT_FAILURE);
421 }
422 }
423 close(layout_fd);
424 printf("Wrote layout to %s\n", layout_fname);
425}
426
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530427static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700428{
429 switch (freq) {
430 case SPI_FREQUENCY_20MHZ:
431 printf("20MHz");
432 break;
433 case SPI_FREQUENCY_33MHZ:
434 printf("33MHz");
435 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700436 case SPI_FREQUENCY_48MHZ:
437 printf("48MHz");
438 break;
439 case SPI_FREQUENCY_50MHZ_30MHZ:
440 switch (ifd_version) {
441 case IFD_VERSION_1:
442 printf("50MHz");
443 break;
444 case IFD_VERSION_2:
445 printf("30MHz");
446 break;
447 }
448 break;
449 case SPI_FREQUENCY_17MHZ:
450 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700451 break;
452 default:
453 printf("unknown<%x>MHz", freq);
454 }
455}
456
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530457static void _decode_spi_frequency_500_series(unsigned int freq)
458{
459 switch (freq) {
460 case SPI_FREQUENCY_100MHZ:
461 printf("100MHz");
462 break;
463 case SPI_FREQUENCY_50MHZ:
464 printf("50MHz");
465 break;
466 case SPI_FREQUENCY_500SERIES_33MHZ:
467 printf("33MHz");
468 break;
469 case SPI_FREQUENCY_25MHZ:
470 printf("25MHz");
471 break;
472 case SPI_FREQUENCY_14MHZ:
473 printf("14MHz");
474 break;
475 default:
476 printf("unknown<%x>MHz", freq);
477 }
478}
479
480static void decode_spi_frequency(unsigned int freq)
481{
Subrata Banika5f47812020-09-29 11:43:01 +0530482 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530483 _decode_spi_frequency_500_series(freq);
484 else
485 _decode_spi_frequency(freq);
486}
487
Subrata Banike5d39922020-08-26 16:01:42 +0530488static void _decode_espi_frequency(unsigned int freq)
489{
490 switch (freq) {
491 case ESPI_FREQUENCY_20MHZ:
492 printf("20MHz");
493 break;
494 case ESPI_FREQUENCY_24MHZ:
495 printf("24MHz");
496 break;
497 case ESPI_FREQUENCY_30MHZ:
498 printf("30MHz");
499 break;
500 case ESPI_FREQUENCY_48MHZ:
501 printf("48MHz");
502 break;
503 case ESPI_FREQUENCY_60MHZ:
504 printf("60MHz");
505 break;
506 case ESPI_FREQUENCY_17MHZ:
507 printf("17MHz");
508 break;
509 default:
510 printf("unknown<%x>MHz", freq);
511 }
512}
513
514static void _decode_espi_frequency_500_series(unsigned int freq)
515{
516 switch (freq) {
517 case ESPI_FREQUENCY_500SERIES_20MHZ:
518 printf("20MHz");
519 break;
520 case ESPI_FREQUENCY_500SERIES_24MHZ:
521 printf("24MHz");
522 break;
523 case ESPI_FREQUENCY_500SERIES_25MHZ:
524 printf("25MHz");
525 break;
526 case ESPI_FREQUENCY_500SERIES_48MHZ:
527 printf("48MHz");
528 break;
529 case ESPI_FREQUENCY_500SERIES_60MHZ:
530 printf("60MHz");
531 break;
532 default:
533 printf("unknown<%x>MHz", freq);
534 }
535}
536
537static void decode_espi_frequency(unsigned int freq)
538{
Subrata Banika5f47812020-09-29 11:43:01 +0530539 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530540 _decode_espi_frequency_500_series(freq);
541 else
542 _decode_espi_frequency(freq);
543}
544
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700545static void decode_component_density(unsigned int density)
546{
547 switch (density) {
548 case COMPONENT_DENSITY_512KB:
549 printf("512KB");
550 break;
551 case COMPONENT_DENSITY_1MB:
552 printf("1MB");
553 break;
554 case COMPONENT_DENSITY_2MB:
555 printf("2MB");
556 break;
557 case COMPONENT_DENSITY_4MB:
558 printf("4MB");
559 break;
560 case COMPONENT_DENSITY_8MB:
561 printf("8MB");
562 break;
563 case COMPONENT_DENSITY_16MB:
564 printf("16MB");
565 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700566 case COMPONENT_DENSITY_32MB:
567 printf("32MB");
568 break;
569 case COMPONENT_DENSITY_64MB:
570 printf("64MB");
571 break;
572 case COMPONENT_DENSITY_UNUSED:
573 printf("UNUSED");
574 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700575 default:
576 printf("unknown<%x>MB", density);
577 }
578}
579
Subrata Banik26058dc2020-08-26 15:12:16 +0530580static int is_platform_with_pch(void)
581{
582 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
583 return 1;
584
585 return 0;
586}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530587
588/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
589static int is_platform_with_100x_series_pch(void)
590{
591 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530592 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530593 return 1;
594
595 return 0;
596}
597
Subrata Banike5d39922020-08-26 16:01:42 +0530598static void dump_fcba(const fcba_t *fcba, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700599{
Subrata Banike5d39922020-08-26 16:01:42 +0530600 unsigned int freq;
601
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700602 printf("\nFound Component Section\n");
603 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700604 printf(" Dual Output Fast Read Support: %ssupported\n",
605 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700606 printf(" Read ID/Read Status Clock Frequency: ");
607 decode_spi_frequency((fcba->flcomp >> 27) & 7);
608 printf("\n Write/Erase Clock Frequency: ");
609 decode_spi_frequency((fcba->flcomp >> 24) & 7);
610 printf("\n Fast Read Clock Frequency: ");
611 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700612 printf("\n Fast Read Support: %ssupported",
613 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530614 if (is_platform_with_100x_series_pch() &&
615 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
616 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530617 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530618 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
619 else
620 freq = (fcba->flcomp >> 17) & 7;
621 decode_espi_frequency(freq);
622 } else {
623 printf("\n Read Clock Frequency: ");
624 decode_spi_frequency((fcba->flcomp >> 17) & 7);
625 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700626
627 switch (ifd_version) {
628 case IFD_VERSION_1:
629 printf("\n Component 2 Density: ");
630 decode_component_density((fcba->flcomp >> 3) & 7);
631 printf("\n Component 1 Density: ");
632 decode_component_density(fcba->flcomp & 7);
633 break;
634 case IFD_VERSION_2:
635 printf("\n Component 2 Density: ");
636 decode_component_density((fcba->flcomp >> 4) & 0xf);
637 printf("\n Component 1 Density: ");
638 decode_component_density(fcba->flcomp & 0xf);
639 break;
640 }
641
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700642 printf("\n");
643 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700644 printf(" Invalid Instruction 3: 0x%02x\n",
645 (fcba->flill >> 24) & 0xff);
646 printf(" Invalid Instruction 2: 0x%02x\n",
647 (fcba->flill >> 16) & 0xff);
648 printf(" Invalid Instruction 1: 0x%02x\n",
649 (fcba->flill >> 8) & 0xff);
650 printf(" Invalid Instruction 0: 0x%02x\n",
651 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530652 if (is_platform_with_100x_series_pch()) {
653 printf("FLILL1 0x%08x\n", fcba->flpb);
654 printf(" Invalid Instruction 7: 0x%02x\n",
655 (fcba->flpb >> 24) & 0xff);
656 printf(" Invalid Instruction 6: 0x%02x\n",
657 (fcba->flpb >> 16) & 0xff);
658 printf(" Invalid Instruction 5: 0x%02x\n",
659 (fcba->flpb >> 8) & 0xff);
660 printf(" Invalid Instruction 4: 0x%02x\n",
661 fcba->flpb & 0xff);
662 } else {
663 printf("FLPB 0x%08x\n", fcba->flpb);
664 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
665 (fcba->flpb & 0xfff) << 12);
666 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700667}
668
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200669static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700670{
Bill XIE4651d452017-09-12 11:54:48 +0800671 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200672 /* SoC Strap Length, aka PSL, aka ISL */
673 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
674
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700675 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200676 for (i = 0; i < SSL; i++)
677 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800678
679 if (ifd_version >= IFD_VERSION_2) {
680 printf("HAP bit is %sset\n",
681 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
682 } else if (chipset >= CHIPSET_ICH8
683 && chipset <= CHIPSET_ICH10) {
684 printf("ICH_MeDisable bit is %sset\n",
685 fpsba->pchstrp[0] & 1 ? "" : "not ");
686 } else {
687 printf("AltMeDisable bit is %sset\n",
688 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
689 }
690
Bill XIE4651d452017-09-12 11:54:48 +0800691 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700692}
693
694static void decode_flmstr(uint32_t flmstr)
695{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700696 int wr_shift, rd_shift;
697 if (ifd_version >= IFD_VERSION_2) {
698 wr_shift = FLMSTR_WR_SHIFT_V2;
699 rd_shift = FLMSTR_RD_SHIFT_V2;
700 } else {
701 wr_shift = FLMSTR_WR_SHIFT_V1;
702 rd_shift = FLMSTR_RD_SHIFT_V1;
703 }
704
705 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700706 if (ifd_version >= IFD_VERSION_2)
707 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700708 (flmstr & (1 << (wr_shift + 8))) ?
709 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700710 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700711 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700712 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700713 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700714 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700715 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700716 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700717 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700718 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700719 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700720
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700721 if (ifd_version >= IFD_VERSION_2)
722 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700723 (flmstr & (1 << (rd_shift + 8))) ?
724 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700725 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700726 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700727 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700728 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700729 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700730 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700731 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700732 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700733 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700734 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700735
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700736 /* Requestor ID doesn't exist for ifd 2 */
737 if (ifd_version < IFD_VERSION_2)
738 printf(" Requester ID: 0x%04x\n\n",
739 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700740}
741
Bill XIEfa5f9942017-09-12 11:22:29 +0800742static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700743{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700744 printf("Found Master Section\n");
745 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
746 decode_flmstr(fmba->flmstr1);
747 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
748 decode_flmstr(fmba->flmstr2);
749 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
750 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700751 if (ifd_version >= IFD_VERSION_2) {
752 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
753 decode_flmstr(fmba->flmstr5);
754 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700755}
756
Bill XIEfa5f9942017-09-12 11:22:29 +0800757static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700758{
Bill XIE612ec0e2017-08-30 16:10:27 +0800759 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700760 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800761 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
762 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800763
764 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
765 printf("MCH_MeDisable bit is %sset\n",
766 fmsba->data[0] & 1 ? "" : "not ");
767 printf("MCH_AltMeDisable bit is %sset\n",
768 fmsba->data[0] & (1 << 7) ? "" : "not ");
769 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700770}
771
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700772static void dump_jid(uint32_t jid)
773{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100774 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700775 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100776 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200777 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100778 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200779 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700780}
781
782static void dump_vscc(uint32_t vscc)
783{
784 printf(" Lower Erase Opcode: 0x%02x\n",
785 vscc >> 24);
786 printf(" Lower Write Enable on Write Status: 0x%02x\n",
787 vscc & (1 << 20) ? 0x06 : 0x50);
788 printf(" Lower Write Status Required: %s\n",
789 vscc & (1 << 19) ? "Yes" : "No");
790 printf(" Lower Write Granularity: %d bytes\n",
791 vscc & (1 << 18) ? 64 : 1);
792 printf(" Lower Block / Sector Erase Size: ");
793 switch ((vscc >> 16) & 0x3) {
794 case 0:
795 printf("256 Byte\n");
796 break;
797 case 1:
798 printf("4KB\n");
799 break;
800 case 2:
801 printf("8KB\n");
802 break;
803 case 3:
804 printf("64KB\n");
805 break;
806 }
807
808 printf(" Upper Erase Opcode: 0x%02x\n",
809 (vscc >> 8) & 0xff);
810 printf(" Upper Write Enable on Write Status: 0x%02x\n",
811 vscc & (1 << 4) ? 0x06 : 0x50);
812 printf(" Upper Write Status Required: %s\n",
813 vscc & (1 << 3) ? "Yes" : "No");
814 printf(" Upper Write Granularity: %d bytes\n",
815 vscc & (1 << 2) ? 64 : 1);
816 printf(" Upper Block / Sector Erase Size: ");
817 switch (vscc & 0x3) {
818 case 0:
819 printf("256 Byte\n");
820 break;
821 case 1:
822 printf("4KB\n");
823 break;
824 case 2:
825 printf("8KB\n");
826 break;
827 case 3:
828 printf("64KB\n");
829 break;
830 }
831}
832
Bill XIEfa5f9942017-09-12 11:22:29 +0800833static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700834{
835 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200836 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
837 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700838
839 printf("ME VSCC table:\n");
840 for (i = 0; i < num; i++) {
841 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
842 dump_jid(vtba->entry[i].jid);
843 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
844 dump_vscc(vtba->entry[i].vscc);
845 }
846 printf("\n");
847}
848
Bill XIEfa5f9942017-09-12 11:22:29 +0800849static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700850{
851 int i, j;
852 printf("OEM Section:\n");
853 for (i = 0; i < 4; i++) {
854 printf("%02x:", i << 4);
855 for (j = 0; j < 16; j++)
856 printf(" %02x", oem[(i<<4)+j]);
857 printf ("\n");
858 }
859 printf ("\n");
860}
861
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700862static void dump_fd(char *image, int size)
863{
Bill XIE612ec0e2017-08-30 16:10:27 +0800864 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700865 if (!fdb)
866 exit(EXIT_FAILURE);
867
Subrata Banik26058dc2020-08-26 15:12:16 +0530868 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
869 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700870 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530871 if (!is_platform_with_100x_series_pch())
872 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700873 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
874 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
875 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
876
877 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530878 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
879 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700880 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
881 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
882 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
883
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530884 if (!is_platform_with_100x_series_pch()) {
885 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
886 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
887 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
888 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700889
Subrata Banika5f47812020-09-29 11:43:01 +0530890 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530891 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
892 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
893 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
894 }
895
Stefan Tauner0d226142018-08-05 18:56:53 +0200896 char *flumap = find_flumap(image, size);
897 uint32_t flumap1 = *(uint32_t *)flumap;
898 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700899 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200900 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700901 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200902 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700903 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200904 (image + ((flumap1 & 0xff) << 4)),
905 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800906 dump_oem((const uint8_t *)image + 0xf00);
907
908 const frba_t *frba = find_frba(image, size);
909 const fcba_t *fcba = find_fcba(image, size);
910 const fpsba_t *fpsba = find_fpsba(image, size);
911 const fmba_t *fmba = find_fmba(image, size);
912 const fmsba_t *fmsba = find_fmsba(image, size);
913
914 if (frba && fcba && fpsba && fmba && fmsba) {
915 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +0530916 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200917 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800918 dump_fmba(fmba);
919 dump_fmsba(fmsba);
920 } else {
921 printf("FD is corrupted!\n");
922 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700923}
924
Bill XIEfa5f9942017-09-12 11:22:29 +0800925static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500926{
Bill XIE612ec0e2017-08-30 16:10:27 +0800927 const frba_t *frba = find_frba(image, size);
928 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500929 exit(EXIT_FAILURE);
930
Bill XIE612ec0e2017-08-30 16:10:27 +0800931 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500932}
933
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700934static void write_regions(char *image, int size)
935{
Bill XIEfa5f9942017-09-12 11:22:29 +0800936 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800937 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700938
Bill XIE612ec0e2017-08-30 16:10:27 +0800939 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700940 exit(EXIT_FAILURE);
941
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700942 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700943 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700944 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700945 if (region.size > 0) {
946 int region_fd;
947 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600948 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700949 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200950 if (region_fd < 0) {
951 perror("Error while trying to open file");
952 exit(EXIT_FAILURE);
953 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700954 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700955 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700956 close(region_fd);
957 }
958 }
959}
960
Mathew Kingc7ddc992019-08-08 14:59:25 -0600961static void validate_layout(char *image, int size)
962{
963 uint i, errors = 0;
964 struct fmap *fmap;
965 long int fmap_loc = fmap_find((uint8_t *)image, size);
966 const frba_t *frba = find_frba(image, size);
967
968 if (fmap_loc < 0 || !frba)
969 exit(EXIT_FAILURE);
970
971 fmap = (struct fmap *)(image + fmap_loc);
972
973 for (i = 0; i < max_regions; i++) {
974 if (region_names[i].fmapname == NULL)
975 continue;
976
977 region_t region = get_region(frba, i);
978
979 if (region.size == 0)
980 continue;
981
982 const struct fmap_area *area =
983 fmap_find_area(fmap, region_names[i].fmapname);
984
985 if (!area)
986 continue;
987
988 if ((uint)region.base != area->offset ||
989 (uint)region.size != area->size) {
990 printf("Region mismatch between %s and %s\n",
991 region_names[i].terse, area->name);
992 printf(" Descriptor region %s:\n", region_names[i].terse);
993 printf(" offset: 0x%08x\n", region.base);
994 printf(" length: 0x%08x\n", region.size);
995 printf(" FMAP area %s:\n", area->name);
996 printf(" offset: 0x%08x\n", area->offset);
997 printf(" length: 0x%08x\n", area->size);
998 errors++;
999 }
1000 }
1001
1002 if (errors > 0)
1003 exit(EXIT_FAILURE);
1004}
1005
Bill XIEfa5f9942017-09-12 11:22:29 +08001006static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001007{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001008 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001009 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001010
1011 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001012 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001013 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001014 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001015 if (new_fd < 0) {
1016 perror("Error while trying to open file");
1017 exit(EXIT_FAILURE);
1018 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001019 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001020 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001021 close(new_fd);
1022}
1023
Bill XIEfa5f9942017-09-12 11:22:29 +08001024static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001025 enum spi_frequency freq)
1026{
Bill XIE612ec0e2017-08-30 16:10:27 +08001027 fcba_t *fcba = find_fcba(image, size);
1028 if (!fcba)
1029 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001030
1031 /* clear bits 21-29 */
1032 fcba->flcomp &= ~0x3fe00000;
1033 /* Read ID and Read Status Clock Frequency */
1034 fcba->flcomp |= freq << 27;
1035 /* Write and Erase Clock Frequency */
1036 fcba->flcomp |= freq << 24;
1037 /* Fast Read Clock Frequency */
1038 fcba->flcomp |= freq << 21;
1039
1040 write_image(filename, image, size);
1041}
1042
Bill XIEfa5f9942017-09-12 11:22:29 +08001043static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001044{
Bill XIE612ec0e2017-08-30 16:10:27 +08001045 fcba_t *fcba = find_fcba(image, size);
1046 if (!fcba)
1047 exit(EXIT_FAILURE);
1048
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001049 int freq;
1050
1051 switch (ifd_version) {
1052 case IFD_VERSION_1:
1053 freq = SPI_FREQUENCY_20MHZ;
1054 break;
1055 case IFD_VERSION_2:
1056 freq = SPI_FREQUENCY_17MHZ;
1057 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001058 default:
1059 freq = SPI_FREQUENCY_17MHZ;
1060 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001061 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001062
1063 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001064 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001065}
1066
Bill XIEfa5f9942017-09-12 11:22:29 +08001067static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +01001068 unsigned int density)
1069{
Bill XIE612ec0e2017-08-30 16:10:27 +08001070 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001071 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001072 if (!fcba)
1073 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001074
1075 printf("Setting chip density to ");
1076 decode_component_density(density);
1077 printf("\n");
1078
1079 switch (ifd_version) {
1080 case IFD_VERSION_1:
1081 /* fail if selected density is not supported by this version */
1082 if ( (density == COMPONENT_DENSITY_32MB) ||
1083 (density == COMPONENT_DENSITY_64MB) ||
1084 (density == COMPONENT_DENSITY_UNUSED) ) {
1085 printf("error: Selected density not supported in IFD version 1.\n");
1086 exit(EXIT_FAILURE);
1087 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001088 mask = 0x7;
1089 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001090 break;
1091 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001092 mask = 0xf;
1093 chip2_offset = 4;
1094 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001095 default:
1096 printf("error: Unknown IFD version\n");
1097 exit(EXIT_FAILURE);
1098 break;
1099 }
1100
1101 /* clear chip density for corresponding chip */
1102 switch (selected_chip) {
1103 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001104 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001105 break;
1106 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001107 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001108 break;
1109 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001110 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001111 break;
1112 }
1113
1114 /* set the new density */
1115 if (selected_chip == 1 || selected_chip == 0)
1116 fcba->flcomp |= (density); /* first chip */
1117 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001118 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001119
1120 write_image(filename, image, size);
1121}
1122
Duncan Laurie7775d672019-06-06 13:39:26 -07001123static int check_region(const frba_t *frba, unsigned int region_type)
1124{
1125 region_t region;
1126
1127 if (!frba)
1128 return 0;
1129
1130 region = get_region(frba, region_type);
1131 return !!((region.base < region.limit) && (region.size > 0));
1132}
1133
Bill XIEfa5f9942017-09-12 11:22:29 +08001134static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001135{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001136 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001137 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001138 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001139 if (!fmba)
1140 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001141
1142 if (ifd_version >= IFD_VERSION_2) {
1143 wr_shift = FLMSTR_WR_SHIFT_V2;
1144 rd_shift = FLMSTR_RD_SHIFT_V2;
1145
1146 /* Clear non-reserved bits */
1147 fmba->flmstr1 &= 0xff;
1148 fmba->flmstr2 &= 0xff;
1149 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001150 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001151 } else {
1152 wr_shift = FLMSTR_WR_SHIFT_V1;
1153 rd_shift = FLMSTR_RD_SHIFT_V1;
1154
1155 fmba->flmstr1 = 0;
1156 fmba->flmstr2 = 0;
1157 /* Requestor ID */
1158 fmba->flmstr3 = 0x118;
1159 }
1160
Andrey Petrov96ecb772016-10-31 19:31:54 -07001161 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001162 case PLATFORM_APL:
1163 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001164 /* CPU/BIOS can read descriptor and BIOS */
1165 fmba->flmstr1 |= 0x3 << rd_shift;
1166 /* CPU/BIOS can write BIOS */
1167 fmba->flmstr1 |= 0x2 << wr_shift;
1168 /* TXE can read descriptor, BIOS and Device Expansion */
1169 fmba->flmstr2 |= 0x23 << rd_shift;
1170 /* TXE can only write Device Expansion */
1171 fmba->flmstr2 |= 0x20 << wr_shift;
1172 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001173 case PLATFORM_CNL:
1174 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001175 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001176 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301177 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001178 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301179 case PLATFORM_ADL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001180 /* CPU/BIOS can read descriptor and BIOS. */
1181 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1182 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1183 /* CPU/BIOS can write BIOS. */
1184 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1185 /* ME can read descriptor and ME. */
1186 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1187 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001188 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001189 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1190 if (check_region(frba, REGION_GBE)) {
1191 /* BIOS can read/write GbE. */
1192 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1193 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1194 /* ME can read GbE. */
1195 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1196 /* GbE can read descriptor and read/write GbE.. */
1197 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1198 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1199 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1200 }
1201 if (check_region(frba, REGION_PDR)) {
1202 /* BIOS can read/write PDR. */
1203 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1204 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1205 }
1206 if (check_region(frba, REGION_EC)) {
1207 /* BIOS can read EC. */
1208 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1209 /* EC can read descriptor and read/write EC. */
1210 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1211 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1212 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1213 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001214 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001215 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001216 /* CPU/BIOS can read descriptor and BIOS. */
1217 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1218 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1219 /* CPU/BIOS can write BIOS. */
1220 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1221 /* ME can read descriptor and ME. */
1222 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1223 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1224 /* ME can write ME. */
1225 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1226 if (check_region(frba, REGION_GBE)) {
1227 /* BIOS can read GbE. */
1228 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1229 /* BIOS can write GbE. */
1230 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1231 /* ME can read GbE. */
1232 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1233 /* ME can write GbE. */
1234 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1235 /* GbE can write GbE. */
1236 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1237 /* GbE can read GbE. */
1238 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1239 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001240 break;
1241 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001242
1243 write_image(filename, image, size);
1244}
1245
Usha P412679d2020-10-15 11:25:08 +05301246static void enable_cpu_read_me(const char *filename, char *image, int size)
1247{
1248 int rd_shift;
1249 fmba_t *fmba = find_fmba(image, size);
1250
1251 if (!fmba)
1252 exit(EXIT_FAILURE);
1253
1254 if (ifd_version >= IFD_VERSION_2)
1255 rd_shift = FLMSTR_RD_SHIFT_V2;
1256 else
1257 rd_shift = FLMSTR_RD_SHIFT_V1;
1258
1259 /* CPU/BIOS can read ME. */
1260 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1261
1262 write_image(filename, image, size);
1263}
1264
Bill XIEfa5f9942017-09-12 11:22:29 +08001265static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001266{
Bill XIE612ec0e2017-08-30 16:10:27 +08001267 fmba_t *fmba = find_fmba(image, size);
1268 if (!fmba)
1269 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001270
1271 if (ifd_version >= IFD_VERSION_2) {
1272 /* Access bits for each region are read: 19:8 write: 31:20 */
1273 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1274 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1275 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001276 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001277 } else {
1278 fmba->flmstr1 = 0xffff0000;
1279 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001280 /* Keep chipset specific Requester ID */
1281 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001282 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001283
1284 write_image(filename, image, size);
1285}
1286
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001287static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1288 const unsigned int value)
1289{
1290 if (!fpsba || !fdb) {
1291 fprintf(stderr, "Internal error\n");
1292 exit(EXIT_FAILURE);
1293 }
1294
1295 /* SoC Strap Length, aka PSL, aka ISL */
1296 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1297 if (strap >= SSL) {
1298 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1299 exit(EXIT_FAILURE);
1300 }
1301 fpsba->pchstrp[strap] = value;
1302}
1303
Bill XIEb3e15a22017-09-07 18:34:50 +08001304/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001305static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001306{
1307 if (ifd_version >= IFD_VERSION_2) {
1308 printf("%sting the HAP bit to %s Intel ME...\n",
1309 altmedisable?"Set":"Unset",
1310 altmedisable?"disable":"enable");
1311 if (altmedisable)
1312 fpsba->pchstrp[0] |= (1 << 16);
1313 else
1314 fpsba->pchstrp[0] &= ~(1 << 16);
1315 } else {
1316 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1317 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1318 "and MCH_AltMeDisable to %s Intel ME...\n",
1319 altmedisable?"Set":"Unset",
1320 altmedisable?"disable":"enable");
1321 if (altmedisable) {
1322 /* MCH_MeDisable */
1323 fmsba->data[0] |= 1;
1324 /* MCH_AltMeDisable */
1325 fmsba->data[0] |= (1 << 7);
1326 /* ICH_MeDisable */
1327 fpsba->pchstrp[0] |= 1;
1328 } else {
1329 fmsba->data[0] &= ~1;
1330 fmsba->data[0] &= ~(1 << 7);
1331 fpsba->pchstrp[0] &= ~1;
1332 }
1333 } else {
1334 printf("%sting the AltMeDisable to %s Intel ME...\n",
1335 altmedisable?"Set":"Unset",
1336 altmedisable?"disable":"enable");
1337 if (altmedisable)
1338 fpsba->pchstrp[10] |= (1 << 7);
1339 else
1340 fpsba->pchstrp[10] &= ~(1 << 7);
1341 }
1342 }
1343}
1344
Jacob Garber595d9262019-06-27 17:33:10 -06001345static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001346 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001347{
Bill XIE612ec0e2017-08-30 16:10:27 +08001348 frba_t *frba = find_frba(image, size);
1349 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001350 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001351
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001352 region_t region = get_region(frba, region_type);
1353 if (region.size <= 0xfff) {
1354 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1355 region_name(region_type));
1356 exit(EXIT_FAILURE);
1357 }
1358
Scott Duplichanf2c98372014-12-12 21:03:06 -06001359 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001360 if (region_fd == -1) {
1361 perror("Could not open file");
1362 exit(EXIT_FAILURE);
1363 }
1364 struct stat buf;
1365 if (fstat(region_fd, &buf) == -1) {
1366 perror("Could not stat file");
1367 exit(EXIT_FAILURE);
1368 }
1369 int region_size = buf.st_size;
1370
1371 printf("File %s is %d bytes\n", region_fname, region_size);
1372
1373 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001374 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001375 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1376 " bytes. Not injecting.\n",
1377 region_name(region_type), region.size,
1378 region.size, region_size, region_size);
1379 exit(EXIT_FAILURE);
1380 }
1381
1382 int offset = 0;
1383 if ((region_type == 1) && (region_size < region.size)) {
1384 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1385 " bytes. Padding before injecting.\n",
1386 region_name(region_type), region.size,
1387 region.size, region_size, region_size);
1388 offset = region.size - region_size;
1389 memset(image + region.base, 0xff, offset);
1390 }
1391
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001392 if (size < region.base + offset + region_size) {
1393 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1394 size, region.base + offset + region_size);
1395 exit(EXIT_FAILURE);
1396 }
1397
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001398 if (read(region_fd, image + region.base + offset, region_size)
1399 != region_size) {
1400 perror("Could not read file");
1401 exit(EXIT_FAILURE);
1402 }
1403
1404 close(region_fd);
1405
1406 printf("Adding %s as the %s section of %s\n",
1407 region_fname, region_name(region_type), filename);
1408 write_image(filename, image, size);
1409}
1410
Jacob Garber595d9262019-06-27 17:33:10 -06001411static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001412{
1413 unsigned int y = 1;
1414 if (x == 0)
1415 return 0;
1416 while (y <= x)
1417 y = y << 1;
1418
1419 return y;
1420}
1421
1422/**
1423 * Determine if two memory regions overlap.
1424 *
1425 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001426 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001427 * @return 1 if the two regions overlap
1428 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001429static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001430{
Bill XIEfa5f9942017-09-12 11:22:29 +08001431 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001432 return 0;
1433
Nico Huber844eda02019-01-05 00:06:19 +01001434 /* r1 should be either completely below or completely above r2 */
1435 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001436}
1437
Jacob Garber595d9262019-06-27 17:33:10 -06001438static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001439 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001440{
1441 FILE *romlayout;
1442 char tempstr[256];
1443 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001444 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001445 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001446 region_t current_regions[MAX_REGIONS];
1447 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001448 int new_extent = 0;
1449 char *new_image;
1450
1451 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001452 frba_t *frba = find_frba(image, size);
1453 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001454 exit(EXIT_FAILURE);
1455
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001456 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001457 current_regions[i] = get_region(frba, i);
1458 new_regions[i] = get_region(frba, i);
1459 }
1460
1461 /* read new layout */
1462 romlayout = fopen(layout_fname, "r");
1463
1464 if (!romlayout) {
1465 perror("Could not read layout file.\n");
1466 exit(EXIT_FAILURE);
1467 }
1468
1469 while (!feof(romlayout)) {
1470 char *tstr1, *tstr2;
1471
Patrick Georgi802ad522014-08-09 17:12:23 +02001472 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001473 layout_region_name))
1474 continue;
1475
1476 region_number = region_num(layout_region_name);
1477 if (region_number < 0)
1478 continue;
1479
1480 tstr1 = strtok(tempstr, ":");
1481 tstr2 = strtok(NULL, ":");
1482 if (!tstr1 || !tstr2) {
1483 fprintf(stderr, "Could not parse layout file.\n");
1484 exit(EXIT_FAILURE);
1485 }
1486 new_regions[region_number].base = strtol(tstr1,
1487 (char **)NULL, 16);
1488 new_regions[region_number].limit = strtol(tstr2,
1489 (char **)NULL, 16);
1490 new_regions[region_number].size =
1491 new_regions[region_number].limit -
1492 new_regions[region_number].base + 1;
1493
1494 if (new_regions[region_number].size < 0)
1495 new_regions[region_number].size = 0;
1496 }
1497 fclose(romlayout);
1498
1499 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001500 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001501 if (new_regions[i].size == 0)
1502 continue;
1503
1504 if (new_regions[i].size < current_regions[i].size) {
1505 printf("DANGER: Region %s is shrinking.\n",
1506 region_name(i));
1507 printf(" The region will be truncated to fit.\n");
1508 printf(" This may result in an unusable image.\n");
1509 }
1510
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001511 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001512 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001513 fprintf(stderr, "Regions would overlap.\n");
1514 exit(EXIT_FAILURE);
1515 }
1516 }
1517
1518 /* detect if the image size should grow */
1519 if (new_extent < new_regions[i].limit)
1520 new_extent = new_regions[i].limit;
1521 }
1522
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001523 /* check if the image is actually a Flash Descriptor region */
1524 if (size == new_regions[0].size) {
1525 printf("The image is a single Flash Descriptor:\n");
1526 printf(" Only the descriptor will be modified\n");
1527 new_extent = size;
1528 } else {
1529 new_extent = next_pow2(new_extent - 1);
1530 if (new_extent != size) {
1531 printf("The image has changed in size.\n");
1532 printf("The old image is %d bytes.\n", size);
1533 printf("The new image is %d bytes.\n", new_extent);
1534 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001535 }
1536
1537 /* copy regions to a new image */
1538 new_image = malloc(new_extent);
1539 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001540 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001541 int copy_size = new_regions[i].size;
1542 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001543 const region_t *current = &current_regions[i];
1544 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001545
Bill XIEfa5f9942017-09-12 11:22:29 +08001546 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001547 continue;
1548
Bill XIEfa5f9942017-09-12 11:22:29 +08001549 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001550 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001551 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001552 if (i == REGION_BIOS)
1553 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001554 }
1555
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001556 if ((i == REGION_BIOS) && (new->size < current->size)) {
1557 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001558 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001559 }
1560
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001561 if (size < current->base + offset_current + copy_size) {
1562 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1563 region_name(i));
1564 continue;
1565 };
1566
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001567 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1568 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001569 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1570 offset_current, current->limit, current->size);
1571 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1572 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001573
Bill XIEfa5f9942017-09-12 11:22:29 +08001574 memcpy(new_image + new->base + offset_new,
1575 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001576 copy_size);
1577 }
1578
1579 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001580 frba = find_frba(new_image, new_extent);
1581 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001582 exit(EXIT_FAILURE);
1583
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001584 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001585 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001586 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001587
1588 write_image(filename, new_image, new_extent);
1589 free(new_image);
1590}
1591
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001592static void print_version(void)
1593{
1594 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1595 printf("Copyright (C) 2011 Google Inc.\n\n");
1596 printf
1597 ("This program is free software: you can redistribute it and/or modify\n"
1598 "it under the terms of the GNU General Public License as published by\n"
1599 "the Free Software Foundation, version 2 of the License.\n\n"
1600 "This program is distributed in the hope that it will be useful,\n"
1601 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1602 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001603 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001604}
1605
1606static void print_usage(const char *name)
1607{
1608 printf("usage: %s [-vhdix?] <filename>\n", name);
1609 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001610 " -d | --dump: dump intel firmware descriptor\n"
1611 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1612 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1613 " -x | --extract: extract intel fd modules\n"
1614 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1615 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001616 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001617 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1618 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1619 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1620 " can only be used once per run:\n"
1621 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1622 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1623 " Dual Output Fast Read Support\n"
1624 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301625 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001626 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001627 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1628 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001629 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301630 " adl - Alder Lake\n"
1631 " aplk - Apollo Lake\n"
1632 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08001633 " lbg - Lewisburg PCH\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001634 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301635 " glk - Gemini Lake\n"
1636 " icl - Ice Lake\n"
1637 " jsl - Jasper Lake\n"
1638 " sklkbl - Sky Lake/Kaby Lake\n"
1639 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001640 " -S | --setpchstrap Write a PCH strap\n"
1641 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001642 " -v | --version: print the version\n"
1643 " -h | --help: print this help\n\n"
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001644 "<region> is one of Descriptor, BIOS, ME, GbE, Platform, res1, res2, res3\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001645 "\n");
1646}
1647
1648int main(int argc, char *argv[])
1649{
1650 int opt, option_index = 0;
1651 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001652 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001653 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Usha P412679d2020-10-15 11:25:08 +05301654 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001655 char *region_type_string = NULL, *region_fname = NULL;
1656 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001657 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001658 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001659 unsigned int value = 0;
1660 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001661 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001662 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1663
Bill XIEfa5f9942017-09-12 11:22:29 +08001664 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001665 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001666 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001667 {"extract", 0, NULL, 'x'},
1668 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001669 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001670 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001671 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001672 {"density", 1, NULL, 'D'},
1673 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001674 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001675 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001676 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301677 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001678 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001679 {"version", 0, NULL, 'v'},
1680 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001681 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001682 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001683 {"setpchstrap", 1, NULL, 'S'},
1684 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001685 {0, 0, 0, 0}
1686 };
1687
Usha P412679d2020-10-15 11:25:08 +05301688 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 -07001689 long_options, &option_index)) != EOF) {
1690 switch (opt) {
1691 case 'd':
1692 mode_dump = 1;
1693 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001694 case 'S':
1695 mode_setstrap = 1;
1696 pchstrap = strtoul(optarg, NULL, 0);
1697 break;
1698 case 'V':
1699 value = strtoul(optarg, NULL, 0);
1700 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001701 case 'f':
1702 mode_layout = 1;
1703 layout_fname = strdup(optarg);
1704 if (!layout_fname) {
1705 fprintf(stderr, "No layout file specified\n");
1706 print_usage(argv[0]);
1707 exit(EXIT_FAILURE);
1708 }
1709 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001710 case 'x':
1711 mode_extract = 1;
1712 break;
1713 case 'i':
1714 // separate type and file name
1715 region_type_string = strdup(optarg);
1716 region_fname = strchr(region_type_string, ':');
1717 if (!region_fname) {
1718 print_usage(argv[0]);
1719 exit(EXIT_FAILURE);
1720 }
1721 region_fname[0] = '\0';
1722 region_fname++;
1723 // Descriptor, BIOS, ME, GbE, Platform
1724 // valid type?
1725 if (!strcasecmp("Descriptor", region_type_string))
1726 region_type = 0;
1727 else if (!strcasecmp("BIOS", region_type_string))
1728 region_type = 1;
1729 else if (!strcasecmp("ME", region_type_string))
1730 region_type = 2;
1731 else if (!strcasecmp("GbE", region_type_string))
1732 region_type = 3;
1733 else if (!strcasecmp("Platform", region_type_string))
1734 region_type = 4;
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001735 else if (!strcasecmp("res1", region_type_string))
1736 region_type = 5;
1737 else if (!strcasecmp("res2", region_type_string))
1738 region_type = 6;
1739 else if (!strcasecmp("res3", region_type_string))
1740 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001741 else if (!strcasecmp("EC", region_type_string))
1742 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001743 if (region_type == -1) {
1744 fprintf(stderr, "No such region type: '%s'\n\n",
1745 region_type_string);
1746 print_usage(argv[0]);
1747 exit(EXIT_FAILURE);
1748 }
1749 mode_inject = 1;
1750 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001751 case 'n':
1752 mode_newlayout = 1;
1753 layout_fname = strdup(optarg);
1754 if (!layout_fname) {
1755 fprintf(stderr, "No layout file specified\n");
1756 print_usage(argv[0]);
1757 exit(EXIT_FAILURE);
1758 }
1759 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001760 case 'O':
1761 new_filename = strdup(optarg);
1762 if (!new_filename) {
1763 fprintf(stderr, "No output filename specified\n");
1764 print_usage(argv[0]);
1765 exit(EXIT_FAILURE);
1766 }
1767 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001768 case 'D':
1769 mode_density = 1;
1770 new_density = strtoul(optarg, NULL, 0);
1771 switch (new_density) {
1772 case 512:
1773 new_density = COMPONENT_DENSITY_512KB;
1774 break;
1775 case 1:
1776 new_density = COMPONENT_DENSITY_1MB;
1777 break;
1778 case 2:
1779 new_density = COMPONENT_DENSITY_2MB;
1780 break;
1781 case 4:
1782 new_density = COMPONENT_DENSITY_4MB;
1783 break;
1784 case 8:
1785 new_density = COMPONENT_DENSITY_8MB;
1786 break;
1787 case 16:
1788 new_density = COMPONENT_DENSITY_16MB;
1789 break;
1790 case 32:
1791 new_density = COMPONENT_DENSITY_32MB;
1792 break;
1793 case 64:
1794 new_density = COMPONENT_DENSITY_64MB;
1795 break;
1796 case 0:
1797 new_density = COMPONENT_DENSITY_UNUSED;
1798 break;
1799 default:
1800 printf("error: Unknown density\n");
1801 print_usage(argv[0]);
1802 exit(EXIT_FAILURE);
1803 }
1804 break;
1805 case 'C':
1806 selected_chip = strtol(optarg, NULL, 0);
1807 if (selected_chip > 2) {
1808 fprintf(stderr, "error: Invalid chip selection\n");
1809 print_usage(argv[0]);
1810 exit(EXIT_FAILURE);
1811 }
1812 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001813 case 'M':
1814 mode_altmedisable = 1;
1815 altmedisable = strtol(optarg, NULL, 0);
1816 if (altmedisable > 1) {
1817 fprintf(stderr, "error: Illegal value\n");
1818 print_usage(argv[0]);
1819 exit(EXIT_FAILURE);
1820 }
1821 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001822 case 's':
1823 // Parse the requested SPI frequency
1824 inputfreq = strtol(optarg, NULL, 0);
1825 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001826 case 17:
1827 spifreq = SPI_FREQUENCY_17MHZ;
1828 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001829 case 20:
1830 spifreq = SPI_FREQUENCY_20MHZ;
1831 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001832 case 30:
1833 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1834 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001835 case 33:
1836 spifreq = SPI_FREQUENCY_33MHZ;
1837 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001838 case 48:
1839 spifreq = SPI_FREQUENCY_48MHZ;
1840 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001841 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001842 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001843 break;
1844 default:
1845 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1846 inputfreq);
1847 print_usage(argv[0]);
1848 exit(EXIT_FAILURE);
1849 }
1850 mode_spifreq = 1;
1851 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001852 case 'e':
1853 mode_em100 = 1;
1854 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001855 case 'l':
1856 mode_locked = 1;
1857 if (mode_unlocked == 1) {
1858 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1859 exit(EXIT_FAILURE);
1860 }
1861 break;
Usha P412679d2020-10-15 11:25:08 +05301862 case 'r':
1863 mode_read = 1;
1864 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001865 case 'u':
1866 mode_unlocked = 1;
1867 if (mode_locked == 1) {
1868 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1869 exit(EXIT_FAILURE);
1870 }
1871 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001872 case 'p':
1873 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001874 platform = PLATFORM_APL;
1875 } else if (!strcmp(optarg, "cnl")) {
1876 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08001877 } else if (!strcmp(optarg, "lbg")) {
1878 platform = PLATFORM_LBG;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001879 } else if (!strcmp(optarg, "ehl")) {
1880 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001881 } else if (!strcmp(optarg, "glk")) {
1882 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301883 } else if (!strcmp(optarg, "icl")) {
1884 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301885 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001886 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001887 } else if (!strcmp(optarg, "sklkbl")) {
1888 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001889 } else if (!strcmp(optarg, "tgl")) {
1890 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301891 } else if (!strcmp(optarg, "adl")) {
1892 platform = PLATFORM_ADL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001893 } else {
1894 fprintf(stderr, "Unknown platform: %s\n", optarg);
1895 exit(EXIT_FAILURE);
1896 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001897 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001898 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001899 case 't':
1900 mode_validate = 1;
1901 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001902 case 'v':
1903 print_version();
1904 exit(EXIT_SUCCESS);
1905 break;
1906 case 'h':
1907 case '?':
1908 default:
1909 print_usage(argv[0]);
1910 exit(EXIT_SUCCESS);
1911 break;
1912 }
1913 }
1914
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001915 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001916 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001917 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001918 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001919 print_usage(argv[0]);
1920 exit(EXIT_FAILURE);
1921 }
1922
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001923 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001924 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001925 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001926 fprintf(stderr, "You need to specify a mode.\n\n");
1927 print_usage(argv[0]);
1928 exit(EXIT_FAILURE);
1929 }
1930
1931 if (optind + 1 != argc) {
1932 fprintf(stderr, "You need to specify a file.\n\n");
1933 print_usage(argv[0]);
1934 exit(EXIT_FAILURE);
1935 }
1936
1937 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001938 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001939 if (bios_fd == -1) {
1940 perror("Could not open file");
1941 exit(EXIT_FAILURE);
1942 }
1943 struct stat buf;
1944 if (fstat(bios_fd, &buf) == -1) {
1945 perror("Could not stat file");
1946 exit(EXIT_FAILURE);
1947 }
1948 int size = buf.st_size;
1949
1950 printf("File %s is %d bytes\n", filename, size);
1951
1952 char *image = malloc(size);
1953 if (!image) {
1954 printf("Out of memory.\n");
1955 exit(EXIT_FAILURE);
1956 }
1957
1958 if (read(bios_fd, image, size) != size) {
1959 perror("Could not read file");
1960 exit(EXIT_FAILURE);
1961 }
1962
1963 close(bios_fd);
1964
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001965 // generate new filename
1966 if (new_filename == NULL) {
1967 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1968 if (!new_filename) {
1969 printf("Out of memory.\n");
1970 exit(EXIT_FAILURE);
1971 }
1972 // - 5: leave room for ".new\0"
1973 strcpy(new_filename, filename);
1974 strcat(new_filename, ".new");
1975 }
1976
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001977 check_ifd_version(image, size);
1978
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001979 if (mode_dump)
1980 dump_fd(image, size);
1981
Chris Douglass03ce0142014-02-26 13:30:13 -05001982 if (mode_layout)
1983 dump_layout(image, size, layout_fname);
1984
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001985 if (mode_extract)
1986 write_regions(image, size);
1987
Mathew Kingc7ddc992019-08-08 14:59:25 -06001988 if (mode_validate)
1989 validate_layout(image, size);
1990
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001991 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001992 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001993 region_fname);
1994
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001995 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001996 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001997
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001998 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001999 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002000
Jan Tatjefa317512016-03-11 00:52:07 +01002001 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002002 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002003
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002004 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002005 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002006
Alexander Couzensd12ea112016-09-10 13:33:05 +02002007 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002008 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002009
Usha P412679d2020-10-15 11:25:08 +05302010 if (mode_read)
2011 enable_cpu_read_me(new_filename, image, size);
2012
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002013 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002014 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002015
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002016 if (mode_setstrap) {
2017 fpsba_t *fpsba = find_fpsba(image, size);
2018 const fdbar_t *fdb = find_fd(image, size);
2019 set_pchstrap(fpsba, fdb, pchstrap, value);
2020 write_image(new_filename, image, size);
2021 }
2022
Bill XIEb3e15a22017-09-07 18:34:50 +08002023 if (mode_altmedisable) {
2024 fpsba_t *fpsba = find_fpsba(image, size);
2025 fmsba_t *fmsba = find_fmsba(image, size);
2026 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002027 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002028 }
2029
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002030 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002031 free(image);
2032
2033 return 0;
2034}