blob: 65ac655fe747c7b83b2f6de4be19387196f1c414 [file] [log] [blame]
Patrick Georgiea063cb2020-05-08 19:28:13 +02001/* ifdtool - dump Intel Firmware Descriptor information */
Patrick Georgi7333a112020-05-08 20:48:04 +02002/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07003
4#include <unistd.h>
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8#include <getopt.h>
9#include <fcntl.h>
10#include <sys/types.h>
11#include <sys/stat.h>
Bill XIE4651d452017-09-12 11:54:48 +080012#include <commonlib/helpers.h>
Mathew Kingc7ddc992019-08-08 14:59:25 -060013#include <fmap.h>
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070014#include "ifdtool.h"
15
Scott Duplichanf2c98372014-12-12 21:03:06 -060016#ifndef O_BINARY
17#define O_BINARY 0
18#endif
19
Bill XIE612ec0e2017-08-30 16:10:27 +080020/**
21 * PTR_IN_RANGE - examine whether a pointer falls in [base, base + limit)
22 * @param ptr: the non-void* pointer to a single arbitrary-sized object.
23 * @param base: base address represented with char* type.
24 * @param limit: upper limit of the legal address.
25 *
26 */
27#define PTR_IN_RANGE(ptr, base, limit) \
28 ((const char *)(ptr) >= (base) && \
29 (const char *)&(ptr)[1] <= (base) + (limit))
30
Duncan Laurie1f7fd722015-06-22 11:14:48 -070031static int ifd_version;
Bill XIEb3e15a22017-09-07 18:34:50 +080032static int chipset;
Bill XIEfa5f9942017-09-12 11:22:29 +080033static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010034static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070035static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050036
Duncan Laurie1f7fd722015-06-22 11:14:48 -070037static const struct region_name region_names[MAX_REGIONS] = {
Mathew Kingc7ddc992019-08-08 14:59:25 -060038 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin", "SI_DESC" },
39 { "BIOS", "bios", "flashregion_1_bios.bin", "SI_BIOS" },
40 { "Intel ME", "me", "flashregion_2_intel_me.bin", "SI_ME" },
41 { "GbE", "gbe", "flashregion_3_gbe.bin", "SI_GBE" },
42 { "Platform Data", "pd", "flashregion_4_platform_data.bin", "SI_PDR" },
43 { "Reserved", "res1", "flashregion_5_reserved.bin", NULL },
44 { "Reserved", "res2", "flashregion_6_reserved.bin", NULL },
45 { "Reserved", "res3", "flashregion_7_reserved.bin", NULL },
46 { "EC", "ec", "flashregion_8_ec.bin", "SI_EC" },
Chris Douglass03ce0142014-02-26 13:30:13 -050047};
48
Bill XIEb3e15a22017-09-07 18:34:50 +080049/* port from flashrom */
50static const char *const ich_chipset_names[] = {
51 "Unknown ICH",
52 "ICH",
53 "ICH2345",
54 "ICH6",
55 "SCH U",
56 "Atom E6xx",
57 "Atom S1220 S1240 S1260",
58 "ICH7",
59 "ICH8",
60 "ICH9",
61 "ICH10",
Subrata Banik89db2252020-08-26 14:49:17 +053062 "Unknown PCH",
Bill XIEb3e15a22017-09-07 18:34:50 +080063 "5 series Ibex Peak",
64 "6 series Cougar Point",
65 "7 series Panther Point",
66 "8 series Lynx Point",
67 "Baytrail",
68 "8 series Lynx Point LP",
69 "8 series Wellsburg",
70 "9 series Wildcat Point",
71 "9 series Wildcat Point LP",
Subrata Banik8c082e52021-06-10 23:02:29 +053072 "Apollo Lake: N3xxx, J3xxx",
Subrata Banik89db2252020-08-26 14:49:17 +053073 "Gemini Lake: N5xxx, J5xxx, N4xxx, J4xxx",
Subrata Banik8c082e52021-06-10 23:02:29 +053074 "Jasper Lake: N6xxx, N51xx, N45xx",
75 "Elkhart Lake: x6000 series Atom",
Subrata Banik89db2252020-08-26 14:49:17 +053076 "100/200 series Sunrise Point",
Subrata Banik8c082e52021-06-10 23:02:29 +053077 "300 series Cannon Point",
78 "400 series Ice Point",
Subrata Banika5f47812020-09-29 11:43:01 +053079 "500 series Tiger Point/ 600 series Alder Point",
Bill XIEb3e15a22017-09-07 18:34:50 +080080 "C620 series Lewisburg",
81 NULL
82};
83
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070084static fdbar_t *find_fd(char *image, int size)
85{
86 int i, found = 0;
87
88 /* Scan for FD signature */
89 for (i = 0; i < (size - 4); i += 4) {
90 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
91 found = 1;
92 break; // signature found.
93 }
94 }
95
96 if (!found) {
97 printf("No Flash Descriptor found in this image\n");
98 return NULL;
99 }
100
Bill XIE612ec0e2017-08-30 16:10:27 +0800101 fdbar_t *fdb = (fdbar_t *) (image + i);
102 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
103}
104
Stefan Tauner0d226142018-08-05 18:56:53 +0200105static char *find_flumap(char *image, int size)
106{
107 /* The upper map is located in the word before the 256B-long OEM section
108 * at the end of the 4kB-long flash descriptor. In the official
109 * documentation this is defined as FDBAR + 0xEFC. However, starting
110 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
111 * has moved 16 bytes back to offset 0x10 of the image. Although
112 * official documentation still maintains the offset relative to FDBAR
113 * this is wrong and a simple fixed offset from the start of the image
114 * works.
115 */
116 char *flumap = image + 4096 - 256 - 4;
117 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
118}
119
Bill XIE612ec0e2017-08-30 16:10:27 +0800120static fcba_t *find_fcba(char *image, int size)
121{
122 fdbar_t *fdb = find_fd(image, size);
123 if (!fdb)
124 return NULL;
125 fcba_t *fcba = (fcba_t *) (image + ((fdb->flmap0 & 0xff) << 4));
126 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
127
128}
129
130static fmba_t *find_fmba(char *image, int size)
131{
132 fdbar_t *fdb = find_fd(image, size);
133 if (!fdb)
134 return NULL;
135 fmba_t *fmba = (fmba_t *) (image + ((fdb->flmap1 & 0xff) << 4));
136 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
137}
138
139static frba_t *find_frba(char *image, int size)
140{
141 fdbar_t *fdb = find_fd(image, size);
142 if (!fdb)
143 return NULL;
144 frba_t *frba =
145 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
146 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
147}
148
149static fpsba_t *find_fpsba(char *image, int size)
150{
151 fdbar_t *fdb = find_fd(image, size);
152 if (!fdb)
153 return NULL;
154 fpsba_t *fpsba =
155 (fpsba_t *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200156
157 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
158 if ((((char *)fpsba) + SSL) >= (image + size))
159 return NULL;
160 return fpsba;
Bill XIE612ec0e2017-08-30 16:10:27 +0800161}
162
163static fmsba_t *find_fmsba(char *image, int size)
164{
165 fdbar_t *fdb = find_fd(image, size);
166 if (!fdb)
167 return NULL;
168 fmsba_t *fmsba = (fmsba_t *) (image + ((fdb->flmap2 & 0xff) << 4));
169 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700170}
171
Bill XIEb3e15a22017-09-07 18:34:50 +0800172/* port from flashrom */
Subrata Banik8c082e52021-06-10 23:02:29 +0530173static enum ich_chipset ifd1_guess_chipset(char *image, int size)
Bill XIEb3e15a22017-09-07 18:34:50 +0800174{
Subrata Banik8c082e52021-06-10 23:02:29 +0530175 const fdbar_t *fdb = find_fd(image, size);
176 if (!fdb)
177 exit(EXIT_FAILURE);
Bill XIEb3e15a22017-09-07 18:34:50 +0800178 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
179 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
180 uint32_t isl = (fdb->flmap1 >> 24);
181 uint32_t nm = (fdb->flmap1 >> 8) & 0x7;
Subrata Banik89db2252020-08-26 14:49:17 +0530182
183 /* Rest for IFD1 chipset type */
Bill XIEb3e15a22017-09-07 18:34:50 +0800184 if (iccriba == 0x00) {
185 if (msl == 0 && isl <= 2)
186 return CHIPSET_ICH8;
187 else if (isl <= 2)
188 return CHIPSET_ICH9;
189 else if (isl <= 10)
190 return CHIPSET_ICH10;
191 else if (isl <= 16)
192 return CHIPSET_5_SERIES_IBEX_PEAK;
193 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
194 return CHIPSET_5_SERIES_IBEX_PEAK;
195 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
196 if (msl == 0 && isl <= 17)
197 return CHIPSET_BAYTRAIL;
198 else if (msl <= 1 && isl <= 18)
199 return CHIPSET_6_SERIES_COUGAR_POINT;
200 else if (msl <= 1 && isl <= 21)
201 return CHIPSET_8_SERIES_LYNX_POINT;
202 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
203 return CHIPSET_9_SERIES_WILDCAT_POINT;
204 } else if (nm == 6) {
205 return CHIPSET_C620_SERIES_LEWISBURG;
206 } else {
Subrata Banik89db2252020-08-26 14:49:17 +0530207 return CHIPSET_100_200_SERIES_SUNRISE_POINT;
Bill XIEb3e15a22017-09-07 18:34:50 +0800208 }
209}
210
Subrata Banik8c082e52021-06-10 23:02:29 +0530211static enum ich_chipset ifd2_platform_to_chipset(const int pindex)
212{
213 switch (pindex) {
214 case PLATFORM_GLK:
215 return CHIPSET_N_J_SERIES_GEMINI_LAKE;
216 case PLATFORM_JSL:
217 return CHIPSET_N_SERIES_JASPER_LAKE;
218 case PLATFORM_EHL:
219 return CHIPSET_x6000_SERIES_ELKHART_LAKE;
220 case PLATFORM_CNL:
221 return CHIPSET_300_SERIES_CANNON_POINT;
222 case PLATFORM_TGL:
223 case PLATFORM_ADL:
224 return CHIPSET_500_600_SERIES_TIGER_ALDER_POINT;
225 case PLATFORM_ICL:
226 return CHIPSET_400_SERIES_ICE_POINT;
227 default:
228 return CHIPSET_PCH_UNKNOWN;
229 }
230}
231
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700232/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700233 * Some newer platforms have re-defined the FCBA field that was used to
234 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
235 * have the required FCBA field, but are IFD v2 and return true if current
236 * platform is one of them.
237 */
238static int is_platform_ifd_2(void)
239{
240 static const int ifd_2_platforms[] = {
241 PLATFORM_GLK,
242 PLATFORM_CNL,
Aamir Bohra1018be22018-06-29 15:08:50 +0530243 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700244 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530245 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700246 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530247 PLATFORM_ADL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700248 };
249 unsigned int i;
250
251 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
252 if (platform == ifd_2_platforms[i])
253 return 1;
254 }
255
256 return 0;
257}
258
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700259static void check_ifd_version(char *image, int size)
260{
Subrata Banik8c082e52021-06-10 23:02:29 +0530261 if (is_platform_ifd_2()) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700262 ifd_version = IFD_VERSION_2;
Subrata Banik8c082e52021-06-10 23:02:29 +0530263 chipset = ifd2_platform_to_chipset(platform);
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700264 max_regions = MAX_REGIONS;
Subrata Banik8c082e52021-06-10 23:02:29 +0530265 } else {
266 ifd_version = IFD_VERSION_1;
267 chipset = ifd1_guess_chipset(image, size);
268 max_regions = MAX_REGIONS_OLD;
269 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700270}
271
Bill XIEfa5f9942017-09-12 11:22:29 +0800272static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700273{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500274 int base_mask;
275 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700276 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700277 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500278
279 if (ifd_version >= IFD_VERSION_2)
280 base_mask = 0x7fff;
281 else
282 base_mask = 0xfff;
283
284 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700285
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400286 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800287 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700288 exit (EXIT_FAILURE);
289 }
290
Bill XIE4651d452017-09-12 11:54:48 +0800291 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700292 region.base = (flreg & base_mask) << 12;
293 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700294 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500295
Chris Douglass03ce0142014-02-26 13:30:13 -0500296 if (region.size < 0)
297 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700298
299 return region;
300}
301
Bill XIEfa5f9942017-09-12 11:22:29 +0800302static void set_region(frba_t *frba, unsigned int region_type,
303 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500304{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400305 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800306 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500307 exit (EXIT_FAILURE);
308 }
Bill XIE4651d452017-09-12 11:54:48 +0800309
310 frba->flreg[region_type] =
311 (((region->limit >> 12) & 0x7fff) << 16) |
312 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500313}
314
Bill XIEfa5f9942017-09-12 11:22:29 +0800315static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700316{
Bill XIEfa5f9942017-09-12 11:22:29 +0800317 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700318 fprintf(stderr, "Invalid region type.\n");
319 exit (EXIT_FAILURE);
320 }
321
Chris Douglass03ce0142014-02-26 13:30:13 -0500322 return region_names[region_type].pretty;
323}
324
Bill XIEfa5f9942017-09-12 11:22:29 +0800325static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500326{
Bill XIEfa5f9942017-09-12 11:22:29 +0800327 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500328 fprintf(stderr, "Invalid region type.\n");
329 exit (EXIT_FAILURE);
330 }
331
332 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700333}
334
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500335static int region_num(const char *name)
336{
Bill XIEfa5f9942017-09-12 11:22:29 +0800337 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500338
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200339 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500340 if (strcasecmp(name, region_names[i].pretty) == 0)
341 return i;
342 if (strcasecmp(name, region_names[i].terse) == 0)
343 return i;
344 }
345
346 return -1;
347}
348
Bill XIEfa5f9942017-09-12 11:22:29 +0800349static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700350{
Bill XIEfa5f9942017-09-12 11:22:29 +0800351 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700352 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700353 exit (EXIT_FAILURE);
354 }
355
Bill XIE1bf65062017-09-12 11:31:37 +0800356 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700357}
358
Bill XIEfa5f9942017-09-12 11:22:29 +0800359static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700360{
361 region_t region = get_region(frba, num);
362 printf(" Flash Region %d (%s): %08x - %08x %s\n",
363 num, region_name(num), region.base, region.limit,
364 region.size < 1 ? "(unused)" : "");
365}
366
Bill XIEfa5f9942017-09-12 11:22:29 +0800367static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
368 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500369{
370 region_t region = get_region(frba, num);
371 snprintf(buf, bufsize, "%08x:%08x %s\n",
372 region.base, region.limit, region_name_short(num));
373}
374
Bill XIEfa5f9942017-09-12 11:22:29 +0800375static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700376{
Bill XIE4651d452017-09-12 11:54:48 +0800377 unsigned int i;
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530378 region_t region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700379 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800380 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530381 region = get_region(frba, i);
382 /* Skip unused & reserved Flash Region */
383 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
384 continue;
385
Bill XIE4651d452017-09-12 11:54:48 +0800386 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
387 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700388 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700389}
390
Bill XIEfa5f9942017-09-12 11:22:29 +0800391static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500392{
393 char buf[LAYOUT_LINELEN];
394 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800395 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500396
397 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
398 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
399 if (layout_fd == -1) {
400 perror("Could not open file");
401 exit(EXIT_FAILURE);
402 }
403
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200404 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200405 region_t region = get_region(frba, i);
406 /* is region invalid? */
407 if (region.size < 1)
408 continue;
409
Chris Douglass03ce0142014-02-26 13:30:13 -0500410 dump_region_layout(buf, bufsize, i, frba);
411 if (write(layout_fd, buf, strlen(buf)) < 0) {
412 perror("Could not write to file");
413 exit(EXIT_FAILURE);
414 }
415 }
416 close(layout_fd);
417 printf("Wrote layout to %s\n", layout_fname);
418}
419
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530420static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700421{
422 switch (freq) {
423 case SPI_FREQUENCY_20MHZ:
424 printf("20MHz");
425 break;
426 case SPI_FREQUENCY_33MHZ:
427 printf("33MHz");
428 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700429 case SPI_FREQUENCY_48MHZ:
430 printf("48MHz");
431 break;
432 case SPI_FREQUENCY_50MHZ_30MHZ:
433 switch (ifd_version) {
434 case IFD_VERSION_1:
435 printf("50MHz");
436 break;
437 case IFD_VERSION_2:
438 printf("30MHz");
439 break;
440 }
441 break;
442 case SPI_FREQUENCY_17MHZ:
443 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700444 break;
445 default:
446 printf("unknown<%x>MHz", freq);
447 }
448}
449
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530450static void _decode_spi_frequency_500_series(unsigned int freq)
451{
452 switch (freq) {
453 case SPI_FREQUENCY_100MHZ:
454 printf("100MHz");
455 break;
456 case SPI_FREQUENCY_50MHZ:
457 printf("50MHz");
458 break;
459 case SPI_FREQUENCY_500SERIES_33MHZ:
460 printf("33MHz");
461 break;
462 case SPI_FREQUENCY_25MHZ:
463 printf("25MHz");
464 break;
465 case SPI_FREQUENCY_14MHZ:
466 printf("14MHz");
467 break;
468 default:
469 printf("unknown<%x>MHz", freq);
470 }
471}
472
473static void decode_spi_frequency(unsigned int freq)
474{
Subrata Banika5f47812020-09-29 11:43:01 +0530475 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530476 _decode_spi_frequency_500_series(freq);
477 else
478 _decode_spi_frequency(freq);
479}
480
Subrata Banike5d39922020-08-26 16:01:42 +0530481static void _decode_espi_frequency(unsigned int freq)
482{
483 switch (freq) {
484 case ESPI_FREQUENCY_20MHZ:
485 printf("20MHz");
486 break;
487 case ESPI_FREQUENCY_24MHZ:
488 printf("24MHz");
489 break;
490 case ESPI_FREQUENCY_30MHZ:
491 printf("30MHz");
492 break;
493 case ESPI_FREQUENCY_48MHZ:
494 printf("48MHz");
495 break;
496 case ESPI_FREQUENCY_60MHZ:
497 printf("60MHz");
498 break;
499 case ESPI_FREQUENCY_17MHZ:
500 printf("17MHz");
501 break;
502 default:
503 printf("unknown<%x>MHz", freq);
504 }
505}
506
507static void _decode_espi_frequency_500_series(unsigned int freq)
508{
509 switch (freq) {
510 case ESPI_FREQUENCY_500SERIES_20MHZ:
511 printf("20MHz");
512 break;
513 case ESPI_FREQUENCY_500SERIES_24MHZ:
514 printf("24MHz");
515 break;
516 case ESPI_FREQUENCY_500SERIES_25MHZ:
517 printf("25MHz");
518 break;
519 case ESPI_FREQUENCY_500SERIES_48MHZ:
520 printf("48MHz");
521 break;
522 case ESPI_FREQUENCY_500SERIES_60MHZ:
523 printf("60MHz");
524 break;
525 default:
526 printf("unknown<%x>MHz", freq);
527 }
528}
529
530static void decode_espi_frequency(unsigned int freq)
531{
Subrata Banika5f47812020-09-29 11:43:01 +0530532 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530533 _decode_espi_frequency_500_series(freq);
534 else
535 _decode_espi_frequency(freq);
536}
537
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700538static void decode_component_density(unsigned int density)
539{
540 switch (density) {
541 case COMPONENT_DENSITY_512KB:
542 printf("512KB");
543 break;
544 case COMPONENT_DENSITY_1MB:
545 printf("1MB");
546 break;
547 case COMPONENT_DENSITY_2MB:
548 printf("2MB");
549 break;
550 case COMPONENT_DENSITY_4MB:
551 printf("4MB");
552 break;
553 case COMPONENT_DENSITY_8MB:
554 printf("8MB");
555 break;
556 case COMPONENT_DENSITY_16MB:
557 printf("16MB");
558 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700559 case COMPONENT_DENSITY_32MB:
560 printf("32MB");
561 break;
562 case COMPONENT_DENSITY_64MB:
563 printf("64MB");
564 break;
565 case COMPONENT_DENSITY_UNUSED:
566 printf("UNUSED");
567 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700568 default:
569 printf("unknown<%x>MB", density);
570 }
571}
572
Subrata Banik26058dc2020-08-26 15:12:16 +0530573static int is_platform_with_pch(void)
574{
575 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
576 return 1;
577
578 return 0;
579}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530580
581/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
582static int is_platform_with_100x_series_pch(void)
583{
584 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530585 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530586 return 1;
587
588 return 0;
589}
590
Subrata Banike5d39922020-08-26 16:01:42 +0530591static void dump_fcba(const fcba_t *fcba, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700592{
Subrata Banike5d39922020-08-26 16:01:42 +0530593 unsigned int freq;
594
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700595 printf("\nFound Component Section\n");
596 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700597 printf(" Dual Output Fast Read Support: %ssupported\n",
598 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700599 printf(" Read ID/Read Status Clock Frequency: ");
600 decode_spi_frequency((fcba->flcomp >> 27) & 7);
601 printf("\n Write/Erase Clock Frequency: ");
602 decode_spi_frequency((fcba->flcomp >> 24) & 7);
603 printf("\n Fast Read Clock Frequency: ");
604 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700605 printf("\n Fast Read Support: %ssupported",
606 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530607 if (is_platform_with_100x_series_pch() &&
608 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
609 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530610 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530611 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
612 else
613 freq = (fcba->flcomp >> 17) & 7;
614 decode_espi_frequency(freq);
615 } else {
616 printf("\n Read Clock Frequency: ");
617 decode_spi_frequency((fcba->flcomp >> 17) & 7);
618 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700619
620 switch (ifd_version) {
621 case IFD_VERSION_1:
622 printf("\n Component 2 Density: ");
623 decode_component_density((fcba->flcomp >> 3) & 7);
624 printf("\n Component 1 Density: ");
625 decode_component_density(fcba->flcomp & 7);
626 break;
627 case IFD_VERSION_2:
628 printf("\n Component 2 Density: ");
629 decode_component_density((fcba->flcomp >> 4) & 0xf);
630 printf("\n Component 1 Density: ");
631 decode_component_density(fcba->flcomp & 0xf);
632 break;
633 }
634
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700635 printf("\n");
636 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700637 printf(" Invalid Instruction 3: 0x%02x\n",
638 (fcba->flill >> 24) & 0xff);
639 printf(" Invalid Instruction 2: 0x%02x\n",
640 (fcba->flill >> 16) & 0xff);
641 printf(" Invalid Instruction 1: 0x%02x\n",
642 (fcba->flill >> 8) & 0xff);
643 printf(" Invalid Instruction 0: 0x%02x\n",
644 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530645 if (is_platform_with_100x_series_pch()) {
646 printf("FLILL1 0x%08x\n", fcba->flpb);
647 printf(" Invalid Instruction 7: 0x%02x\n",
648 (fcba->flpb >> 24) & 0xff);
649 printf(" Invalid Instruction 6: 0x%02x\n",
650 (fcba->flpb >> 16) & 0xff);
651 printf(" Invalid Instruction 5: 0x%02x\n",
652 (fcba->flpb >> 8) & 0xff);
653 printf(" Invalid Instruction 4: 0x%02x\n",
654 fcba->flpb & 0xff);
655 } else {
656 printf("FLPB 0x%08x\n", fcba->flpb);
657 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
658 (fcba->flpb & 0xfff) << 12);
659 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700660}
661
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200662static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700663{
Bill XIE4651d452017-09-12 11:54:48 +0800664 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200665 /* SoC Strap Length, aka PSL, aka ISL */
666 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
667
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700668 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200669 for (i = 0; i < SSL; i++)
670 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800671
672 if (ifd_version >= IFD_VERSION_2) {
673 printf("HAP bit is %sset\n",
674 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
675 } else if (chipset >= CHIPSET_ICH8
676 && chipset <= CHIPSET_ICH10) {
677 printf("ICH_MeDisable bit is %sset\n",
678 fpsba->pchstrp[0] & 1 ? "" : "not ");
679 } else {
680 printf("AltMeDisable bit is %sset\n",
681 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
682 }
683
Bill XIE4651d452017-09-12 11:54:48 +0800684 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700685}
686
687static void decode_flmstr(uint32_t flmstr)
688{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700689 int wr_shift, rd_shift;
690 if (ifd_version >= IFD_VERSION_2) {
691 wr_shift = FLMSTR_WR_SHIFT_V2;
692 rd_shift = FLMSTR_RD_SHIFT_V2;
693 } else {
694 wr_shift = FLMSTR_WR_SHIFT_V1;
695 rd_shift = FLMSTR_RD_SHIFT_V1;
696 }
697
698 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700699 if (ifd_version >= IFD_VERSION_2)
700 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700701 (flmstr & (1 << (wr_shift + 8))) ?
702 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700703 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700704 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700705 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700706 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700707 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700708 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700709 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700710 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700711 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700712 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700713
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700714 if (ifd_version >= IFD_VERSION_2)
715 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700716 (flmstr & (1 << (rd_shift + 8))) ?
717 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700718 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700719 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700720 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700721 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700722 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700723 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700724 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700725 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700726 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700727 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700728
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700729 /* Requestor ID doesn't exist for ifd 2 */
730 if (ifd_version < IFD_VERSION_2)
731 printf(" Requester ID: 0x%04x\n\n",
732 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700733}
734
Bill XIEfa5f9942017-09-12 11:22:29 +0800735static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700736{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700737 printf("Found Master Section\n");
738 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
739 decode_flmstr(fmba->flmstr1);
740 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
741 decode_flmstr(fmba->flmstr2);
742 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
743 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700744 if (ifd_version >= IFD_VERSION_2) {
745 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
746 decode_flmstr(fmba->flmstr5);
747 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700748}
749
Bill XIEfa5f9942017-09-12 11:22:29 +0800750static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700751{
Bill XIE612ec0e2017-08-30 16:10:27 +0800752 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700753 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800754 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
755 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800756
757 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
758 printf("MCH_MeDisable bit is %sset\n",
759 fmsba->data[0] & 1 ? "" : "not ");
760 printf("MCH_AltMeDisable bit is %sset\n",
761 fmsba->data[0] & (1 << 7) ? "" : "not ");
762 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700763}
764
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700765static void dump_jid(uint32_t jid)
766{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100767 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700768 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100769 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200770 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100771 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200772 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700773}
774
775static void dump_vscc(uint32_t vscc)
776{
777 printf(" Lower Erase Opcode: 0x%02x\n",
778 vscc >> 24);
779 printf(" Lower Write Enable on Write Status: 0x%02x\n",
780 vscc & (1 << 20) ? 0x06 : 0x50);
781 printf(" Lower Write Status Required: %s\n",
782 vscc & (1 << 19) ? "Yes" : "No");
783 printf(" Lower Write Granularity: %d bytes\n",
784 vscc & (1 << 18) ? 64 : 1);
785 printf(" Lower Block / Sector Erase Size: ");
786 switch ((vscc >> 16) & 0x3) {
787 case 0:
788 printf("256 Byte\n");
789 break;
790 case 1:
791 printf("4KB\n");
792 break;
793 case 2:
794 printf("8KB\n");
795 break;
796 case 3:
797 printf("64KB\n");
798 break;
799 }
800
801 printf(" Upper Erase Opcode: 0x%02x\n",
802 (vscc >> 8) & 0xff);
803 printf(" Upper Write Enable on Write Status: 0x%02x\n",
804 vscc & (1 << 4) ? 0x06 : 0x50);
805 printf(" Upper Write Status Required: %s\n",
806 vscc & (1 << 3) ? "Yes" : "No");
807 printf(" Upper Write Granularity: %d bytes\n",
808 vscc & (1 << 2) ? 64 : 1);
809 printf(" Upper Block / Sector Erase Size: ");
810 switch (vscc & 0x3) {
811 case 0:
812 printf("256 Byte\n");
813 break;
814 case 1:
815 printf("4KB\n");
816 break;
817 case 2:
818 printf("8KB\n");
819 break;
820 case 3:
821 printf("64KB\n");
822 break;
823 }
824}
825
Bill XIEfa5f9942017-09-12 11:22:29 +0800826static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700827{
828 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200829 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
830 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700831
832 printf("ME VSCC table:\n");
833 for (i = 0; i < num; i++) {
834 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
835 dump_jid(vtba->entry[i].jid);
836 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
837 dump_vscc(vtba->entry[i].vscc);
838 }
839 printf("\n");
840}
841
Bill XIEfa5f9942017-09-12 11:22:29 +0800842static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700843{
844 int i, j;
845 printf("OEM Section:\n");
846 for (i = 0; i < 4; i++) {
847 printf("%02x:", i << 4);
848 for (j = 0; j < 16; j++)
849 printf(" %02x", oem[(i<<4)+j]);
850 printf ("\n");
851 }
852 printf ("\n");
853}
854
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700855static void dump_fd(char *image, int size)
856{
Bill XIE612ec0e2017-08-30 16:10:27 +0800857 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700858 if (!fdb)
859 exit(EXIT_FAILURE);
860
Subrata Banik26058dc2020-08-26 15:12:16 +0530861 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
862 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700863 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530864 if (!is_platform_with_100x_series_pch())
865 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700866 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
867 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
868 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
869
870 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530871 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
872 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700873 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
874 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
875 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
876
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530877 if (!is_platform_with_100x_series_pch()) {
878 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
879 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
880 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
881 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700882
Subrata Banika5f47812020-09-29 11:43:01 +0530883 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530884 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
885 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
886 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
887 }
888
Stefan Tauner0d226142018-08-05 18:56:53 +0200889 char *flumap = find_flumap(image, size);
890 uint32_t flumap1 = *(uint32_t *)flumap;
891 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700892 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200893 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700894 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200895 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700896 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200897 (image + ((flumap1 & 0xff) << 4)),
898 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800899 dump_oem((const uint8_t *)image + 0xf00);
900
901 const frba_t *frba = find_frba(image, size);
902 const fcba_t *fcba = find_fcba(image, size);
903 const fpsba_t *fpsba = find_fpsba(image, size);
904 const fmba_t *fmba = find_fmba(image, size);
905 const fmsba_t *fmsba = find_fmsba(image, size);
906
907 if (frba && fcba && fpsba && fmba && fmsba) {
908 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +0530909 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200910 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800911 dump_fmba(fmba);
912 dump_fmsba(fmsba);
913 } else {
914 printf("FD is corrupted!\n");
915 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700916}
917
Bill XIEfa5f9942017-09-12 11:22:29 +0800918static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500919{
Bill XIE612ec0e2017-08-30 16:10:27 +0800920 const frba_t *frba = find_frba(image, size);
921 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500922 exit(EXIT_FAILURE);
923
Bill XIE612ec0e2017-08-30 16:10:27 +0800924 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500925}
926
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700927static void write_regions(char *image, int size)
928{
Bill XIEfa5f9942017-09-12 11:22:29 +0800929 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800930 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700931
Bill XIE612ec0e2017-08-30 16:10:27 +0800932 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700933 exit(EXIT_FAILURE);
934
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700935 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700936 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700937 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700938 if (region.size > 0) {
939 int region_fd;
940 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600941 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700942 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200943 if (region_fd < 0) {
944 perror("Error while trying to open file");
945 exit(EXIT_FAILURE);
946 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700947 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700948 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700949 close(region_fd);
950 }
951 }
952}
953
Mathew Kingc7ddc992019-08-08 14:59:25 -0600954static void validate_layout(char *image, int size)
955{
956 uint i, errors = 0;
957 struct fmap *fmap;
958 long int fmap_loc = fmap_find((uint8_t *)image, size);
959 const frba_t *frba = find_frba(image, size);
960
961 if (fmap_loc < 0 || !frba)
962 exit(EXIT_FAILURE);
963
964 fmap = (struct fmap *)(image + fmap_loc);
965
966 for (i = 0; i < max_regions; i++) {
967 if (region_names[i].fmapname == NULL)
968 continue;
969
970 region_t region = get_region(frba, i);
971
972 if (region.size == 0)
973 continue;
974
975 const struct fmap_area *area =
976 fmap_find_area(fmap, region_names[i].fmapname);
977
978 if (!area)
979 continue;
980
981 if ((uint)region.base != area->offset ||
982 (uint)region.size != area->size) {
983 printf("Region mismatch between %s and %s\n",
984 region_names[i].terse, area->name);
985 printf(" Descriptor region %s:\n", region_names[i].terse);
986 printf(" offset: 0x%08x\n", region.base);
987 printf(" length: 0x%08x\n", region.size);
988 printf(" FMAP area %s:\n", area->name);
989 printf(" offset: 0x%08x\n", area->offset);
990 printf(" length: 0x%08x\n", area->size);
991 errors++;
992 }
993 }
994
995 if (errors > 0)
996 exit(EXIT_FAILURE);
997}
998
Bill XIEfa5f9942017-09-12 11:22:29 +0800999static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001000{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001001 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001002 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001003
1004 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001005 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001006 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001007 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001008 if (new_fd < 0) {
1009 perror("Error while trying to open file");
1010 exit(EXIT_FAILURE);
1011 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001012 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001013 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001014 close(new_fd);
1015}
1016
Bill XIEfa5f9942017-09-12 11:22:29 +08001017static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001018 enum spi_frequency freq)
1019{
Bill XIE612ec0e2017-08-30 16:10:27 +08001020 fcba_t *fcba = find_fcba(image, size);
1021 if (!fcba)
1022 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001023
1024 /* clear bits 21-29 */
1025 fcba->flcomp &= ~0x3fe00000;
1026 /* Read ID and Read Status Clock Frequency */
1027 fcba->flcomp |= freq << 27;
1028 /* Write and Erase Clock Frequency */
1029 fcba->flcomp |= freq << 24;
1030 /* Fast Read Clock Frequency */
1031 fcba->flcomp |= freq << 21;
1032
1033 write_image(filename, image, size);
1034}
1035
Bill XIEfa5f9942017-09-12 11:22:29 +08001036static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001037{
Bill XIE612ec0e2017-08-30 16:10:27 +08001038 fcba_t *fcba = find_fcba(image, size);
1039 if (!fcba)
1040 exit(EXIT_FAILURE);
1041
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001042 int freq;
1043
1044 switch (ifd_version) {
1045 case IFD_VERSION_1:
1046 freq = SPI_FREQUENCY_20MHZ;
1047 break;
1048 case IFD_VERSION_2:
1049 freq = SPI_FREQUENCY_17MHZ;
1050 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001051 default:
1052 freq = SPI_FREQUENCY_17MHZ;
1053 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001054 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001055
1056 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001057 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001058}
1059
Bill XIEfa5f9942017-09-12 11:22:29 +08001060static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +01001061 unsigned int density)
1062{
Bill XIE612ec0e2017-08-30 16:10:27 +08001063 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001064 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001065 if (!fcba)
1066 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001067
1068 printf("Setting chip density to ");
1069 decode_component_density(density);
1070 printf("\n");
1071
1072 switch (ifd_version) {
1073 case IFD_VERSION_1:
1074 /* fail if selected density is not supported by this version */
1075 if ( (density == COMPONENT_DENSITY_32MB) ||
1076 (density == COMPONENT_DENSITY_64MB) ||
1077 (density == COMPONENT_DENSITY_UNUSED) ) {
1078 printf("error: Selected density not supported in IFD version 1.\n");
1079 exit(EXIT_FAILURE);
1080 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001081 mask = 0x7;
1082 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001083 break;
1084 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001085 mask = 0xf;
1086 chip2_offset = 4;
1087 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001088 default:
1089 printf("error: Unknown IFD version\n");
1090 exit(EXIT_FAILURE);
1091 break;
1092 }
1093
1094 /* clear chip density for corresponding chip */
1095 switch (selected_chip) {
1096 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001097 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001098 break;
1099 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001100 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001101 break;
1102 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001103 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001104 break;
1105 }
1106
1107 /* set the new density */
1108 if (selected_chip == 1 || selected_chip == 0)
1109 fcba->flcomp |= (density); /* first chip */
1110 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001111 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001112
1113 write_image(filename, image, size);
1114}
1115
Duncan Laurie7775d672019-06-06 13:39:26 -07001116static int check_region(const frba_t *frba, unsigned int region_type)
1117{
1118 region_t region;
1119
1120 if (!frba)
1121 return 0;
1122
1123 region = get_region(frba, region_type);
1124 return !!((region.base < region.limit) && (region.size > 0));
1125}
1126
Bill XIEfa5f9942017-09-12 11:22:29 +08001127static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001128{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001129 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001130 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001131 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001132 if (!fmba)
1133 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001134
1135 if (ifd_version >= IFD_VERSION_2) {
1136 wr_shift = FLMSTR_WR_SHIFT_V2;
1137 rd_shift = FLMSTR_RD_SHIFT_V2;
1138
1139 /* Clear non-reserved bits */
1140 fmba->flmstr1 &= 0xff;
1141 fmba->flmstr2 &= 0xff;
1142 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001143 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001144 } else {
1145 wr_shift = FLMSTR_WR_SHIFT_V1;
1146 rd_shift = FLMSTR_RD_SHIFT_V1;
1147
1148 fmba->flmstr1 = 0;
1149 fmba->flmstr2 = 0;
1150 /* Requestor ID */
1151 fmba->flmstr3 = 0x118;
1152 }
1153
Andrey Petrov96ecb772016-10-31 19:31:54 -07001154 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001155 case PLATFORM_APL:
1156 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001157 /* CPU/BIOS can read descriptor and BIOS */
1158 fmba->flmstr1 |= 0x3 << rd_shift;
1159 /* CPU/BIOS can write BIOS */
1160 fmba->flmstr1 |= 0x2 << wr_shift;
1161 /* TXE can read descriptor, BIOS and Device Expansion */
1162 fmba->flmstr2 |= 0x23 << rd_shift;
1163 /* TXE can only write Device Expansion */
1164 fmba->flmstr2 |= 0x20 << wr_shift;
1165 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001166 case PLATFORM_CNL:
1167 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001168 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001169 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301170 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001171 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301172 case PLATFORM_ADL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001173 /* CPU/BIOS can read descriptor and BIOS. */
1174 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1175 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1176 /* CPU/BIOS can write BIOS. */
1177 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1178 /* ME can read descriptor and ME. */
1179 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1180 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001181 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001182 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1183 if (check_region(frba, REGION_GBE)) {
1184 /* BIOS can read/write GbE. */
1185 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1186 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1187 /* ME can read GbE. */
1188 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1189 /* GbE can read descriptor and read/write GbE.. */
1190 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1191 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1192 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1193 }
1194 if (check_region(frba, REGION_PDR)) {
1195 /* BIOS can read/write PDR. */
1196 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1197 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1198 }
1199 if (check_region(frba, REGION_EC)) {
1200 /* BIOS can read EC. */
1201 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1202 /* EC can read descriptor and read/write EC. */
1203 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1204 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1205 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1206 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001207 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001208 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001209 /* CPU/BIOS can read descriptor and BIOS. */
1210 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1211 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1212 /* CPU/BIOS can write BIOS. */
1213 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1214 /* ME can read descriptor and ME. */
1215 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1216 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1217 /* ME can write ME. */
1218 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1219 if (check_region(frba, REGION_GBE)) {
1220 /* BIOS can read GbE. */
1221 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1222 /* BIOS can write GbE. */
1223 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1224 /* ME can read GbE. */
1225 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1226 /* ME can write GbE. */
1227 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1228 /* GbE can write GbE. */
1229 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1230 /* GbE can read GbE. */
1231 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1232 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001233 break;
1234 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001235
1236 write_image(filename, image, size);
1237}
1238
Usha P412679d2020-10-15 11:25:08 +05301239static void enable_cpu_read_me(const char *filename, char *image, int size)
1240{
1241 int rd_shift;
1242 fmba_t *fmba = find_fmba(image, size);
1243
1244 if (!fmba)
1245 exit(EXIT_FAILURE);
1246
1247 if (ifd_version >= IFD_VERSION_2)
1248 rd_shift = FLMSTR_RD_SHIFT_V2;
1249 else
1250 rd_shift = FLMSTR_RD_SHIFT_V1;
1251
1252 /* CPU/BIOS can read ME. */
1253 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1254
1255 write_image(filename, image, size);
1256}
1257
Bill XIEfa5f9942017-09-12 11:22:29 +08001258static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001259{
Bill XIE612ec0e2017-08-30 16:10:27 +08001260 fmba_t *fmba = find_fmba(image, size);
1261 if (!fmba)
1262 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001263
1264 if (ifd_version >= IFD_VERSION_2) {
1265 /* Access bits for each region are read: 19:8 write: 31:20 */
1266 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1267 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1268 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001269 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001270 } else {
1271 fmba->flmstr1 = 0xffff0000;
1272 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001273 /* Keep chipset specific Requester ID */
1274 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001275 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001276
1277 write_image(filename, image, size);
1278}
1279
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001280static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1281 const unsigned int value)
1282{
1283 if (!fpsba || !fdb) {
1284 fprintf(stderr, "Internal error\n");
1285 exit(EXIT_FAILURE);
1286 }
1287
1288 /* SoC Strap Length, aka PSL, aka ISL */
1289 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1290 if (strap >= SSL) {
1291 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1292 exit(EXIT_FAILURE);
1293 }
1294 fpsba->pchstrp[strap] = value;
1295}
1296
Bill XIEb3e15a22017-09-07 18:34:50 +08001297/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001298static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001299{
1300 if (ifd_version >= IFD_VERSION_2) {
1301 printf("%sting the HAP bit to %s Intel ME...\n",
1302 altmedisable?"Set":"Unset",
1303 altmedisable?"disable":"enable");
1304 if (altmedisable)
1305 fpsba->pchstrp[0] |= (1 << 16);
1306 else
1307 fpsba->pchstrp[0] &= ~(1 << 16);
1308 } else {
1309 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1310 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1311 "and MCH_AltMeDisable to %s Intel ME...\n",
1312 altmedisable?"Set":"Unset",
1313 altmedisable?"disable":"enable");
1314 if (altmedisable) {
1315 /* MCH_MeDisable */
1316 fmsba->data[0] |= 1;
1317 /* MCH_AltMeDisable */
1318 fmsba->data[0] |= (1 << 7);
1319 /* ICH_MeDisable */
1320 fpsba->pchstrp[0] |= 1;
1321 } else {
1322 fmsba->data[0] &= ~1;
1323 fmsba->data[0] &= ~(1 << 7);
1324 fpsba->pchstrp[0] &= ~1;
1325 }
1326 } else {
1327 printf("%sting the AltMeDisable to %s Intel ME...\n",
1328 altmedisable?"Set":"Unset",
1329 altmedisable?"disable":"enable");
1330 if (altmedisable)
1331 fpsba->pchstrp[10] |= (1 << 7);
1332 else
1333 fpsba->pchstrp[10] &= ~(1 << 7);
1334 }
1335 }
1336}
1337
Jacob Garber595d9262019-06-27 17:33:10 -06001338static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001339 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001340{
Bill XIE612ec0e2017-08-30 16:10:27 +08001341 frba_t *frba = find_frba(image, size);
1342 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001343 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001344
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001345 region_t region = get_region(frba, region_type);
1346 if (region.size <= 0xfff) {
1347 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1348 region_name(region_type));
1349 exit(EXIT_FAILURE);
1350 }
1351
Scott Duplichanf2c98372014-12-12 21:03:06 -06001352 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001353 if (region_fd == -1) {
1354 perror("Could not open file");
1355 exit(EXIT_FAILURE);
1356 }
1357 struct stat buf;
1358 if (fstat(region_fd, &buf) == -1) {
1359 perror("Could not stat file");
1360 exit(EXIT_FAILURE);
1361 }
1362 int region_size = buf.st_size;
1363
1364 printf("File %s is %d bytes\n", region_fname, region_size);
1365
1366 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001367 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001368 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1369 " bytes. Not injecting.\n",
1370 region_name(region_type), region.size,
1371 region.size, region_size, region_size);
1372 exit(EXIT_FAILURE);
1373 }
1374
1375 int offset = 0;
1376 if ((region_type == 1) && (region_size < region.size)) {
1377 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1378 " bytes. Padding before injecting.\n",
1379 region_name(region_type), region.size,
1380 region.size, region_size, region_size);
1381 offset = region.size - region_size;
1382 memset(image + region.base, 0xff, offset);
1383 }
1384
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001385 if (size < region.base + offset + region_size) {
1386 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1387 size, region.base + offset + region_size);
1388 exit(EXIT_FAILURE);
1389 }
1390
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001391 if (read(region_fd, image + region.base + offset, region_size)
1392 != region_size) {
1393 perror("Could not read file");
1394 exit(EXIT_FAILURE);
1395 }
1396
1397 close(region_fd);
1398
1399 printf("Adding %s as the %s section of %s\n",
1400 region_fname, region_name(region_type), filename);
1401 write_image(filename, image, size);
1402}
1403
Jacob Garber595d9262019-06-27 17:33:10 -06001404static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001405{
1406 unsigned int y = 1;
1407 if (x == 0)
1408 return 0;
1409 while (y <= x)
1410 y = y << 1;
1411
1412 return y;
1413}
1414
1415/**
1416 * Determine if two memory regions overlap.
1417 *
1418 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001419 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001420 * @return 1 if the two regions overlap
1421 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001422static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001423{
Bill XIEfa5f9942017-09-12 11:22:29 +08001424 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001425 return 0;
1426
Nico Huber844eda02019-01-05 00:06:19 +01001427 /* r1 should be either completely below or completely above r2 */
1428 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001429}
1430
Jacob Garber595d9262019-06-27 17:33:10 -06001431static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001432 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001433{
1434 FILE *romlayout;
1435 char tempstr[256];
1436 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001437 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001438 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001439 region_t current_regions[MAX_REGIONS];
1440 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001441 int new_extent = 0;
1442 char *new_image;
1443
1444 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001445 frba_t *frba = find_frba(image, size);
1446 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001447 exit(EXIT_FAILURE);
1448
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001449 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001450 current_regions[i] = get_region(frba, i);
1451 new_regions[i] = get_region(frba, i);
1452 }
1453
1454 /* read new layout */
1455 romlayout = fopen(layout_fname, "r");
1456
1457 if (!romlayout) {
1458 perror("Could not read layout file.\n");
1459 exit(EXIT_FAILURE);
1460 }
1461
1462 while (!feof(romlayout)) {
1463 char *tstr1, *tstr2;
1464
Patrick Georgi802ad522014-08-09 17:12:23 +02001465 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001466 layout_region_name))
1467 continue;
1468
1469 region_number = region_num(layout_region_name);
1470 if (region_number < 0)
1471 continue;
1472
1473 tstr1 = strtok(tempstr, ":");
1474 tstr2 = strtok(NULL, ":");
1475 if (!tstr1 || !tstr2) {
1476 fprintf(stderr, "Could not parse layout file.\n");
1477 exit(EXIT_FAILURE);
1478 }
1479 new_regions[region_number].base = strtol(tstr1,
1480 (char **)NULL, 16);
1481 new_regions[region_number].limit = strtol(tstr2,
1482 (char **)NULL, 16);
1483 new_regions[region_number].size =
1484 new_regions[region_number].limit -
1485 new_regions[region_number].base + 1;
1486
1487 if (new_regions[region_number].size < 0)
1488 new_regions[region_number].size = 0;
1489 }
1490 fclose(romlayout);
1491
1492 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001493 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001494 if (new_regions[i].size == 0)
1495 continue;
1496
1497 if (new_regions[i].size < current_regions[i].size) {
1498 printf("DANGER: Region %s is shrinking.\n",
1499 region_name(i));
1500 printf(" The region will be truncated to fit.\n");
1501 printf(" This may result in an unusable image.\n");
1502 }
1503
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001504 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001505 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001506 fprintf(stderr, "Regions would overlap.\n");
1507 exit(EXIT_FAILURE);
1508 }
1509 }
1510
1511 /* detect if the image size should grow */
1512 if (new_extent < new_regions[i].limit)
1513 new_extent = new_regions[i].limit;
1514 }
1515
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001516 /* check if the image is actually a Flash Descriptor region */
1517 if (size == new_regions[0].size) {
1518 printf("The image is a single Flash Descriptor:\n");
1519 printf(" Only the descriptor will be modified\n");
1520 new_extent = size;
1521 } else {
1522 new_extent = next_pow2(new_extent - 1);
1523 if (new_extent != size) {
1524 printf("The image has changed in size.\n");
1525 printf("The old image is %d bytes.\n", size);
1526 printf("The new image is %d bytes.\n", new_extent);
1527 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001528 }
1529
1530 /* copy regions to a new image */
1531 new_image = malloc(new_extent);
1532 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001533 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001534 int copy_size = new_regions[i].size;
1535 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001536 const region_t *current = &current_regions[i];
1537 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001538
Bill XIEfa5f9942017-09-12 11:22:29 +08001539 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001540 continue;
1541
Bill XIEfa5f9942017-09-12 11:22:29 +08001542 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001543 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001544 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001545 if (i == REGION_BIOS)
1546 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001547 }
1548
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001549 if ((i == REGION_BIOS) && (new->size < current->size)) {
1550 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001551 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001552 }
1553
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001554 if (size < current->base + offset_current + copy_size) {
1555 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1556 region_name(i));
1557 continue;
1558 };
1559
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001560 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1561 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001562 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1563 offset_current, current->limit, current->size);
1564 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1565 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001566
Bill XIEfa5f9942017-09-12 11:22:29 +08001567 memcpy(new_image + new->base + offset_new,
1568 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001569 copy_size);
1570 }
1571
1572 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001573 frba = find_frba(new_image, new_extent);
1574 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001575 exit(EXIT_FAILURE);
1576
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001577 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001578 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001579 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001580
1581 write_image(filename, new_image, new_extent);
1582 free(new_image);
1583}
1584
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001585static void print_version(void)
1586{
1587 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1588 printf("Copyright (C) 2011 Google Inc.\n\n");
1589 printf
1590 ("This program is free software: you can redistribute it and/or modify\n"
1591 "it under the terms of the GNU General Public License as published by\n"
1592 "the Free Software Foundation, version 2 of the License.\n\n"
1593 "This program is distributed in the hope that it will be useful,\n"
1594 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1595 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001596 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001597}
1598
1599static void print_usage(const char *name)
1600{
1601 printf("usage: %s [-vhdix?] <filename>\n", name);
1602 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001603 " -d | --dump: dump intel firmware descriptor\n"
1604 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1605 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1606 " -x | --extract: extract intel fd modules\n"
1607 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1608 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001609 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001610 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1611 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1612 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1613 " can only be used once per run:\n"
1614 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1615 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1616 " Dual Output Fast Read Support\n"
1617 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301618 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001619 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001620 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1621 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001622 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301623 " adl - Alder Lake\n"
1624 " aplk - Apollo Lake\n"
1625 " cnl - Cannon Lake\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001626 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301627 " glk - Gemini Lake\n"
1628 " icl - Ice Lake\n"
1629 " jsl - Jasper Lake\n"
1630 " sklkbl - Sky Lake/Kaby Lake\n"
1631 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001632 " -S | --setpchstrap Write a PCH strap\n"
1633 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001634 " -v | --version: print the version\n"
1635 " -h | --help: print this help\n\n"
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001636 "<region> is one of Descriptor, BIOS, ME, GbE, Platform, res1, res2, res3\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001637 "\n");
1638}
1639
1640int main(int argc, char *argv[])
1641{
1642 int opt, option_index = 0;
1643 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001644 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001645 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Usha P412679d2020-10-15 11:25:08 +05301646 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001647 char *region_type_string = NULL, *region_fname = NULL;
1648 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001649 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001650 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001651 unsigned int value = 0;
1652 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001653 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001654 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1655
Bill XIEfa5f9942017-09-12 11:22:29 +08001656 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001657 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001658 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001659 {"extract", 0, NULL, 'x'},
1660 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001661 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001662 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001663 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001664 {"density", 1, NULL, 'D'},
1665 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001666 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001667 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001668 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301669 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001670 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001671 {"version", 0, NULL, 'v'},
1672 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001673 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001674 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001675 {"setpchstrap", 1, NULL, 'S'},
1676 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001677 {0, 0, 0, 0}
1678 };
1679
Usha P412679d2020-10-15 11:25:08 +05301680 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 -07001681 long_options, &option_index)) != EOF) {
1682 switch (opt) {
1683 case 'd':
1684 mode_dump = 1;
1685 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001686 case 'S':
1687 mode_setstrap = 1;
1688 pchstrap = strtoul(optarg, NULL, 0);
1689 break;
1690 case 'V':
1691 value = strtoul(optarg, NULL, 0);
1692 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001693 case 'f':
1694 mode_layout = 1;
1695 layout_fname = strdup(optarg);
1696 if (!layout_fname) {
1697 fprintf(stderr, "No layout file specified\n");
1698 print_usage(argv[0]);
1699 exit(EXIT_FAILURE);
1700 }
1701 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001702 case 'x':
1703 mode_extract = 1;
1704 break;
1705 case 'i':
1706 // separate type and file name
1707 region_type_string = strdup(optarg);
1708 region_fname = strchr(region_type_string, ':');
1709 if (!region_fname) {
1710 print_usage(argv[0]);
1711 exit(EXIT_FAILURE);
1712 }
1713 region_fname[0] = '\0';
1714 region_fname++;
1715 // Descriptor, BIOS, ME, GbE, Platform
1716 // valid type?
1717 if (!strcasecmp("Descriptor", region_type_string))
1718 region_type = 0;
1719 else if (!strcasecmp("BIOS", region_type_string))
1720 region_type = 1;
1721 else if (!strcasecmp("ME", region_type_string))
1722 region_type = 2;
1723 else if (!strcasecmp("GbE", region_type_string))
1724 region_type = 3;
1725 else if (!strcasecmp("Platform", region_type_string))
1726 region_type = 4;
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001727 else if (!strcasecmp("res1", region_type_string))
1728 region_type = 5;
1729 else if (!strcasecmp("res2", region_type_string))
1730 region_type = 6;
1731 else if (!strcasecmp("res3", region_type_string))
1732 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001733 else if (!strcasecmp("EC", region_type_string))
1734 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001735 if (region_type == -1) {
1736 fprintf(stderr, "No such region type: '%s'\n\n",
1737 region_type_string);
1738 print_usage(argv[0]);
1739 exit(EXIT_FAILURE);
1740 }
1741 mode_inject = 1;
1742 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001743 case 'n':
1744 mode_newlayout = 1;
1745 layout_fname = strdup(optarg);
1746 if (!layout_fname) {
1747 fprintf(stderr, "No layout file specified\n");
1748 print_usage(argv[0]);
1749 exit(EXIT_FAILURE);
1750 }
1751 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001752 case 'O':
1753 new_filename = strdup(optarg);
1754 if (!new_filename) {
1755 fprintf(stderr, "No output filename specified\n");
1756 print_usage(argv[0]);
1757 exit(EXIT_FAILURE);
1758 }
1759 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001760 case 'D':
1761 mode_density = 1;
1762 new_density = strtoul(optarg, NULL, 0);
1763 switch (new_density) {
1764 case 512:
1765 new_density = COMPONENT_DENSITY_512KB;
1766 break;
1767 case 1:
1768 new_density = COMPONENT_DENSITY_1MB;
1769 break;
1770 case 2:
1771 new_density = COMPONENT_DENSITY_2MB;
1772 break;
1773 case 4:
1774 new_density = COMPONENT_DENSITY_4MB;
1775 break;
1776 case 8:
1777 new_density = COMPONENT_DENSITY_8MB;
1778 break;
1779 case 16:
1780 new_density = COMPONENT_DENSITY_16MB;
1781 break;
1782 case 32:
1783 new_density = COMPONENT_DENSITY_32MB;
1784 break;
1785 case 64:
1786 new_density = COMPONENT_DENSITY_64MB;
1787 break;
1788 case 0:
1789 new_density = COMPONENT_DENSITY_UNUSED;
1790 break;
1791 default:
1792 printf("error: Unknown density\n");
1793 print_usage(argv[0]);
1794 exit(EXIT_FAILURE);
1795 }
1796 break;
1797 case 'C':
1798 selected_chip = strtol(optarg, NULL, 0);
1799 if (selected_chip > 2) {
1800 fprintf(stderr, "error: Invalid chip selection\n");
1801 print_usage(argv[0]);
1802 exit(EXIT_FAILURE);
1803 }
1804 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001805 case 'M':
1806 mode_altmedisable = 1;
1807 altmedisable = strtol(optarg, NULL, 0);
1808 if (altmedisable > 1) {
1809 fprintf(stderr, "error: Illegal value\n");
1810 print_usage(argv[0]);
1811 exit(EXIT_FAILURE);
1812 }
1813 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001814 case 's':
1815 // Parse the requested SPI frequency
1816 inputfreq = strtol(optarg, NULL, 0);
1817 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001818 case 17:
1819 spifreq = SPI_FREQUENCY_17MHZ;
1820 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001821 case 20:
1822 spifreq = SPI_FREQUENCY_20MHZ;
1823 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001824 case 30:
1825 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1826 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001827 case 33:
1828 spifreq = SPI_FREQUENCY_33MHZ;
1829 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001830 case 48:
1831 spifreq = SPI_FREQUENCY_48MHZ;
1832 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001833 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001834 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001835 break;
1836 default:
1837 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1838 inputfreq);
1839 print_usage(argv[0]);
1840 exit(EXIT_FAILURE);
1841 }
1842 mode_spifreq = 1;
1843 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001844 case 'e':
1845 mode_em100 = 1;
1846 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001847 case 'l':
1848 mode_locked = 1;
1849 if (mode_unlocked == 1) {
1850 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1851 exit(EXIT_FAILURE);
1852 }
1853 break;
Usha P412679d2020-10-15 11:25:08 +05301854 case 'r':
1855 mode_read = 1;
1856 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001857 case 'u':
1858 mode_unlocked = 1;
1859 if (mode_locked == 1) {
1860 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1861 exit(EXIT_FAILURE);
1862 }
1863 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001864 case 'p':
1865 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001866 platform = PLATFORM_APL;
1867 } else if (!strcmp(optarg, "cnl")) {
1868 platform = PLATFORM_CNL;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001869 } else if (!strcmp(optarg, "ehl")) {
1870 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001871 } else if (!strcmp(optarg, "glk")) {
1872 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301873 } else if (!strcmp(optarg, "icl")) {
1874 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301875 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001876 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001877 } else if (!strcmp(optarg, "sklkbl")) {
1878 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001879 } else if (!strcmp(optarg, "tgl")) {
1880 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301881 } else if (!strcmp(optarg, "adl")) {
1882 platform = PLATFORM_ADL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001883 } else {
1884 fprintf(stderr, "Unknown platform: %s\n", optarg);
1885 exit(EXIT_FAILURE);
1886 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001887 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001888 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001889 case 't':
1890 mode_validate = 1;
1891 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001892 case 'v':
1893 print_version();
1894 exit(EXIT_SUCCESS);
1895 break;
1896 case 'h':
1897 case '?':
1898 default:
1899 print_usage(argv[0]);
1900 exit(EXIT_SUCCESS);
1901 break;
1902 }
1903 }
1904
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001905 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001906 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001907 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001908 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001909 print_usage(argv[0]);
1910 exit(EXIT_FAILURE);
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_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001915 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001916 fprintf(stderr, "You need to specify a mode.\n\n");
1917 print_usage(argv[0]);
1918 exit(EXIT_FAILURE);
1919 }
1920
1921 if (optind + 1 != argc) {
1922 fprintf(stderr, "You need to specify a file.\n\n");
1923 print_usage(argv[0]);
1924 exit(EXIT_FAILURE);
1925 }
1926
1927 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001928 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001929 if (bios_fd == -1) {
1930 perror("Could not open file");
1931 exit(EXIT_FAILURE);
1932 }
1933 struct stat buf;
1934 if (fstat(bios_fd, &buf) == -1) {
1935 perror("Could not stat file");
1936 exit(EXIT_FAILURE);
1937 }
1938 int size = buf.st_size;
1939
1940 printf("File %s is %d bytes\n", filename, size);
1941
1942 char *image = malloc(size);
1943 if (!image) {
1944 printf("Out of memory.\n");
1945 exit(EXIT_FAILURE);
1946 }
1947
1948 if (read(bios_fd, image, size) != size) {
1949 perror("Could not read file");
1950 exit(EXIT_FAILURE);
1951 }
1952
1953 close(bios_fd);
1954
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001955 // generate new filename
1956 if (new_filename == NULL) {
1957 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1958 if (!new_filename) {
1959 printf("Out of memory.\n");
1960 exit(EXIT_FAILURE);
1961 }
1962 // - 5: leave room for ".new\0"
1963 strcpy(new_filename, filename);
1964 strcat(new_filename, ".new");
1965 }
1966
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001967 check_ifd_version(image, size);
1968
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001969 if (mode_dump)
1970 dump_fd(image, size);
1971
Chris Douglass03ce0142014-02-26 13:30:13 -05001972 if (mode_layout)
1973 dump_layout(image, size, layout_fname);
1974
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001975 if (mode_extract)
1976 write_regions(image, size);
1977
Mathew Kingc7ddc992019-08-08 14:59:25 -06001978 if (mode_validate)
1979 validate_layout(image, size);
1980
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001981 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001982 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001983 region_fname);
1984
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001985 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001986 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001987
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001988 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001989 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001990
Jan Tatjefa317512016-03-11 00:52:07 +01001991 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001992 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01001993
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001994 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001995 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001996
Alexander Couzensd12ea112016-09-10 13:33:05 +02001997 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001998 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001999
Usha P412679d2020-10-15 11:25:08 +05302000 if (mode_read)
2001 enable_cpu_read_me(new_filename, image, size);
2002
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002003 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002004 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002005
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002006 if (mode_setstrap) {
2007 fpsba_t *fpsba = find_fpsba(image, size);
2008 const fdbar_t *fdb = find_fd(image, size);
2009 set_pchstrap(fpsba, fdb, pchstrap, value);
2010 write_image(new_filename, image, size);
2011 }
2012
Bill XIEb3e15a22017-09-07 18:34:50 +08002013 if (mode_altmedisable) {
2014 fpsba_t *fpsba = find_fpsba(image, size);
2015 fmsba_t *fmsba = find_fmsba(image, size);
2016 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002017 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002018 }
2019
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002020 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002021 free(image);
2022
2023 return 0;
2024}