blob: e99cdeca8c010b06e9335f586147c2cadfaf1b37 [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;
208 } else {
Subrata Banik89db2252020-08-26 14:49:17 +0530209 return CHIPSET_100_200_SERIES_SUNRISE_POINT;
Bill XIEb3e15a22017-09-07 18:34:50 +0800210 }
211}
212
Subrata Banik8c082e52021-06-10 23:02:29 +0530213static enum ich_chipset ifd2_platform_to_chipset(const int pindex)
214{
215 switch (pindex) {
216 case PLATFORM_GLK:
217 return CHIPSET_N_J_SERIES_GEMINI_LAKE;
218 case PLATFORM_JSL:
219 return CHIPSET_N_SERIES_JASPER_LAKE;
220 case PLATFORM_EHL:
221 return CHIPSET_x6000_SERIES_ELKHART_LAKE;
222 case PLATFORM_CNL:
223 return CHIPSET_300_SERIES_CANNON_POINT;
224 case PLATFORM_TGL:
225 case PLATFORM_ADL:
226 return CHIPSET_500_600_SERIES_TIGER_ALDER_POINT;
227 case PLATFORM_ICL:
228 return CHIPSET_400_SERIES_ICE_POINT;
Johnny Line273a022021-06-22 11:26:46 +0800229 case PLATFORM_LBG:
230 return CHIPSET_C620_SERIES_LEWISBURG;
Subrata Banik8c082e52021-06-10 23:02:29 +0530231 default:
232 return CHIPSET_PCH_UNKNOWN;
233 }
234}
235
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700236/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700237 * Some newer platforms have re-defined the FCBA field that was used to
238 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
239 * have the required FCBA field, but are IFD v2 and return true if current
240 * platform is one of them.
241 */
242static int is_platform_ifd_2(void)
243{
244 static const int ifd_2_platforms[] = {
245 PLATFORM_GLK,
246 PLATFORM_CNL,
Johnny Line273a022021-06-22 11:26:46 +0800247 PLATFORM_LBG,
Aamir Bohra1018be22018-06-29 15:08:50 +0530248 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700249 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530250 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700251 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530252 PLATFORM_ADL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700253 };
254 unsigned int i;
255
256 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
257 if (platform == ifd_2_platforms[i])
258 return 1;
259 }
260
261 return 0;
262}
263
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700264static void check_ifd_version(char *image, int size)
265{
Subrata Banik8c082e52021-06-10 23:02:29 +0530266 if (is_platform_ifd_2()) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700267 ifd_version = IFD_VERSION_2;
Subrata Banik8c082e52021-06-10 23:02:29 +0530268 chipset = ifd2_platform_to_chipset(platform);
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700269 max_regions = MAX_REGIONS;
Subrata Banik8c082e52021-06-10 23:02:29 +0530270 } else {
271 ifd_version = IFD_VERSION_1;
272 chipset = ifd1_guess_chipset(image, size);
273 max_regions = MAX_REGIONS_OLD;
274 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700275}
276
Bill XIEfa5f9942017-09-12 11:22:29 +0800277static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700278{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500279 int base_mask;
280 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700281 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700282 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500283
284 if (ifd_version >= IFD_VERSION_2)
285 base_mask = 0x7fff;
286 else
287 base_mask = 0xfff;
288
289 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700290
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400291 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800292 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700293 exit (EXIT_FAILURE);
294 }
295
Bill XIE4651d452017-09-12 11:54:48 +0800296 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700297 region.base = (flreg & base_mask) << 12;
298 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700299 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500300
Chris Douglass03ce0142014-02-26 13:30:13 -0500301 if (region.size < 0)
302 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700303
304 return region;
305}
306
Bill XIEfa5f9942017-09-12 11:22:29 +0800307static void set_region(frba_t *frba, unsigned int region_type,
308 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500309{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400310 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800311 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500312 exit (EXIT_FAILURE);
313 }
Bill XIE4651d452017-09-12 11:54:48 +0800314
315 frba->flreg[region_type] =
316 (((region->limit >> 12) & 0x7fff) << 16) |
317 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500318}
319
Bill XIEfa5f9942017-09-12 11:22:29 +0800320static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700321{
Bill XIEfa5f9942017-09-12 11:22:29 +0800322 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700323 fprintf(stderr, "Invalid region type.\n");
324 exit (EXIT_FAILURE);
325 }
326
Chris Douglass03ce0142014-02-26 13:30:13 -0500327 return region_names[region_type].pretty;
328}
329
Bill XIEfa5f9942017-09-12 11:22:29 +0800330static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500331{
Bill XIEfa5f9942017-09-12 11:22:29 +0800332 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500333 fprintf(stderr, "Invalid region type.\n");
334 exit (EXIT_FAILURE);
335 }
336
337 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700338}
339
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500340static int region_num(const char *name)
341{
Bill XIEfa5f9942017-09-12 11:22:29 +0800342 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500343
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200344 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500345 if (strcasecmp(name, region_names[i].pretty) == 0)
346 return i;
347 if (strcasecmp(name, region_names[i].terse) == 0)
348 return i;
349 }
350
351 return -1;
352}
353
Bill XIEfa5f9942017-09-12 11:22:29 +0800354static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700355{
Bill XIEfa5f9942017-09-12 11:22:29 +0800356 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700357 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700358 exit (EXIT_FAILURE);
359 }
360
Bill XIE1bf65062017-09-12 11:31:37 +0800361 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700362}
363
Bill XIEfa5f9942017-09-12 11:22:29 +0800364static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700365{
366 region_t region = get_region(frba, num);
367 printf(" Flash Region %d (%s): %08x - %08x %s\n",
368 num, region_name(num), region.base, region.limit,
369 region.size < 1 ? "(unused)" : "");
370}
371
Bill XIEfa5f9942017-09-12 11:22:29 +0800372static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
373 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500374{
375 region_t region = get_region(frba, num);
376 snprintf(buf, bufsize, "%08x:%08x %s\n",
377 region.base, region.limit, region_name_short(num));
378}
379
Bill XIEfa5f9942017-09-12 11:22:29 +0800380static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700381{
Bill XIE4651d452017-09-12 11:54:48 +0800382 unsigned int i;
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530383 region_t region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700384 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800385 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530386 region = get_region(frba, i);
387 /* Skip unused & reserved Flash Region */
388 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
389 continue;
390
Bill XIE4651d452017-09-12 11:54:48 +0800391 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
392 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700393 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700394}
395
Bill XIEfa5f9942017-09-12 11:22:29 +0800396static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500397{
398 char buf[LAYOUT_LINELEN];
399 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800400 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500401
402 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
403 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
404 if (layout_fd == -1) {
405 perror("Could not open file");
406 exit(EXIT_FAILURE);
407 }
408
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200409 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200410 region_t region = get_region(frba, i);
411 /* is region invalid? */
412 if (region.size < 1)
413 continue;
414
Chris Douglass03ce0142014-02-26 13:30:13 -0500415 dump_region_layout(buf, bufsize, i, frba);
416 if (write(layout_fd, buf, strlen(buf)) < 0) {
417 perror("Could not write to file");
418 exit(EXIT_FAILURE);
419 }
420 }
421 close(layout_fd);
422 printf("Wrote layout to %s\n", layout_fname);
423}
424
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530425static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700426{
427 switch (freq) {
428 case SPI_FREQUENCY_20MHZ:
429 printf("20MHz");
430 break;
431 case SPI_FREQUENCY_33MHZ:
432 printf("33MHz");
433 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700434 case SPI_FREQUENCY_48MHZ:
435 printf("48MHz");
436 break;
437 case SPI_FREQUENCY_50MHZ_30MHZ:
438 switch (ifd_version) {
439 case IFD_VERSION_1:
440 printf("50MHz");
441 break;
442 case IFD_VERSION_2:
443 printf("30MHz");
444 break;
445 }
446 break;
447 case SPI_FREQUENCY_17MHZ:
448 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700449 break;
450 default:
451 printf("unknown<%x>MHz", freq);
452 }
453}
454
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530455static void _decode_spi_frequency_500_series(unsigned int freq)
456{
457 switch (freq) {
458 case SPI_FREQUENCY_100MHZ:
459 printf("100MHz");
460 break;
461 case SPI_FREQUENCY_50MHZ:
462 printf("50MHz");
463 break;
464 case SPI_FREQUENCY_500SERIES_33MHZ:
465 printf("33MHz");
466 break;
467 case SPI_FREQUENCY_25MHZ:
468 printf("25MHz");
469 break;
470 case SPI_FREQUENCY_14MHZ:
471 printf("14MHz");
472 break;
473 default:
474 printf("unknown<%x>MHz", freq);
475 }
476}
477
478static void decode_spi_frequency(unsigned int freq)
479{
Subrata Banika5f47812020-09-29 11:43:01 +0530480 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530481 _decode_spi_frequency_500_series(freq);
482 else
483 _decode_spi_frequency(freq);
484}
485
Subrata Banike5d39922020-08-26 16:01:42 +0530486static void _decode_espi_frequency(unsigned int freq)
487{
488 switch (freq) {
489 case ESPI_FREQUENCY_20MHZ:
490 printf("20MHz");
491 break;
492 case ESPI_FREQUENCY_24MHZ:
493 printf("24MHz");
494 break;
495 case ESPI_FREQUENCY_30MHZ:
496 printf("30MHz");
497 break;
498 case ESPI_FREQUENCY_48MHZ:
499 printf("48MHz");
500 break;
501 case ESPI_FREQUENCY_60MHZ:
502 printf("60MHz");
503 break;
504 case ESPI_FREQUENCY_17MHZ:
505 printf("17MHz");
506 break;
507 default:
508 printf("unknown<%x>MHz", freq);
509 }
510}
511
512static void _decode_espi_frequency_500_series(unsigned int freq)
513{
514 switch (freq) {
515 case ESPI_FREQUENCY_500SERIES_20MHZ:
516 printf("20MHz");
517 break;
518 case ESPI_FREQUENCY_500SERIES_24MHZ:
519 printf("24MHz");
520 break;
521 case ESPI_FREQUENCY_500SERIES_25MHZ:
522 printf("25MHz");
523 break;
524 case ESPI_FREQUENCY_500SERIES_48MHZ:
525 printf("48MHz");
526 break;
527 case ESPI_FREQUENCY_500SERIES_60MHZ:
528 printf("60MHz");
529 break;
530 default:
531 printf("unknown<%x>MHz", freq);
532 }
533}
534
535static void decode_espi_frequency(unsigned int freq)
536{
Subrata Banika5f47812020-09-29 11:43:01 +0530537 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530538 _decode_espi_frequency_500_series(freq);
539 else
540 _decode_espi_frequency(freq);
541}
542
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700543static void decode_component_density(unsigned int density)
544{
545 switch (density) {
546 case COMPONENT_DENSITY_512KB:
547 printf("512KB");
548 break;
549 case COMPONENT_DENSITY_1MB:
550 printf("1MB");
551 break;
552 case COMPONENT_DENSITY_2MB:
553 printf("2MB");
554 break;
555 case COMPONENT_DENSITY_4MB:
556 printf("4MB");
557 break;
558 case COMPONENT_DENSITY_8MB:
559 printf("8MB");
560 break;
561 case COMPONENT_DENSITY_16MB:
562 printf("16MB");
563 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700564 case COMPONENT_DENSITY_32MB:
565 printf("32MB");
566 break;
567 case COMPONENT_DENSITY_64MB:
568 printf("64MB");
569 break;
570 case COMPONENT_DENSITY_UNUSED:
571 printf("UNUSED");
572 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700573 default:
574 printf("unknown<%x>MB", density);
575 }
576}
577
Subrata Banik26058dc2020-08-26 15:12:16 +0530578static int is_platform_with_pch(void)
579{
580 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
581 return 1;
582
583 return 0;
584}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530585
586/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
587static int is_platform_with_100x_series_pch(void)
588{
589 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530590 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530591 return 1;
592
593 return 0;
594}
595
Subrata Banike5d39922020-08-26 16:01:42 +0530596static void dump_fcba(const fcba_t *fcba, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700597{
Subrata Banike5d39922020-08-26 16:01:42 +0530598 unsigned int freq;
599
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700600 printf("\nFound Component Section\n");
601 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700602 printf(" Dual Output Fast Read Support: %ssupported\n",
603 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700604 printf(" Read ID/Read Status Clock Frequency: ");
605 decode_spi_frequency((fcba->flcomp >> 27) & 7);
606 printf("\n Write/Erase Clock Frequency: ");
607 decode_spi_frequency((fcba->flcomp >> 24) & 7);
608 printf("\n Fast Read Clock Frequency: ");
609 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700610 printf("\n Fast Read Support: %ssupported",
611 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530612 if (is_platform_with_100x_series_pch() &&
613 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
614 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530615 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530616 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
617 else
618 freq = (fcba->flcomp >> 17) & 7;
619 decode_espi_frequency(freq);
620 } else {
621 printf("\n Read Clock Frequency: ");
622 decode_spi_frequency((fcba->flcomp >> 17) & 7);
623 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700624
625 switch (ifd_version) {
626 case IFD_VERSION_1:
627 printf("\n Component 2 Density: ");
628 decode_component_density((fcba->flcomp >> 3) & 7);
629 printf("\n Component 1 Density: ");
630 decode_component_density(fcba->flcomp & 7);
631 break;
632 case IFD_VERSION_2:
633 printf("\n Component 2 Density: ");
634 decode_component_density((fcba->flcomp >> 4) & 0xf);
635 printf("\n Component 1 Density: ");
636 decode_component_density(fcba->flcomp & 0xf);
637 break;
638 }
639
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700640 printf("\n");
641 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700642 printf(" Invalid Instruction 3: 0x%02x\n",
643 (fcba->flill >> 24) & 0xff);
644 printf(" Invalid Instruction 2: 0x%02x\n",
645 (fcba->flill >> 16) & 0xff);
646 printf(" Invalid Instruction 1: 0x%02x\n",
647 (fcba->flill >> 8) & 0xff);
648 printf(" Invalid Instruction 0: 0x%02x\n",
649 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530650 if (is_platform_with_100x_series_pch()) {
651 printf("FLILL1 0x%08x\n", fcba->flpb);
652 printf(" Invalid Instruction 7: 0x%02x\n",
653 (fcba->flpb >> 24) & 0xff);
654 printf(" Invalid Instruction 6: 0x%02x\n",
655 (fcba->flpb >> 16) & 0xff);
656 printf(" Invalid Instruction 5: 0x%02x\n",
657 (fcba->flpb >> 8) & 0xff);
658 printf(" Invalid Instruction 4: 0x%02x\n",
659 fcba->flpb & 0xff);
660 } else {
661 printf("FLPB 0x%08x\n", fcba->flpb);
662 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
663 (fcba->flpb & 0xfff) << 12);
664 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700665}
666
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200667static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700668{
Bill XIE4651d452017-09-12 11:54:48 +0800669 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200670 /* SoC Strap Length, aka PSL, aka ISL */
671 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
672
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700673 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200674 for (i = 0; i < SSL; i++)
675 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800676
677 if (ifd_version >= IFD_VERSION_2) {
678 printf("HAP bit is %sset\n",
679 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
680 } else if (chipset >= CHIPSET_ICH8
681 && chipset <= CHIPSET_ICH10) {
682 printf("ICH_MeDisable bit is %sset\n",
683 fpsba->pchstrp[0] & 1 ? "" : "not ");
684 } else {
685 printf("AltMeDisable bit is %sset\n",
686 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
687 }
688
Bill XIE4651d452017-09-12 11:54:48 +0800689 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700690}
691
692static void decode_flmstr(uint32_t flmstr)
693{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700694 int wr_shift, rd_shift;
695 if (ifd_version >= IFD_VERSION_2) {
696 wr_shift = FLMSTR_WR_SHIFT_V2;
697 rd_shift = FLMSTR_RD_SHIFT_V2;
698 } else {
699 wr_shift = FLMSTR_WR_SHIFT_V1;
700 rd_shift = FLMSTR_RD_SHIFT_V1;
701 }
702
703 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700704 if (ifd_version >= IFD_VERSION_2)
705 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700706 (flmstr & (1 << (wr_shift + 8))) ?
707 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700708 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700709 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700710 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700711 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700712 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700713 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700714 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700715 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700716 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700717 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700718
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700719 if (ifd_version >= IFD_VERSION_2)
720 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700721 (flmstr & (1 << (rd_shift + 8))) ?
722 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700723 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700724 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700725 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700726 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700727 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700728 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700729 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700730 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700731 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700732 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700733
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700734 /* Requestor ID doesn't exist for ifd 2 */
735 if (ifd_version < IFD_VERSION_2)
736 printf(" Requester ID: 0x%04x\n\n",
737 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700738}
739
Bill XIEfa5f9942017-09-12 11:22:29 +0800740static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700741{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700742 printf("Found Master Section\n");
743 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
744 decode_flmstr(fmba->flmstr1);
745 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
746 decode_flmstr(fmba->flmstr2);
747 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
748 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700749 if (ifd_version >= IFD_VERSION_2) {
750 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
751 decode_flmstr(fmba->flmstr5);
752 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700753}
754
Bill XIEfa5f9942017-09-12 11:22:29 +0800755static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700756{
Bill XIE612ec0e2017-08-30 16:10:27 +0800757 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700758 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800759 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
760 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800761
762 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
763 printf("MCH_MeDisable bit is %sset\n",
764 fmsba->data[0] & 1 ? "" : "not ");
765 printf("MCH_AltMeDisable bit is %sset\n",
766 fmsba->data[0] & (1 << 7) ? "" : "not ");
767 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700768}
769
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700770static void dump_jid(uint32_t jid)
771{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100772 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700773 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100774 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200775 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100776 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200777 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700778}
779
780static void dump_vscc(uint32_t vscc)
781{
782 printf(" Lower Erase Opcode: 0x%02x\n",
783 vscc >> 24);
784 printf(" Lower Write Enable on Write Status: 0x%02x\n",
785 vscc & (1 << 20) ? 0x06 : 0x50);
786 printf(" Lower Write Status Required: %s\n",
787 vscc & (1 << 19) ? "Yes" : "No");
788 printf(" Lower Write Granularity: %d bytes\n",
789 vscc & (1 << 18) ? 64 : 1);
790 printf(" Lower Block / Sector Erase Size: ");
791 switch ((vscc >> 16) & 0x3) {
792 case 0:
793 printf("256 Byte\n");
794 break;
795 case 1:
796 printf("4KB\n");
797 break;
798 case 2:
799 printf("8KB\n");
800 break;
801 case 3:
802 printf("64KB\n");
803 break;
804 }
805
806 printf(" Upper Erase Opcode: 0x%02x\n",
807 (vscc >> 8) & 0xff);
808 printf(" Upper Write Enable on Write Status: 0x%02x\n",
809 vscc & (1 << 4) ? 0x06 : 0x50);
810 printf(" Upper Write Status Required: %s\n",
811 vscc & (1 << 3) ? "Yes" : "No");
812 printf(" Upper Write Granularity: %d bytes\n",
813 vscc & (1 << 2) ? 64 : 1);
814 printf(" Upper Block / Sector Erase Size: ");
815 switch (vscc & 0x3) {
816 case 0:
817 printf("256 Byte\n");
818 break;
819 case 1:
820 printf("4KB\n");
821 break;
822 case 2:
823 printf("8KB\n");
824 break;
825 case 3:
826 printf("64KB\n");
827 break;
828 }
829}
830
Bill XIEfa5f9942017-09-12 11:22:29 +0800831static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700832{
833 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200834 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
835 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700836
837 printf("ME VSCC table:\n");
838 for (i = 0; i < num; i++) {
839 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
840 dump_jid(vtba->entry[i].jid);
841 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
842 dump_vscc(vtba->entry[i].vscc);
843 }
844 printf("\n");
845}
846
Bill XIEfa5f9942017-09-12 11:22:29 +0800847static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700848{
849 int i, j;
850 printf("OEM Section:\n");
851 for (i = 0; i < 4; i++) {
852 printf("%02x:", i << 4);
853 for (j = 0; j < 16; j++)
854 printf(" %02x", oem[(i<<4)+j]);
855 printf ("\n");
856 }
857 printf ("\n");
858}
859
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700860static void dump_fd(char *image, int size)
861{
Bill XIE612ec0e2017-08-30 16:10:27 +0800862 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700863 if (!fdb)
864 exit(EXIT_FAILURE);
865
Subrata Banik26058dc2020-08-26 15:12:16 +0530866 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
867 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700868 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530869 if (!is_platform_with_100x_series_pch())
870 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700871 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
872 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
873 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
874
875 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530876 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
877 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700878 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
879 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
880 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
881
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530882 if (!is_platform_with_100x_series_pch()) {
883 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
884 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
885 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
886 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700887
Subrata Banika5f47812020-09-29 11:43:01 +0530888 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530889 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
890 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
891 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
892 }
893
Stefan Tauner0d226142018-08-05 18:56:53 +0200894 char *flumap = find_flumap(image, size);
895 uint32_t flumap1 = *(uint32_t *)flumap;
896 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700897 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200898 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700899 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200900 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700901 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200902 (image + ((flumap1 & 0xff) << 4)),
903 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800904 dump_oem((const uint8_t *)image + 0xf00);
905
906 const frba_t *frba = find_frba(image, size);
907 const fcba_t *fcba = find_fcba(image, size);
908 const fpsba_t *fpsba = find_fpsba(image, size);
909 const fmba_t *fmba = find_fmba(image, size);
910 const fmsba_t *fmsba = find_fmsba(image, size);
911
912 if (frba && fcba && fpsba && fmba && fmsba) {
913 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +0530914 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200915 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800916 dump_fmba(fmba);
917 dump_fmsba(fmsba);
918 } else {
919 printf("FD is corrupted!\n");
920 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700921}
922
Bill XIEfa5f9942017-09-12 11:22:29 +0800923static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500924{
Bill XIE612ec0e2017-08-30 16:10:27 +0800925 const frba_t *frba = find_frba(image, size);
926 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500927 exit(EXIT_FAILURE);
928
Bill XIE612ec0e2017-08-30 16:10:27 +0800929 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500930}
931
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700932static void write_regions(char *image, int size)
933{
Bill XIEfa5f9942017-09-12 11:22:29 +0800934 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800935 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700936
Bill XIE612ec0e2017-08-30 16:10:27 +0800937 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700938 exit(EXIT_FAILURE);
939
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700940 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700941 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700942 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700943 if (region.size > 0) {
944 int region_fd;
945 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600946 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700947 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200948 if (region_fd < 0) {
949 perror("Error while trying to open file");
950 exit(EXIT_FAILURE);
951 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700952 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700953 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700954 close(region_fd);
955 }
956 }
957}
958
Mathew Kingc7ddc992019-08-08 14:59:25 -0600959static void validate_layout(char *image, int size)
960{
961 uint i, errors = 0;
962 struct fmap *fmap;
963 long int fmap_loc = fmap_find((uint8_t *)image, size);
964 const frba_t *frba = find_frba(image, size);
965
966 if (fmap_loc < 0 || !frba)
967 exit(EXIT_FAILURE);
968
969 fmap = (struct fmap *)(image + fmap_loc);
970
971 for (i = 0; i < max_regions; i++) {
972 if (region_names[i].fmapname == NULL)
973 continue;
974
975 region_t region = get_region(frba, i);
976
977 if (region.size == 0)
978 continue;
979
980 const struct fmap_area *area =
981 fmap_find_area(fmap, region_names[i].fmapname);
982
983 if (!area)
984 continue;
985
986 if ((uint)region.base != area->offset ||
987 (uint)region.size != area->size) {
988 printf("Region mismatch between %s and %s\n",
989 region_names[i].terse, area->name);
990 printf(" Descriptor region %s:\n", region_names[i].terse);
991 printf(" offset: 0x%08x\n", region.base);
992 printf(" length: 0x%08x\n", region.size);
993 printf(" FMAP area %s:\n", area->name);
994 printf(" offset: 0x%08x\n", area->offset);
995 printf(" length: 0x%08x\n", area->size);
996 errors++;
997 }
998 }
999
1000 if (errors > 0)
1001 exit(EXIT_FAILURE);
1002}
1003
Bill XIEfa5f9942017-09-12 11:22:29 +08001004static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001005{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001006 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001007 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001008
1009 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001010 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001011 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001012 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001013 if (new_fd < 0) {
1014 perror("Error while trying to open file");
1015 exit(EXIT_FAILURE);
1016 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001017 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001018 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001019 close(new_fd);
1020}
1021
Bill XIEfa5f9942017-09-12 11:22:29 +08001022static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001023 enum spi_frequency freq)
1024{
Bill XIE612ec0e2017-08-30 16:10:27 +08001025 fcba_t *fcba = find_fcba(image, size);
1026 if (!fcba)
1027 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001028
1029 /* clear bits 21-29 */
1030 fcba->flcomp &= ~0x3fe00000;
1031 /* Read ID and Read Status Clock Frequency */
1032 fcba->flcomp |= freq << 27;
1033 /* Write and Erase Clock Frequency */
1034 fcba->flcomp |= freq << 24;
1035 /* Fast Read Clock Frequency */
1036 fcba->flcomp |= freq << 21;
1037
1038 write_image(filename, image, size);
1039}
1040
Bill XIEfa5f9942017-09-12 11:22:29 +08001041static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001042{
Bill XIE612ec0e2017-08-30 16:10:27 +08001043 fcba_t *fcba = find_fcba(image, size);
1044 if (!fcba)
1045 exit(EXIT_FAILURE);
1046
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001047 int freq;
1048
1049 switch (ifd_version) {
1050 case IFD_VERSION_1:
1051 freq = SPI_FREQUENCY_20MHZ;
1052 break;
1053 case IFD_VERSION_2:
1054 freq = SPI_FREQUENCY_17MHZ;
1055 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001056 default:
1057 freq = SPI_FREQUENCY_17MHZ;
1058 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001059 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001060
1061 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001062 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001063}
1064
Bill XIEfa5f9942017-09-12 11:22:29 +08001065static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +01001066 unsigned int density)
1067{
Bill XIE612ec0e2017-08-30 16:10:27 +08001068 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001069 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001070 if (!fcba)
1071 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001072
1073 printf("Setting chip density to ");
1074 decode_component_density(density);
1075 printf("\n");
1076
1077 switch (ifd_version) {
1078 case IFD_VERSION_1:
1079 /* fail if selected density is not supported by this version */
1080 if ( (density == COMPONENT_DENSITY_32MB) ||
1081 (density == COMPONENT_DENSITY_64MB) ||
1082 (density == COMPONENT_DENSITY_UNUSED) ) {
1083 printf("error: Selected density not supported in IFD version 1.\n");
1084 exit(EXIT_FAILURE);
1085 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001086 mask = 0x7;
1087 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001088 break;
1089 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001090 mask = 0xf;
1091 chip2_offset = 4;
1092 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001093 default:
1094 printf("error: Unknown IFD version\n");
1095 exit(EXIT_FAILURE);
1096 break;
1097 }
1098
1099 /* clear chip density for corresponding chip */
1100 switch (selected_chip) {
1101 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001102 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001103 break;
1104 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001105 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001106 break;
1107 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001108 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001109 break;
1110 }
1111
1112 /* set the new density */
1113 if (selected_chip == 1 || selected_chip == 0)
1114 fcba->flcomp |= (density); /* first chip */
1115 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001116 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001117
1118 write_image(filename, image, size);
1119}
1120
Duncan Laurie7775d672019-06-06 13:39:26 -07001121static int check_region(const frba_t *frba, unsigned int region_type)
1122{
1123 region_t region;
1124
1125 if (!frba)
1126 return 0;
1127
1128 region = get_region(frba, region_type);
1129 return !!((region.base < region.limit) && (region.size > 0));
1130}
1131
Bill XIEfa5f9942017-09-12 11:22:29 +08001132static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001133{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001134 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001135 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001136 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001137 if (!fmba)
1138 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001139
1140 if (ifd_version >= IFD_VERSION_2) {
1141 wr_shift = FLMSTR_WR_SHIFT_V2;
1142 rd_shift = FLMSTR_RD_SHIFT_V2;
1143
1144 /* Clear non-reserved bits */
1145 fmba->flmstr1 &= 0xff;
1146 fmba->flmstr2 &= 0xff;
1147 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001148 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001149 } else {
1150 wr_shift = FLMSTR_WR_SHIFT_V1;
1151 rd_shift = FLMSTR_RD_SHIFT_V1;
1152
1153 fmba->flmstr1 = 0;
1154 fmba->flmstr2 = 0;
1155 /* Requestor ID */
1156 fmba->flmstr3 = 0x118;
1157 }
1158
Andrey Petrov96ecb772016-10-31 19:31:54 -07001159 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001160 case PLATFORM_APL:
1161 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001162 /* CPU/BIOS can read descriptor and BIOS */
1163 fmba->flmstr1 |= 0x3 << rd_shift;
1164 /* CPU/BIOS can write BIOS */
1165 fmba->flmstr1 |= 0x2 << wr_shift;
1166 /* TXE can read descriptor, BIOS and Device Expansion */
1167 fmba->flmstr2 |= 0x23 << rd_shift;
1168 /* TXE can only write Device Expansion */
1169 fmba->flmstr2 |= 0x20 << wr_shift;
1170 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001171 case PLATFORM_CNL:
1172 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001173 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001174 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301175 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001176 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301177 case PLATFORM_ADL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001178 /* CPU/BIOS can read descriptor and BIOS. */
1179 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1180 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1181 /* CPU/BIOS can write BIOS. */
1182 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1183 /* ME can read descriptor and ME. */
1184 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1185 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001186 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001187 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1188 if (check_region(frba, REGION_GBE)) {
1189 /* BIOS can read/write GbE. */
1190 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1191 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1192 /* ME can read GbE. */
1193 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1194 /* GbE can read descriptor and read/write GbE.. */
1195 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1196 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1197 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1198 }
1199 if (check_region(frba, REGION_PDR)) {
1200 /* BIOS can read/write PDR. */
1201 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1202 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1203 }
1204 if (check_region(frba, REGION_EC)) {
1205 /* BIOS can read EC. */
1206 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1207 /* EC can read descriptor and read/write EC. */
1208 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1209 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1210 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1211 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001212 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001213 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001214 /* CPU/BIOS can read descriptor and BIOS. */
1215 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1216 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1217 /* CPU/BIOS can write BIOS. */
1218 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1219 /* ME can read descriptor and ME. */
1220 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1221 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1222 /* ME can write ME. */
1223 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1224 if (check_region(frba, REGION_GBE)) {
1225 /* BIOS can read GbE. */
1226 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1227 /* BIOS can write GbE. */
1228 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1229 /* ME can read GbE. */
1230 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1231 /* ME can write GbE. */
1232 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1233 /* GbE can write GbE. */
1234 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1235 /* GbE can read GbE. */
1236 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1237 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001238 break;
1239 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001240
1241 write_image(filename, image, size);
1242}
1243
Usha P412679d2020-10-15 11:25:08 +05301244static void enable_cpu_read_me(const char *filename, char *image, int size)
1245{
1246 int rd_shift;
1247 fmba_t *fmba = find_fmba(image, size);
1248
1249 if (!fmba)
1250 exit(EXIT_FAILURE);
1251
1252 if (ifd_version >= IFD_VERSION_2)
1253 rd_shift = FLMSTR_RD_SHIFT_V2;
1254 else
1255 rd_shift = FLMSTR_RD_SHIFT_V1;
1256
1257 /* CPU/BIOS can read ME. */
1258 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1259
1260 write_image(filename, image, size);
1261}
1262
Bill XIEfa5f9942017-09-12 11:22:29 +08001263static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001264{
Bill XIE612ec0e2017-08-30 16:10:27 +08001265 fmba_t *fmba = find_fmba(image, size);
1266 if (!fmba)
1267 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001268
1269 if (ifd_version >= IFD_VERSION_2) {
1270 /* Access bits for each region are read: 19:8 write: 31:20 */
1271 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1272 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1273 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001274 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001275 } else {
1276 fmba->flmstr1 = 0xffff0000;
1277 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001278 /* Keep chipset specific Requester ID */
1279 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001280 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001281
1282 write_image(filename, image, size);
1283}
1284
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001285static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1286 const unsigned int value)
1287{
1288 if (!fpsba || !fdb) {
1289 fprintf(stderr, "Internal error\n");
1290 exit(EXIT_FAILURE);
1291 }
1292
1293 /* SoC Strap Length, aka PSL, aka ISL */
1294 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1295 if (strap >= SSL) {
1296 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1297 exit(EXIT_FAILURE);
1298 }
1299 fpsba->pchstrp[strap] = value;
1300}
1301
Bill XIEb3e15a22017-09-07 18:34:50 +08001302/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001303static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001304{
1305 if (ifd_version >= IFD_VERSION_2) {
1306 printf("%sting the HAP bit to %s Intel ME...\n",
1307 altmedisable?"Set":"Unset",
1308 altmedisable?"disable":"enable");
1309 if (altmedisable)
1310 fpsba->pchstrp[0] |= (1 << 16);
1311 else
1312 fpsba->pchstrp[0] &= ~(1 << 16);
1313 } else {
1314 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1315 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1316 "and MCH_AltMeDisable to %s Intel ME...\n",
1317 altmedisable?"Set":"Unset",
1318 altmedisable?"disable":"enable");
1319 if (altmedisable) {
1320 /* MCH_MeDisable */
1321 fmsba->data[0] |= 1;
1322 /* MCH_AltMeDisable */
1323 fmsba->data[0] |= (1 << 7);
1324 /* ICH_MeDisable */
1325 fpsba->pchstrp[0] |= 1;
1326 } else {
1327 fmsba->data[0] &= ~1;
1328 fmsba->data[0] &= ~(1 << 7);
1329 fpsba->pchstrp[0] &= ~1;
1330 }
1331 } else {
1332 printf("%sting the AltMeDisable to %s Intel ME...\n",
1333 altmedisable?"Set":"Unset",
1334 altmedisable?"disable":"enable");
1335 if (altmedisable)
1336 fpsba->pchstrp[10] |= (1 << 7);
1337 else
1338 fpsba->pchstrp[10] &= ~(1 << 7);
1339 }
1340 }
1341}
1342
Jacob Garber595d9262019-06-27 17:33:10 -06001343static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001344 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001345{
Bill XIE612ec0e2017-08-30 16:10:27 +08001346 frba_t *frba = find_frba(image, size);
1347 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001348 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001349
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001350 region_t region = get_region(frba, region_type);
1351 if (region.size <= 0xfff) {
1352 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1353 region_name(region_type));
1354 exit(EXIT_FAILURE);
1355 }
1356
Scott Duplichanf2c98372014-12-12 21:03:06 -06001357 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001358 if (region_fd == -1) {
1359 perror("Could not open file");
1360 exit(EXIT_FAILURE);
1361 }
1362 struct stat buf;
1363 if (fstat(region_fd, &buf) == -1) {
1364 perror("Could not stat file");
1365 exit(EXIT_FAILURE);
1366 }
1367 int region_size = buf.st_size;
1368
1369 printf("File %s is %d bytes\n", region_fname, region_size);
1370
1371 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001372 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001373 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1374 " bytes. Not injecting.\n",
1375 region_name(region_type), region.size,
1376 region.size, region_size, region_size);
1377 exit(EXIT_FAILURE);
1378 }
1379
1380 int offset = 0;
1381 if ((region_type == 1) && (region_size < region.size)) {
1382 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1383 " bytes. Padding before injecting.\n",
1384 region_name(region_type), region.size,
1385 region.size, region_size, region_size);
1386 offset = region.size - region_size;
1387 memset(image + region.base, 0xff, offset);
1388 }
1389
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001390 if (size < region.base + offset + region_size) {
1391 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1392 size, region.base + offset + region_size);
1393 exit(EXIT_FAILURE);
1394 }
1395
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001396 if (read(region_fd, image + region.base + offset, region_size)
1397 != region_size) {
1398 perror("Could not read file");
1399 exit(EXIT_FAILURE);
1400 }
1401
1402 close(region_fd);
1403
1404 printf("Adding %s as the %s section of %s\n",
1405 region_fname, region_name(region_type), filename);
1406 write_image(filename, image, size);
1407}
1408
Jacob Garber595d9262019-06-27 17:33:10 -06001409static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001410{
1411 unsigned int y = 1;
1412 if (x == 0)
1413 return 0;
1414 while (y <= x)
1415 y = y << 1;
1416
1417 return y;
1418}
1419
1420/**
1421 * Determine if two memory regions overlap.
1422 *
1423 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001424 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001425 * @return 1 if the two regions overlap
1426 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001427static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001428{
Bill XIEfa5f9942017-09-12 11:22:29 +08001429 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001430 return 0;
1431
Nico Huber844eda02019-01-05 00:06:19 +01001432 /* r1 should be either completely below or completely above r2 */
1433 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001434}
1435
Jacob Garber595d9262019-06-27 17:33:10 -06001436static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001437 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001438{
1439 FILE *romlayout;
1440 char tempstr[256];
1441 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001442 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001443 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001444 region_t current_regions[MAX_REGIONS];
1445 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001446 int new_extent = 0;
1447 char *new_image;
1448
1449 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001450 frba_t *frba = find_frba(image, size);
1451 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001452 exit(EXIT_FAILURE);
1453
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001454 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001455 current_regions[i] = get_region(frba, i);
1456 new_regions[i] = get_region(frba, i);
1457 }
1458
1459 /* read new layout */
1460 romlayout = fopen(layout_fname, "r");
1461
1462 if (!romlayout) {
1463 perror("Could not read layout file.\n");
1464 exit(EXIT_FAILURE);
1465 }
1466
1467 while (!feof(romlayout)) {
1468 char *tstr1, *tstr2;
1469
Patrick Georgi802ad522014-08-09 17:12:23 +02001470 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001471 layout_region_name))
1472 continue;
1473
1474 region_number = region_num(layout_region_name);
1475 if (region_number < 0)
1476 continue;
1477
1478 tstr1 = strtok(tempstr, ":");
1479 tstr2 = strtok(NULL, ":");
1480 if (!tstr1 || !tstr2) {
1481 fprintf(stderr, "Could not parse layout file.\n");
1482 exit(EXIT_FAILURE);
1483 }
1484 new_regions[region_number].base = strtol(tstr1,
1485 (char **)NULL, 16);
1486 new_regions[region_number].limit = strtol(tstr2,
1487 (char **)NULL, 16);
1488 new_regions[region_number].size =
1489 new_regions[region_number].limit -
1490 new_regions[region_number].base + 1;
1491
1492 if (new_regions[region_number].size < 0)
1493 new_regions[region_number].size = 0;
1494 }
1495 fclose(romlayout);
1496
1497 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001498 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001499 if (new_regions[i].size == 0)
1500 continue;
1501
1502 if (new_regions[i].size < current_regions[i].size) {
1503 printf("DANGER: Region %s is shrinking.\n",
1504 region_name(i));
1505 printf(" The region will be truncated to fit.\n");
1506 printf(" This may result in an unusable image.\n");
1507 }
1508
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001509 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001510 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001511 fprintf(stderr, "Regions would overlap.\n");
1512 exit(EXIT_FAILURE);
1513 }
1514 }
1515
1516 /* detect if the image size should grow */
1517 if (new_extent < new_regions[i].limit)
1518 new_extent = new_regions[i].limit;
1519 }
1520
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001521 /* check if the image is actually a Flash Descriptor region */
1522 if (size == new_regions[0].size) {
1523 printf("The image is a single Flash Descriptor:\n");
1524 printf(" Only the descriptor will be modified\n");
1525 new_extent = size;
1526 } else {
1527 new_extent = next_pow2(new_extent - 1);
1528 if (new_extent != size) {
1529 printf("The image has changed in size.\n");
1530 printf("The old image is %d bytes.\n", size);
1531 printf("The new image is %d bytes.\n", new_extent);
1532 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001533 }
1534
1535 /* copy regions to a new image */
1536 new_image = malloc(new_extent);
1537 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001538 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001539 int copy_size = new_regions[i].size;
1540 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001541 const region_t *current = &current_regions[i];
1542 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001543
Bill XIEfa5f9942017-09-12 11:22:29 +08001544 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001545 continue;
1546
Bill XIEfa5f9942017-09-12 11:22:29 +08001547 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001548 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001549 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001550 if (i == REGION_BIOS)
1551 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001552 }
1553
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001554 if ((i == REGION_BIOS) && (new->size < current->size)) {
1555 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001556 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001557 }
1558
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001559 if (size < current->base + offset_current + copy_size) {
1560 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1561 region_name(i));
1562 continue;
1563 };
1564
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001565 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1566 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001567 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1568 offset_current, current->limit, current->size);
1569 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1570 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001571
Bill XIEfa5f9942017-09-12 11:22:29 +08001572 memcpy(new_image + new->base + offset_new,
1573 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001574 copy_size);
1575 }
1576
1577 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001578 frba = find_frba(new_image, new_extent);
1579 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001580 exit(EXIT_FAILURE);
1581
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001582 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001583 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001584 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001585
1586 write_image(filename, new_image, new_extent);
1587 free(new_image);
1588}
1589
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001590static void print_version(void)
1591{
1592 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1593 printf("Copyright (C) 2011 Google Inc.\n\n");
1594 printf
1595 ("This program is free software: you can redistribute it and/or modify\n"
1596 "it under the terms of the GNU General Public License as published by\n"
1597 "the Free Software Foundation, version 2 of the License.\n\n"
1598 "This program is distributed in the hope that it will be useful,\n"
1599 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1600 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001601 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001602}
1603
1604static void print_usage(const char *name)
1605{
1606 printf("usage: %s [-vhdix?] <filename>\n", name);
1607 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001608 " -d | --dump: dump intel firmware descriptor\n"
1609 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1610 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1611 " -x | --extract: extract intel fd modules\n"
1612 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1613 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001614 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001615 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1616 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1617 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1618 " can only be used once per run:\n"
1619 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1620 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1621 " Dual Output Fast Read Support\n"
1622 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301623 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001624 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001625 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1626 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001627 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301628 " adl - Alder Lake\n"
1629 " aplk - Apollo Lake\n"
1630 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08001631 " lbg - Lewisburg PCH\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001632 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301633 " glk - Gemini Lake\n"
1634 " icl - Ice Lake\n"
1635 " jsl - Jasper Lake\n"
1636 " sklkbl - Sky Lake/Kaby Lake\n"
1637 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001638 " -S | --setpchstrap Write a PCH strap\n"
1639 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001640 " -v | --version: print the version\n"
1641 " -h | --help: print this help\n\n"
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001642 "<region> is one of Descriptor, BIOS, ME, GbE, Platform, res1, res2, res3\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001643 "\n");
1644}
1645
1646int main(int argc, char *argv[])
1647{
1648 int opt, option_index = 0;
1649 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001650 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001651 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Usha P412679d2020-10-15 11:25:08 +05301652 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001653 char *region_type_string = NULL, *region_fname = NULL;
1654 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001655 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001656 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001657 unsigned int value = 0;
1658 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001659 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001660 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1661
Bill XIEfa5f9942017-09-12 11:22:29 +08001662 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001663 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001664 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001665 {"extract", 0, NULL, 'x'},
1666 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001667 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001668 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001669 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001670 {"density", 1, NULL, 'D'},
1671 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001672 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001673 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001674 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301675 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001676 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001677 {"version", 0, NULL, 'v'},
1678 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001679 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001680 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001681 {"setpchstrap", 1, NULL, 'S'},
1682 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001683 {0, 0, 0, 0}
1684 };
1685
Usha P412679d2020-10-15 11:25:08 +05301686 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 -07001687 long_options, &option_index)) != EOF) {
1688 switch (opt) {
1689 case 'd':
1690 mode_dump = 1;
1691 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001692 case 'S':
1693 mode_setstrap = 1;
1694 pchstrap = strtoul(optarg, NULL, 0);
1695 break;
1696 case 'V':
1697 value = strtoul(optarg, NULL, 0);
1698 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001699 case 'f':
1700 mode_layout = 1;
1701 layout_fname = strdup(optarg);
1702 if (!layout_fname) {
1703 fprintf(stderr, "No layout file specified\n");
1704 print_usage(argv[0]);
1705 exit(EXIT_FAILURE);
1706 }
1707 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001708 case 'x':
1709 mode_extract = 1;
1710 break;
1711 case 'i':
1712 // separate type and file name
1713 region_type_string = strdup(optarg);
1714 region_fname = strchr(region_type_string, ':');
1715 if (!region_fname) {
1716 print_usage(argv[0]);
1717 exit(EXIT_FAILURE);
1718 }
1719 region_fname[0] = '\0';
1720 region_fname++;
1721 // Descriptor, BIOS, ME, GbE, Platform
1722 // valid type?
1723 if (!strcasecmp("Descriptor", region_type_string))
1724 region_type = 0;
1725 else if (!strcasecmp("BIOS", region_type_string))
1726 region_type = 1;
1727 else if (!strcasecmp("ME", region_type_string))
1728 region_type = 2;
1729 else if (!strcasecmp("GbE", region_type_string))
1730 region_type = 3;
1731 else if (!strcasecmp("Platform", region_type_string))
1732 region_type = 4;
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001733 else if (!strcasecmp("res1", region_type_string))
1734 region_type = 5;
1735 else if (!strcasecmp("res2", region_type_string))
1736 region_type = 6;
1737 else if (!strcasecmp("res3", region_type_string))
1738 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001739 else if (!strcasecmp("EC", region_type_string))
1740 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001741 if (region_type == -1) {
1742 fprintf(stderr, "No such region type: '%s'\n\n",
1743 region_type_string);
1744 print_usage(argv[0]);
1745 exit(EXIT_FAILURE);
1746 }
1747 mode_inject = 1;
1748 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001749 case 'n':
1750 mode_newlayout = 1;
1751 layout_fname = strdup(optarg);
1752 if (!layout_fname) {
1753 fprintf(stderr, "No layout file specified\n");
1754 print_usage(argv[0]);
1755 exit(EXIT_FAILURE);
1756 }
1757 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001758 case 'O':
1759 new_filename = strdup(optarg);
1760 if (!new_filename) {
1761 fprintf(stderr, "No output filename specified\n");
1762 print_usage(argv[0]);
1763 exit(EXIT_FAILURE);
1764 }
1765 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001766 case 'D':
1767 mode_density = 1;
1768 new_density = strtoul(optarg, NULL, 0);
1769 switch (new_density) {
1770 case 512:
1771 new_density = COMPONENT_DENSITY_512KB;
1772 break;
1773 case 1:
1774 new_density = COMPONENT_DENSITY_1MB;
1775 break;
1776 case 2:
1777 new_density = COMPONENT_DENSITY_2MB;
1778 break;
1779 case 4:
1780 new_density = COMPONENT_DENSITY_4MB;
1781 break;
1782 case 8:
1783 new_density = COMPONENT_DENSITY_8MB;
1784 break;
1785 case 16:
1786 new_density = COMPONENT_DENSITY_16MB;
1787 break;
1788 case 32:
1789 new_density = COMPONENT_DENSITY_32MB;
1790 break;
1791 case 64:
1792 new_density = COMPONENT_DENSITY_64MB;
1793 break;
1794 case 0:
1795 new_density = COMPONENT_DENSITY_UNUSED;
1796 break;
1797 default:
1798 printf("error: Unknown density\n");
1799 print_usage(argv[0]);
1800 exit(EXIT_FAILURE);
1801 }
1802 break;
1803 case 'C':
1804 selected_chip = strtol(optarg, NULL, 0);
1805 if (selected_chip > 2) {
1806 fprintf(stderr, "error: Invalid chip selection\n");
1807 print_usage(argv[0]);
1808 exit(EXIT_FAILURE);
1809 }
1810 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001811 case 'M':
1812 mode_altmedisable = 1;
1813 altmedisable = strtol(optarg, NULL, 0);
1814 if (altmedisable > 1) {
1815 fprintf(stderr, "error: Illegal value\n");
1816 print_usage(argv[0]);
1817 exit(EXIT_FAILURE);
1818 }
1819 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001820 case 's':
1821 // Parse the requested SPI frequency
1822 inputfreq = strtol(optarg, NULL, 0);
1823 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001824 case 17:
1825 spifreq = SPI_FREQUENCY_17MHZ;
1826 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001827 case 20:
1828 spifreq = SPI_FREQUENCY_20MHZ;
1829 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001830 case 30:
1831 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1832 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001833 case 33:
1834 spifreq = SPI_FREQUENCY_33MHZ;
1835 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001836 case 48:
1837 spifreq = SPI_FREQUENCY_48MHZ;
1838 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001839 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001840 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001841 break;
1842 default:
1843 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1844 inputfreq);
1845 print_usage(argv[0]);
1846 exit(EXIT_FAILURE);
1847 }
1848 mode_spifreq = 1;
1849 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001850 case 'e':
1851 mode_em100 = 1;
1852 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001853 case 'l':
1854 mode_locked = 1;
1855 if (mode_unlocked == 1) {
1856 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1857 exit(EXIT_FAILURE);
1858 }
1859 break;
Usha P412679d2020-10-15 11:25:08 +05301860 case 'r':
1861 mode_read = 1;
1862 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001863 case 'u':
1864 mode_unlocked = 1;
1865 if (mode_locked == 1) {
1866 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1867 exit(EXIT_FAILURE);
1868 }
1869 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001870 case 'p':
1871 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001872 platform = PLATFORM_APL;
1873 } else if (!strcmp(optarg, "cnl")) {
1874 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08001875 } else if (!strcmp(optarg, "lbg")) {
1876 platform = PLATFORM_LBG;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001877 } else if (!strcmp(optarg, "ehl")) {
1878 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001879 } else if (!strcmp(optarg, "glk")) {
1880 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301881 } else if (!strcmp(optarg, "icl")) {
1882 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301883 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001884 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001885 } else if (!strcmp(optarg, "sklkbl")) {
1886 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001887 } else if (!strcmp(optarg, "tgl")) {
1888 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301889 } else if (!strcmp(optarg, "adl")) {
1890 platform = PLATFORM_ADL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001891 } else {
1892 fprintf(stderr, "Unknown platform: %s\n", optarg);
1893 exit(EXIT_FAILURE);
1894 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001895 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001896 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001897 case 't':
1898 mode_validate = 1;
1899 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001900 case 'v':
1901 print_version();
1902 exit(EXIT_SUCCESS);
1903 break;
1904 case 'h':
1905 case '?':
1906 default:
1907 print_usage(argv[0]);
1908 exit(EXIT_SUCCESS);
1909 break;
1910 }
1911 }
1912
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001913 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001914 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001915 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001916 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001917 print_usage(argv[0]);
1918 exit(EXIT_FAILURE);
1919 }
1920
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001921 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001922 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001923 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001924 fprintf(stderr, "You need to specify a mode.\n\n");
1925 print_usage(argv[0]);
1926 exit(EXIT_FAILURE);
1927 }
1928
1929 if (optind + 1 != argc) {
1930 fprintf(stderr, "You need to specify a file.\n\n");
1931 print_usage(argv[0]);
1932 exit(EXIT_FAILURE);
1933 }
1934
1935 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001936 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001937 if (bios_fd == -1) {
1938 perror("Could not open file");
1939 exit(EXIT_FAILURE);
1940 }
1941 struct stat buf;
1942 if (fstat(bios_fd, &buf) == -1) {
1943 perror("Could not stat file");
1944 exit(EXIT_FAILURE);
1945 }
1946 int size = buf.st_size;
1947
1948 printf("File %s is %d bytes\n", filename, size);
1949
1950 char *image = malloc(size);
1951 if (!image) {
1952 printf("Out of memory.\n");
1953 exit(EXIT_FAILURE);
1954 }
1955
1956 if (read(bios_fd, image, size) != size) {
1957 perror("Could not read file");
1958 exit(EXIT_FAILURE);
1959 }
1960
1961 close(bios_fd);
1962
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001963 // generate new filename
1964 if (new_filename == NULL) {
1965 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1966 if (!new_filename) {
1967 printf("Out of memory.\n");
1968 exit(EXIT_FAILURE);
1969 }
1970 // - 5: leave room for ".new\0"
1971 strcpy(new_filename, filename);
1972 strcat(new_filename, ".new");
1973 }
1974
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001975 check_ifd_version(image, size);
1976
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001977 if (mode_dump)
1978 dump_fd(image, size);
1979
Chris Douglass03ce0142014-02-26 13:30:13 -05001980 if (mode_layout)
1981 dump_layout(image, size, layout_fname);
1982
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001983 if (mode_extract)
1984 write_regions(image, size);
1985
Mathew Kingc7ddc992019-08-08 14:59:25 -06001986 if (mode_validate)
1987 validate_layout(image, size);
1988
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001989 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001990 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001991 region_fname);
1992
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001993 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001994 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001995
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001996 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001997 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001998
Jan Tatjefa317512016-03-11 00:52:07 +01001999 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002000 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002001
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002002 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002003 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002004
Alexander Couzensd12ea112016-09-10 13:33:05 +02002005 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002006 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002007
Usha P412679d2020-10-15 11:25:08 +05302008 if (mode_read)
2009 enable_cpu_read_me(new_filename, image, size);
2010
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002011 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002012 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002013
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002014 if (mode_setstrap) {
2015 fpsba_t *fpsba = find_fpsba(image, size);
2016 const fdbar_t *fdb = find_fd(image, size);
2017 set_pchstrap(fpsba, fdb, pchstrap, value);
2018 write_image(new_filename, image, size);
2019 }
2020
Bill XIEb3e15a22017-09-07 18:34:50 +08002021 if (mode_altmedisable) {
2022 fpsba_t *fpsba = find_fpsba(image, size);
2023 fmsba_t *fmsba = find_fmsba(image, size);
2024 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002025 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002026 }
2027
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002028 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002029 free(image);
2030
2031 return 0;
2032}