blob: 20c4ed417a649b633454988c48164a36ece54a1f [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" },
Jeff Daly3623eca2022-01-05 23:51:40 -050043 { "Device Exp1", "devexp", "flashregion_5_device_exp.bin", "SI_DEVICEEXT" },
44 { "Secondary BIOS", "bios2", "flashregion_6_bios2.bin", "SI_BIOS2" },
45 { "Reserved", "res7", "flashregion_7_reserved.bin", NULL },
Mathew Kingc7ddc992019-08-08 14:59:25 -060046 { "EC", "ec", "flashregion_8_ec.bin", "SI_EC" },
Jeff Daly3623eca2022-01-05 23:51:40 -050047 { "Device Exp2", "devexp2", "flashregion_9_device_exp.bin", "SI_DEVICEEXT2" },
48 { "IE", "ie", "flashregion_10_ie.bin", "SI_IE" },
49 { "10GbE_0", "10gbe_0", "flashregion_11_10gbe0.bin", "SI_10GBE0" },
50 { "10GbE_1", "10gbe_1", "flashregion_12_10gbe1.bin", "SI_10GBE1" },
51 { "Reserved", "res13", "flashregion_13_reserved.bin", NULL },
52 { "Reserved", "res14", "flashregion_14_reserved.bin", NULL },
53 { "PTT", "ptt", "flashregion_15_ptt.bin", "SI_PTT" },
Chris Douglass03ce0142014-02-26 13:30:13 -050054};
55
Bill XIEb3e15a22017-09-07 18:34:50 +080056/* port from flashrom */
57static const char *const ich_chipset_names[] = {
58 "Unknown ICH",
59 "ICH",
60 "ICH2345",
61 "ICH6",
62 "SCH U",
63 "Atom E6xx",
64 "Atom S1220 S1240 S1260",
65 "ICH7",
66 "ICH8",
67 "ICH9",
68 "ICH10",
Subrata Banik89db2252020-08-26 14:49:17 +053069 "Unknown PCH",
Bill XIEb3e15a22017-09-07 18:34:50 +080070 "5 series Ibex Peak",
71 "6 series Cougar Point",
72 "7 series Panther Point",
73 "8 series Lynx Point",
74 "Baytrail",
75 "8 series Lynx Point LP",
76 "8 series Wellsburg",
77 "9 series Wildcat Point",
78 "9 series Wildcat Point LP",
Subrata Banik8c082e52021-06-10 23:02:29 +053079 "Apollo Lake: N3xxx, J3xxx",
Subrata Banik89db2252020-08-26 14:49:17 +053080 "Gemini Lake: N5xxx, J5xxx, N4xxx, J4xxx",
Subrata Banik8c082e52021-06-10 23:02:29 +053081 "Jasper Lake: N6xxx, N51xx, N45xx",
82 "Elkhart Lake: x6000 series Atom",
Subrata Banik89db2252020-08-26 14:49:17 +053083 "100/200 series Sunrise Point",
Subrata Banik8c082e52021-06-10 23:02:29 +053084 "300 series Cannon Point",
85 "400 series Ice Point",
Subrata Banika5f47812020-09-29 11:43:01 +053086 "500 series Tiger Point/ 600 series Alder Point",
Bill XIEb3e15a22017-09-07 18:34:50 +080087 "C620 series Lewisburg",
88 NULL
89};
90
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070091static fdbar_t *find_fd(char *image, int size)
92{
93 int i, found = 0;
94
95 /* Scan for FD signature */
96 for (i = 0; i < (size - 4); i += 4) {
97 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
98 found = 1;
99 break; // signature found.
100 }
101 }
102
103 if (!found) {
104 printf("No Flash Descriptor found in this image\n");
105 return NULL;
106 }
107
Bill XIE612ec0e2017-08-30 16:10:27 +0800108 fdbar_t *fdb = (fdbar_t *) (image + i);
109 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
110}
111
Stefan Tauner0d226142018-08-05 18:56:53 +0200112static char *find_flumap(char *image, int size)
113{
114 /* The upper map is located in the word before the 256B-long OEM section
115 * at the end of the 4kB-long flash descriptor. In the official
116 * documentation this is defined as FDBAR + 0xEFC. However, starting
117 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
118 * has moved 16 bytes back to offset 0x10 of the image. Although
119 * official documentation still maintains the offset relative to FDBAR
120 * this is wrong and a simple fixed offset from the start of the image
121 * works.
122 */
123 char *flumap = image + 4096 - 256 - 4;
124 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
125}
126
Bill XIE612ec0e2017-08-30 16:10:27 +0800127static fcba_t *find_fcba(char *image, int size)
128{
129 fdbar_t *fdb = find_fd(image, size);
130 if (!fdb)
131 return NULL;
132 fcba_t *fcba = (fcba_t *) (image + ((fdb->flmap0 & 0xff) << 4));
133 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
134
135}
136
137static fmba_t *find_fmba(char *image, int size)
138{
139 fdbar_t *fdb = find_fd(image, size);
140 if (!fdb)
141 return NULL;
142 fmba_t *fmba = (fmba_t *) (image + ((fdb->flmap1 & 0xff) << 4));
143 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
144}
145
146static frba_t *find_frba(char *image, int size)
147{
148 fdbar_t *fdb = find_fd(image, size);
149 if (!fdb)
150 return NULL;
151 frba_t *frba =
152 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
153 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
154}
155
156static fpsba_t *find_fpsba(char *image, int size)
157{
158 fdbar_t *fdb = find_fd(image, size);
159 if (!fdb)
160 return NULL;
161 fpsba_t *fpsba =
162 (fpsba_t *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200163
164 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
165 if ((((char *)fpsba) + SSL) >= (image + size))
166 return NULL;
167 return fpsba;
Bill XIE612ec0e2017-08-30 16:10:27 +0800168}
169
170static fmsba_t *find_fmsba(char *image, int size)
171{
172 fdbar_t *fdb = find_fd(image, size);
173 if (!fdb)
174 return NULL;
175 fmsba_t *fmsba = (fmsba_t *) (image + ((fdb->flmap2 & 0xff) << 4));
176 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700177}
178
Bill XIEb3e15a22017-09-07 18:34:50 +0800179/* port from flashrom */
Subrata Banik8c082e52021-06-10 23:02:29 +0530180static enum ich_chipset ifd1_guess_chipset(char *image, int size)
Bill XIEb3e15a22017-09-07 18:34:50 +0800181{
Subrata Banik8c082e52021-06-10 23:02:29 +0530182 const fdbar_t *fdb = find_fd(image, size);
183 if (!fdb)
184 exit(EXIT_FAILURE);
Bill XIEb3e15a22017-09-07 18:34:50 +0800185 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
186 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
187 uint32_t isl = (fdb->flmap1 >> 24);
188 uint32_t nm = (fdb->flmap1 >> 8) & 0x7;
Subrata Banik89db2252020-08-26 14:49:17 +0530189
190 /* Rest for IFD1 chipset type */
Bill XIEb3e15a22017-09-07 18:34:50 +0800191 if (iccriba == 0x00) {
192 if (msl == 0 && isl <= 2)
193 return CHIPSET_ICH8;
194 else if (isl <= 2)
195 return CHIPSET_ICH9;
196 else if (isl <= 10)
197 return CHIPSET_ICH10;
198 else if (isl <= 16)
199 return CHIPSET_5_SERIES_IBEX_PEAK;
200 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
201 return CHIPSET_5_SERIES_IBEX_PEAK;
202 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
203 if (msl == 0 && isl <= 17)
204 return CHIPSET_BAYTRAIL;
205 else if (msl <= 1 && isl <= 18)
206 return CHIPSET_6_SERIES_COUGAR_POINT;
207 else if (msl <= 1 && isl <= 21)
208 return CHIPSET_8_SERIES_LYNX_POINT;
209 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
210 return CHIPSET_9_SERIES_WILDCAT_POINT;
211 } else if (nm == 6) {
212 return CHIPSET_C620_SERIES_LEWISBURG;
Bill XIEb3e15a22017-09-07 18:34:50 +0800213 }
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200214 return CHIPSET_PCH_UNKNOWN;
Bill XIEb3e15a22017-09-07 18:34:50 +0800215}
216
Subrata Banik8c082e52021-06-10 23:02:29 +0530217static enum ich_chipset ifd2_platform_to_chipset(const int pindex)
218{
219 switch (pindex) {
Subrata Banik6da003c2021-07-14 13:52:03 +0530220 case PLATFORM_APL:
221 return CHIPSET_N_J_SERIES_APOLLO_LAKE;
Subrata Banik8c082e52021-06-10 23:02:29 +0530222 case PLATFORM_GLK:
223 return CHIPSET_N_J_SERIES_GEMINI_LAKE;
224 case PLATFORM_JSL:
225 return CHIPSET_N_SERIES_JASPER_LAKE;
226 case PLATFORM_EHL:
227 return CHIPSET_x6000_SERIES_ELKHART_LAKE;
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200228 case PLATFORM_SKLKBL:
229 return CHIPSET_100_200_SERIES_SUNRISE_POINT;
Subrata Banik8c082e52021-06-10 23:02:29 +0530230 case PLATFORM_CNL:
231 return CHIPSET_300_SERIES_CANNON_POINT;
232 case PLATFORM_TGL:
233 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800234 case PLATFORM_IFD2:
Subrata Banik8c082e52021-06-10 23:02:29 +0530235 return CHIPSET_500_600_SERIES_TIGER_ALDER_POINT;
236 case PLATFORM_ICL:
237 return CHIPSET_400_SERIES_ICE_POINT;
Johnny Line273a022021-06-22 11:26:46 +0800238 case PLATFORM_LBG:
239 return CHIPSET_C620_SERIES_LEWISBURG;
Subrata Banik8c082e52021-06-10 23:02:29 +0530240 default:
241 return CHIPSET_PCH_UNKNOWN;
242 }
243}
244
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700245/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700246 * Some newer platforms have re-defined the FCBA field that was used to
247 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
248 * have the required FCBA field, but are IFD v2 and return true if current
249 * platform is one of them.
250 */
251static int is_platform_ifd_2(void)
252{
253 static const int ifd_2_platforms[] = {
Subrata Banik6da003c2021-07-14 13:52:03 +0530254 PLATFORM_APL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700255 PLATFORM_GLK,
256 PLATFORM_CNL,
Johnny Line273a022021-06-22 11:26:46 +0800257 PLATFORM_LBG,
Aamir Bohra1018be22018-06-29 15:08:50 +0530258 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700259 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530260 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700261 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530262 PLATFORM_ADL,
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200263 PLATFORM_SKLKBL,
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800264 PLATFORM_IFD2,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700265 };
266 unsigned int i;
267
268 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
269 if (platform == ifd_2_platforms[i])
270 return 1;
271 }
272
273 return 0;
274}
275
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700276static void check_ifd_version(char *image, int size)
277{
Subrata Banik8c082e52021-06-10 23:02:29 +0530278 if (is_platform_ifd_2()) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700279 ifd_version = IFD_VERSION_2;
Subrata Banik8c082e52021-06-10 23:02:29 +0530280 chipset = ifd2_platform_to_chipset(platform);
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700281 max_regions = MAX_REGIONS;
Subrata Banik8c082e52021-06-10 23:02:29 +0530282 } else {
283 ifd_version = IFD_VERSION_1;
284 chipset = ifd1_guess_chipset(image, size);
285 max_regions = MAX_REGIONS_OLD;
286 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700287}
288
Bill XIEfa5f9942017-09-12 11:22:29 +0800289static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700290{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500291 int base_mask;
292 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700293 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700294 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500295
296 if (ifd_version >= IFD_VERSION_2)
297 base_mask = 0x7fff;
298 else
299 base_mask = 0xfff;
300
301 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700302
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400303 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800304 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700305 exit (EXIT_FAILURE);
306 }
307
Bill XIE4651d452017-09-12 11:54:48 +0800308 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700309 region.base = (flreg & base_mask) << 12;
310 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700311 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500312
Chris Douglass03ce0142014-02-26 13:30:13 -0500313 if (region.size < 0)
314 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700315
316 return region;
317}
318
Bill XIEfa5f9942017-09-12 11:22:29 +0800319static void set_region(frba_t *frba, unsigned int region_type,
320 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500321{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400322 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800323 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500324 exit (EXIT_FAILURE);
325 }
Bill XIE4651d452017-09-12 11:54:48 +0800326
327 frba->flreg[region_type] =
328 (((region->limit >> 12) & 0x7fff) << 16) |
329 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500330}
331
Bill XIEfa5f9942017-09-12 11:22:29 +0800332static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700333{
Bill XIEfa5f9942017-09-12 11:22:29 +0800334 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700335 fprintf(stderr, "Invalid region type.\n");
336 exit (EXIT_FAILURE);
337 }
338
Chris Douglass03ce0142014-02-26 13:30:13 -0500339 return region_names[region_type].pretty;
340}
341
Bill XIEfa5f9942017-09-12 11:22:29 +0800342static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500343{
Bill XIEfa5f9942017-09-12 11:22:29 +0800344 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500345 fprintf(stderr, "Invalid region type.\n");
346 exit (EXIT_FAILURE);
347 }
348
349 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700350}
351
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500352static int region_num(const char *name)
353{
Bill XIEfa5f9942017-09-12 11:22:29 +0800354 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500355
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200356 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500357 if (strcasecmp(name, region_names[i].pretty) == 0)
358 return i;
359 if (strcasecmp(name, region_names[i].terse) == 0)
360 return i;
361 }
362
363 return -1;
364}
365
Bill XIEfa5f9942017-09-12 11:22:29 +0800366static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700367{
Bill XIEfa5f9942017-09-12 11:22:29 +0800368 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700369 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700370 exit (EXIT_FAILURE);
371 }
372
Bill XIE1bf65062017-09-12 11:31:37 +0800373 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700374}
375
Bill XIEfa5f9942017-09-12 11:22:29 +0800376static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700377{
378 region_t region = get_region(frba, num);
379 printf(" Flash Region %d (%s): %08x - %08x %s\n",
380 num, region_name(num), region.base, region.limit,
381 region.size < 1 ? "(unused)" : "");
382}
383
Bill XIEfa5f9942017-09-12 11:22:29 +0800384static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
385 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500386{
387 region_t region = get_region(frba, num);
388 snprintf(buf, bufsize, "%08x:%08x %s\n",
389 region.base, region.limit, region_name_short(num));
390}
391
Bill XIEfa5f9942017-09-12 11:22:29 +0800392static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700393{
Bill XIE4651d452017-09-12 11:54:48 +0800394 unsigned int i;
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530395 region_t region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700396 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800397 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530398 region = get_region(frba, i);
399 /* Skip unused & reserved Flash Region */
400 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
401 continue;
402
Bill XIE4651d452017-09-12 11:54:48 +0800403 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
404 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700405 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700406}
407
Bill XIEfa5f9942017-09-12 11:22:29 +0800408static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500409{
410 char buf[LAYOUT_LINELEN];
411 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800412 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500413
414 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
415 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
416 if (layout_fd == -1) {
417 perror("Could not open file");
418 exit(EXIT_FAILURE);
419 }
420
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200421 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200422 region_t region = get_region(frba, i);
423 /* is region invalid? */
424 if (region.size < 1)
425 continue;
426
Chris Douglass03ce0142014-02-26 13:30:13 -0500427 dump_region_layout(buf, bufsize, i, frba);
428 if (write(layout_fd, buf, strlen(buf)) < 0) {
429 perror("Could not write to file");
430 exit(EXIT_FAILURE);
431 }
432 }
433 close(layout_fd);
434 printf("Wrote layout to %s\n", layout_fname);
435}
436
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530437static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700438{
439 switch (freq) {
440 case SPI_FREQUENCY_20MHZ:
441 printf("20MHz");
442 break;
443 case SPI_FREQUENCY_33MHZ:
444 printf("33MHz");
445 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700446 case SPI_FREQUENCY_48MHZ:
447 printf("48MHz");
448 break;
449 case SPI_FREQUENCY_50MHZ_30MHZ:
450 switch (ifd_version) {
451 case IFD_VERSION_1:
452 printf("50MHz");
453 break;
454 case IFD_VERSION_2:
455 printf("30MHz");
456 break;
457 }
458 break;
459 case SPI_FREQUENCY_17MHZ:
460 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700461 break;
462 default:
463 printf("unknown<%x>MHz", freq);
464 }
465}
466
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530467static void _decode_spi_frequency_500_series(unsigned int freq)
468{
469 switch (freq) {
470 case SPI_FREQUENCY_100MHZ:
471 printf("100MHz");
472 break;
473 case SPI_FREQUENCY_50MHZ:
474 printf("50MHz");
475 break;
476 case SPI_FREQUENCY_500SERIES_33MHZ:
477 printf("33MHz");
478 break;
479 case SPI_FREQUENCY_25MHZ:
480 printf("25MHz");
481 break;
482 case SPI_FREQUENCY_14MHZ:
483 printf("14MHz");
484 break;
485 default:
486 printf("unknown<%x>MHz", freq);
487 }
488}
489
490static void decode_spi_frequency(unsigned int freq)
491{
Subrata Banika5f47812020-09-29 11:43:01 +0530492 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530493 _decode_spi_frequency_500_series(freq);
494 else
495 _decode_spi_frequency(freq);
496}
497
Subrata Banike5d39922020-08-26 16:01:42 +0530498static void _decode_espi_frequency(unsigned int freq)
499{
500 switch (freq) {
501 case ESPI_FREQUENCY_20MHZ:
502 printf("20MHz");
503 break;
504 case ESPI_FREQUENCY_24MHZ:
505 printf("24MHz");
506 break;
507 case ESPI_FREQUENCY_30MHZ:
508 printf("30MHz");
509 break;
510 case ESPI_FREQUENCY_48MHZ:
511 printf("48MHz");
512 break;
513 case ESPI_FREQUENCY_60MHZ:
514 printf("60MHz");
515 break;
516 case ESPI_FREQUENCY_17MHZ:
517 printf("17MHz");
518 break;
519 default:
520 printf("unknown<%x>MHz", freq);
521 }
522}
523
524static void _decode_espi_frequency_500_series(unsigned int freq)
525{
526 switch (freq) {
527 case ESPI_FREQUENCY_500SERIES_20MHZ:
528 printf("20MHz");
529 break;
530 case ESPI_FREQUENCY_500SERIES_24MHZ:
531 printf("24MHz");
532 break;
533 case ESPI_FREQUENCY_500SERIES_25MHZ:
534 printf("25MHz");
535 break;
536 case ESPI_FREQUENCY_500SERIES_48MHZ:
537 printf("48MHz");
538 break;
539 case ESPI_FREQUENCY_500SERIES_60MHZ:
540 printf("60MHz");
541 break;
542 default:
543 printf("unknown<%x>MHz", freq);
544 }
545}
546
547static void decode_espi_frequency(unsigned int freq)
548{
Subrata Banika5f47812020-09-29 11:43:01 +0530549 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530550 _decode_espi_frequency_500_series(freq);
551 else
552 _decode_espi_frequency(freq);
553}
554
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700555static void decode_component_density(unsigned int density)
556{
557 switch (density) {
558 case COMPONENT_DENSITY_512KB:
559 printf("512KB");
560 break;
561 case COMPONENT_DENSITY_1MB:
562 printf("1MB");
563 break;
564 case COMPONENT_DENSITY_2MB:
565 printf("2MB");
566 break;
567 case COMPONENT_DENSITY_4MB:
568 printf("4MB");
569 break;
570 case COMPONENT_DENSITY_8MB:
571 printf("8MB");
572 break;
573 case COMPONENT_DENSITY_16MB:
574 printf("16MB");
575 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700576 case COMPONENT_DENSITY_32MB:
577 printf("32MB");
578 break;
579 case COMPONENT_DENSITY_64MB:
580 printf("64MB");
581 break;
582 case COMPONENT_DENSITY_UNUSED:
583 printf("UNUSED");
584 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700585 default:
586 printf("unknown<%x>MB", density);
587 }
588}
589
Subrata Banik26058dc2020-08-26 15:12:16 +0530590static int is_platform_with_pch(void)
591{
592 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
593 return 1;
594
595 return 0;
596}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530597
598/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
599static int is_platform_with_100x_series_pch(void)
600{
601 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530602 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530603 return 1;
604
605 return 0;
606}
607
Subrata Banike5d39922020-08-26 16:01:42 +0530608static void dump_fcba(const fcba_t *fcba, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700609{
Subrata Banike5d39922020-08-26 16:01:42 +0530610 unsigned int freq;
611
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700612 printf("\nFound Component Section\n");
613 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700614 printf(" Dual Output Fast Read Support: %ssupported\n",
615 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700616 printf(" Read ID/Read Status Clock Frequency: ");
617 decode_spi_frequency((fcba->flcomp >> 27) & 7);
618 printf("\n Write/Erase Clock Frequency: ");
619 decode_spi_frequency((fcba->flcomp >> 24) & 7);
620 printf("\n Fast Read Clock Frequency: ");
621 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700622 printf("\n Fast Read Support: %ssupported",
623 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530624 if (is_platform_with_100x_series_pch() &&
625 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
626 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530627 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530628 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
629 else
630 freq = (fcba->flcomp >> 17) & 7;
631 decode_espi_frequency(freq);
632 } else {
633 printf("\n Read Clock Frequency: ");
634 decode_spi_frequency((fcba->flcomp >> 17) & 7);
635 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700636
637 switch (ifd_version) {
638 case IFD_VERSION_1:
639 printf("\n Component 2 Density: ");
640 decode_component_density((fcba->flcomp >> 3) & 7);
641 printf("\n Component 1 Density: ");
642 decode_component_density(fcba->flcomp & 7);
643 break;
644 case IFD_VERSION_2:
645 printf("\n Component 2 Density: ");
646 decode_component_density((fcba->flcomp >> 4) & 0xf);
647 printf("\n Component 1 Density: ");
648 decode_component_density(fcba->flcomp & 0xf);
649 break;
650 }
651
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700652 printf("\n");
653 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700654 printf(" Invalid Instruction 3: 0x%02x\n",
655 (fcba->flill >> 24) & 0xff);
656 printf(" Invalid Instruction 2: 0x%02x\n",
657 (fcba->flill >> 16) & 0xff);
658 printf(" Invalid Instruction 1: 0x%02x\n",
659 (fcba->flill >> 8) & 0xff);
660 printf(" Invalid Instruction 0: 0x%02x\n",
661 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530662 if (is_platform_with_100x_series_pch()) {
663 printf("FLILL1 0x%08x\n", fcba->flpb);
664 printf(" Invalid Instruction 7: 0x%02x\n",
665 (fcba->flpb >> 24) & 0xff);
666 printf(" Invalid Instruction 6: 0x%02x\n",
667 (fcba->flpb >> 16) & 0xff);
668 printf(" Invalid Instruction 5: 0x%02x\n",
669 (fcba->flpb >> 8) & 0xff);
670 printf(" Invalid Instruction 4: 0x%02x\n",
671 fcba->flpb & 0xff);
672 } else {
673 printf("FLPB 0x%08x\n", fcba->flpb);
674 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
675 (fcba->flpb & 0xfff) << 12);
676 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700677}
678
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200679static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700680{
Bill XIE4651d452017-09-12 11:54:48 +0800681 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200682 /* SoC Strap Length, aka PSL, aka ISL */
683 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
684
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700685 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200686 for (i = 0; i < SSL; i++)
687 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800688
689 if (ifd_version >= IFD_VERSION_2) {
690 printf("HAP bit is %sset\n",
691 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
692 } else if (chipset >= CHIPSET_ICH8
693 && chipset <= CHIPSET_ICH10) {
694 printf("ICH_MeDisable bit is %sset\n",
695 fpsba->pchstrp[0] & 1 ? "" : "not ");
696 } else {
697 printf("AltMeDisable bit is %sset\n",
698 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
699 }
700
Bill XIE4651d452017-09-12 11:54:48 +0800701 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700702}
703
704static void decode_flmstr(uint32_t flmstr)
705{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700706 int wr_shift, rd_shift;
707 if (ifd_version >= IFD_VERSION_2) {
708 wr_shift = FLMSTR_WR_SHIFT_V2;
709 rd_shift = FLMSTR_RD_SHIFT_V2;
710 } else {
711 wr_shift = FLMSTR_WR_SHIFT_V1;
712 rd_shift = FLMSTR_RD_SHIFT_V1;
713 }
714
715 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700716 if (ifd_version >= IFD_VERSION_2)
717 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700718 (flmstr & (1 << (wr_shift + 8))) ?
719 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700720 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700721 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700722 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700723 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700724 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700725 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700726 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700727 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700728 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700729 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700730
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700731 if (ifd_version >= IFD_VERSION_2)
732 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700733 (flmstr & (1 << (rd_shift + 8))) ?
734 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700735 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700736 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700737 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700738 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700739 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700740 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700741 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700742 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700743 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700744 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700745
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700746 /* Requestor ID doesn't exist for ifd 2 */
747 if (ifd_version < IFD_VERSION_2)
748 printf(" Requester ID: 0x%04x\n\n",
749 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700750}
751
Bill XIEfa5f9942017-09-12 11:22:29 +0800752static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700753{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700754 printf("Found Master Section\n");
755 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
756 decode_flmstr(fmba->flmstr1);
757 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
758 decode_flmstr(fmba->flmstr2);
759 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
760 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700761 if (ifd_version >= IFD_VERSION_2) {
762 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
763 decode_flmstr(fmba->flmstr5);
764 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700765}
766
Bill XIEfa5f9942017-09-12 11:22:29 +0800767static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700768{
Bill XIE612ec0e2017-08-30 16:10:27 +0800769 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700770 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800771 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
772 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800773
774 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
775 printf("MCH_MeDisable bit is %sset\n",
776 fmsba->data[0] & 1 ? "" : "not ");
777 printf("MCH_AltMeDisable bit is %sset\n",
778 fmsba->data[0] & (1 << 7) ? "" : "not ");
779 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700780}
781
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700782static void dump_jid(uint32_t jid)
783{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100784 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700785 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100786 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200787 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100788 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200789 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700790}
791
792static void dump_vscc(uint32_t vscc)
793{
794 printf(" Lower Erase Opcode: 0x%02x\n",
795 vscc >> 24);
796 printf(" Lower Write Enable on Write Status: 0x%02x\n",
797 vscc & (1 << 20) ? 0x06 : 0x50);
798 printf(" Lower Write Status Required: %s\n",
799 vscc & (1 << 19) ? "Yes" : "No");
800 printf(" Lower Write Granularity: %d bytes\n",
801 vscc & (1 << 18) ? 64 : 1);
802 printf(" Lower Block / Sector Erase Size: ");
803 switch ((vscc >> 16) & 0x3) {
804 case 0:
805 printf("256 Byte\n");
806 break;
807 case 1:
808 printf("4KB\n");
809 break;
810 case 2:
811 printf("8KB\n");
812 break;
813 case 3:
814 printf("64KB\n");
815 break;
816 }
817
818 printf(" Upper Erase Opcode: 0x%02x\n",
819 (vscc >> 8) & 0xff);
820 printf(" Upper Write Enable on Write Status: 0x%02x\n",
821 vscc & (1 << 4) ? 0x06 : 0x50);
822 printf(" Upper Write Status Required: %s\n",
823 vscc & (1 << 3) ? "Yes" : "No");
824 printf(" Upper Write Granularity: %d bytes\n",
825 vscc & (1 << 2) ? 64 : 1);
826 printf(" Upper Block / Sector Erase Size: ");
827 switch (vscc & 0x3) {
828 case 0:
829 printf("256 Byte\n");
830 break;
831 case 1:
832 printf("4KB\n");
833 break;
834 case 2:
835 printf("8KB\n");
836 break;
837 case 3:
838 printf("64KB\n");
839 break;
840 }
841}
842
Bill XIEfa5f9942017-09-12 11:22:29 +0800843static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700844{
845 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200846 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
847 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700848
849 printf("ME VSCC table:\n");
850 for (i = 0; i < num; i++) {
851 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
852 dump_jid(vtba->entry[i].jid);
853 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
854 dump_vscc(vtba->entry[i].vscc);
855 }
856 printf("\n");
857}
858
Bill XIEfa5f9942017-09-12 11:22:29 +0800859static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700860{
861 int i, j;
862 printf("OEM Section:\n");
863 for (i = 0; i < 4; i++) {
864 printf("%02x:", i << 4);
865 for (j = 0; j < 16; j++)
866 printf(" %02x", oem[(i<<4)+j]);
867 printf ("\n");
868 }
869 printf ("\n");
870}
871
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700872static void dump_fd(char *image, int size)
873{
Bill XIE612ec0e2017-08-30 16:10:27 +0800874 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700875 if (!fdb)
876 exit(EXIT_FAILURE);
877
Subrata Banik26058dc2020-08-26 15:12:16 +0530878 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
879 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700880 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530881 if (!is_platform_with_100x_series_pch())
882 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700883 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
884 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
885 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
886
887 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530888 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
889 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700890 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
891 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
892 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
893
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530894 if (!is_platform_with_100x_series_pch()) {
895 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
896 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
897 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
898 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700899
Subrata Banika5f47812020-09-29 11:43:01 +0530900 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530901 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
902 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
903 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
904 }
905
Stefan Tauner0d226142018-08-05 18:56:53 +0200906 char *flumap = find_flumap(image, size);
907 uint32_t flumap1 = *(uint32_t *)flumap;
908 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700909 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200910 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700911 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200912 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700913 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200914 (image + ((flumap1 & 0xff) << 4)),
915 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800916 dump_oem((const uint8_t *)image + 0xf00);
917
918 const frba_t *frba = find_frba(image, size);
919 const fcba_t *fcba = find_fcba(image, size);
920 const fpsba_t *fpsba = find_fpsba(image, size);
921 const fmba_t *fmba = find_fmba(image, size);
922 const fmsba_t *fmsba = find_fmsba(image, size);
923
924 if (frba && fcba && fpsba && fmba && fmsba) {
925 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +0530926 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200927 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800928 dump_fmba(fmba);
929 dump_fmsba(fmsba);
930 } else {
931 printf("FD is corrupted!\n");
932 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700933}
934
Bill XIEfa5f9942017-09-12 11:22:29 +0800935static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500936{
Bill XIE612ec0e2017-08-30 16:10:27 +0800937 const frba_t *frba = find_frba(image, size);
938 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500939 exit(EXIT_FAILURE);
940
Bill XIE612ec0e2017-08-30 16:10:27 +0800941 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500942}
943
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700944static void write_regions(char *image, int size)
945{
Bill XIEfa5f9942017-09-12 11:22:29 +0800946 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800947 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700948
Bill XIE612ec0e2017-08-30 16:10:27 +0800949 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700950 exit(EXIT_FAILURE);
951
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700952 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700953 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700954 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700955 if (region.size > 0) {
956 int region_fd;
957 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600958 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700959 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200960 if (region_fd < 0) {
961 perror("Error while trying to open file");
962 exit(EXIT_FAILURE);
963 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700964 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700965 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700966 close(region_fd);
967 }
968 }
969}
970
Mathew Kingc7ddc992019-08-08 14:59:25 -0600971static void validate_layout(char *image, int size)
972{
973 uint i, errors = 0;
974 struct fmap *fmap;
975 long int fmap_loc = fmap_find((uint8_t *)image, size);
976 const frba_t *frba = find_frba(image, size);
977
978 if (fmap_loc < 0 || !frba)
979 exit(EXIT_FAILURE);
980
981 fmap = (struct fmap *)(image + fmap_loc);
982
983 for (i = 0; i < max_regions; i++) {
984 if (region_names[i].fmapname == NULL)
985 continue;
986
987 region_t region = get_region(frba, i);
988
989 if (region.size == 0)
990 continue;
991
992 const struct fmap_area *area =
993 fmap_find_area(fmap, region_names[i].fmapname);
994
995 if (!area)
996 continue;
997
998 if ((uint)region.base != area->offset ||
999 (uint)region.size != area->size) {
1000 printf("Region mismatch between %s and %s\n",
1001 region_names[i].terse, area->name);
1002 printf(" Descriptor region %s:\n", region_names[i].terse);
1003 printf(" offset: 0x%08x\n", region.base);
1004 printf(" length: 0x%08x\n", region.size);
1005 printf(" FMAP area %s:\n", area->name);
1006 printf(" offset: 0x%08x\n", area->offset);
1007 printf(" length: 0x%08x\n", area->size);
1008 errors++;
1009 }
1010 }
1011
1012 if (errors > 0)
1013 exit(EXIT_FAILURE);
1014}
1015
Bill XIEfa5f9942017-09-12 11:22:29 +08001016static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001017{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001018 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001019 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001020
1021 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001022 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001023 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001024 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001025 if (new_fd < 0) {
1026 perror("Error while trying to open file");
1027 exit(EXIT_FAILURE);
1028 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001029 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001030 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001031 close(new_fd);
1032}
1033
Bill XIEfa5f9942017-09-12 11:22:29 +08001034static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001035 enum spi_frequency freq)
1036{
Bill XIE612ec0e2017-08-30 16:10:27 +08001037 fcba_t *fcba = find_fcba(image, size);
1038 if (!fcba)
1039 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001040
1041 /* clear bits 21-29 */
1042 fcba->flcomp &= ~0x3fe00000;
1043 /* Read ID and Read Status Clock Frequency */
1044 fcba->flcomp |= freq << 27;
1045 /* Write and Erase Clock Frequency */
1046 fcba->flcomp |= freq << 24;
1047 /* Fast Read Clock Frequency */
1048 fcba->flcomp |= freq << 21;
1049
1050 write_image(filename, image, size);
1051}
1052
Bill XIEfa5f9942017-09-12 11:22:29 +08001053static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001054{
Bill XIE612ec0e2017-08-30 16:10:27 +08001055 fcba_t *fcba = find_fcba(image, size);
1056 if (!fcba)
1057 exit(EXIT_FAILURE);
1058
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001059 int freq;
1060
1061 switch (ifd_version) {
1062 case IFD_VERSION_1:
1063 freq = SPI_FREQUENCY_20MHZ;
1064 break;
1065 case IFD_VERSION_2:
1066 freq = SPI_FREQUENCY_17MHZ;
1067 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001068 default:
1069 freq = SPI_FREQUENCY_17MHZ;
1070 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001071 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001072
1073 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001074 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001075}
1076
Bill XIEfa5f9942017-09-12 11:22:29 +08001077static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +01001078 unsigned int density)
1079{
Bill XIE612ec0e2017-08-30 16:10:27 +08001080 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001081 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001082 if (!fcba)
1083 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001084
1085 printf("Setting chip density to ");
1086 decode_component_density(density);
1087 printf("\n");
1088
1089 switch (ifd_version) {
1090 case IFD_VERSION_1:
1091 /* fail if selected density is not supported by this version */
1092 if ( (density == COMPONENT_DENSITY_32MB) ||
1093 (density == COMPONENT_DENSITY_64MB) ||
1094 (density == COMPONENT_DENSITY_UNUSED) ) {
1095 printf("error: Selected density not supported in IFD version 1.\n");
1096 exit(EXIT_FAILURE);
1097 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001098 mask = 0x7;
1099 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001100 break;
1101 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001102 mask = 0xf;
1103 chip2_offset = 4;
1104 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001105 default:
1106 printf("error: Unknown IFD version\n");
1107 exit(EXIT_FAILURE);
1108 break;
1109 }
1110
1111 /* clear chip density for corresponding chip */
1112 switch (selected_chip) {
1113 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001114 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001115 break;
1116 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001117 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001118 break;
1119 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001120 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001121 break;
1122 }
1123
1124 /* set the new density */
1125 if (selected_chip == 1 || selected_chip == 0)
1126 fcba->flcomp |= (density); /* first chip */
1127 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001128 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001129
1130 write_image(filename, image, size);
1131}
1132
Duncan Laurie7775d672019-06-06 13:39:26 -07001133static int check_region(const frba_t *frba, unsigned int region_type)
1134{
1135 region_t region;
1136
1137 if (!frba)
1138 return 0;
1139
1140 region = get_region(frba, region_type);
1141 return !!((region.base < region.limit) && (region.size > 0));
1142}
1143
Bill XIEfa5f9942017-09-12 11:22:29 +08001144static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001145{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001146 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001147 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001148 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001149 if (!fmba)
1150 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001151
1152 if (ifd_version >= IFD_VERSION_2) {
1153 wr_shift = FLMSTR_WR_SHIFT_V2;
1154 rd_shift = FLMSTR_RD_SHIFT_V2;
1155
1156 /* Clear non-reserved bits */
1157 fmba->flmstr1 &= 0xff;
1158 fmba->flmstr2 &= 0xff;
1159 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001160 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001161 } else {
1162 wr_shift = FLMSTR_WR_SHIFT_V1;
1163 rd_shift = FLMSTR_RD_SHIFT_V1;
1164
1165 fmba->flmstr1 = 0;
1166 fmba->flmstr2 = 0;
1167 /* Requestor ID */
1168 fmba->flmstr3 = 0x118;
1169 }
1170
Andrey Petrov96ecb772016-10-31 19:31:54 -07001171 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001172 case PLATFORM_APL:
1173 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001174 /* CPU/BIOS can read descriptor and BIOS */
1175 fmba->flmstr1 |= 0x3 << rd_shift;
1176 /* CPU/BIOS can write BIOS */
1177 fmba->flmstr1 |= 0x2 << wr_shift;
1178 /* TXE can read descriptor, BIOS and Device Expansion */
1179 fmba->flmstr2 |= 0x23 << rd_shift;
1180 /* TXE can only write Device Expansion */
1181 fmba->flmstr2 |= 0x20 << wr_shift;
1182 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001183 case PLATFORM_CNL:
1184 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001185 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001186 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301187 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001188 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301189 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001190 case PLATFORM_IFD2:
Duncan Laurie7775d672019-06-06 13:39:26 -07001191 /* CPU/BIOS can read descriptor and BIOS. */
1192 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1193 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1194 /* CPU/BIOS can write BIOS. */
1195 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1196 /* ME can read descriptor and ME. */
1197 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1198 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001199 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001200 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1201 if (check_region(frba, REGION_GBE)) {
1202 /* BIOS can read/write GbE. */
1203 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1204 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1205 /* ME can read GbE. */
1206 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1207 /* GbE can read descriptor and read/write GbE.. */
1208 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1209 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1210 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1211 }
1212 if (check_region(frba, REGION_PDR)) {
1213 /* BIOS can read/write PDR. */
1214 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1215 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1216 }
1217 if (check_region(frba, REGION_EC)) {
1218 /* BIOS can read EC. */
1219 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1220 /* EC can read descriptor and read/write EC. */
1221 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1222 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1223 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1224 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001225 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001226 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001227 /* CPU/BIOS can read descriptor and BIOS. */
1228 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1229 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1230 /* CPU/BIOS can write BIOS. */
1231 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1232 /* ME can read descriptor and ME. */
1233 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1234 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1235 /* ME can write ME. */
1236 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1237 if (check_region(frba, REGION_GBE)) {
1238 /* BIOS can read GbE. */
1239 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1240 /* BIOS can write GbE. */
1241 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1242 /* ME can read GbE. */
1243 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1244 /* ME can write GbE. */
1245 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1246 /* GbE can write GbE. */
1247 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1248 /* GbE can read GbE. */
1249 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1250 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001251 break;
1252 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001253
1254 write_image(filename, image, size);
1255}
1256
Usha P412679d2020-10-15 11:25:08 +05301257static void enable_cpu_read_me(const char *filename, char *image, int size)
1258{
1259 int rd_shift;
1260 fmba_t *fmba = find_fmba(image, size);
1261
1262 if (!fmba)
1263 exit(EXIT_FAILURE);
1264
1265 if (ifd_version >= IFD_VERSION_2)
1266 rd_shift = FLMSTR_RD_SHIFT_V2;
1267 else
1268 rd_shift = FLMSTR_RD_SHIFT_V1;
1269
1270 /* CPU/BIOS can read ME. */
1271 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1272
1273 write_image(filename, image, size);
1274}
1275
Bill XIEfa5f9942017-09-12 11:22:29 +08001276static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001277{
Bill XIE612ec0e2017-08-30 16:10:27 +08001278 fmba_t *fmba = find_fmba(image, size);
1279 if (!fmba)
1280 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001281
1282 if (ifd_version >= IFD_VERSION_2) {
1283 /* Access bits for each region are read: 19:8 write: 31:20 */
1284 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1285 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1286 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001287 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001288 } else {
1289 fmba->flmstr1 = 0xffff0000;
1290 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001291 /* Keep chipset specific Requester ID */
1292 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001293 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001294
1295 write_image(filename, image, size);
1296}
1297
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001298static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1299 const unsigned int value)
1300{
1301 if (!fpsba || !fdb) {
1302 fprintf(stderr, "Internal error\n");
1303 exit(EXIT_FAILURE);
1304 }
1305
1306 /* SoC Strap Length, aka PSL, aka ISL */
1307 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1308 if (strap >= SSL) {
1309 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1310 exit(EXIT_FAILURE);
1311 }
1312 fpsba->pchstrp[strap] = value;
1313}
1314
Bill XIEb3e15a22017-09-07 18:34:50 +08001315/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001316static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001317{
1318 if (ifd_version >= IFD_VERSION_2) {
1319 printf("%sting the HAP bit to %s Intel ME...\n",
1320 altmedisable?"Set":"Unset",
1321 altmedisable?"disable":"enable");
1322 if (altmedisable)
1323 fpsba->pchstrp[0] |= (1 << 16);
1324 else
1325 fpsba->pchstrp[0] &= ~(1 << 16);
1326 } else {
1327 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1328 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1329 "and MCH_AltMeDisable to %s Intel ME...\n",
1330 altmedisable?"Set":"Unset",
1331 altmedisable?"disable":"enable");
1332 if (altmedisable) {
1333 /* MCH_MeDisable */
1334 fmsba->data[0] |= 1;
1335 /* MCH_AltMeDisable */
1336 fmsba->data[0] |= (1 << 7);
1337 /* ICH_MeDisable */
1338 fpsba->pchstrp[0] |= 1;
1339 } else {
1340 fmsba->data[0] &= ~1;
1341 fmsba->data[0] &= ~(1 << 7);
1342 fpsba->pchstrp[0] &= ~1;
1343 }
1344 } else {
1345 printf("%sting the AltMeDisable to %s Intel ME...\n",
1346 altmedisable?"Set":"Unset",
1347 altmedisable?"disable":"enable");
1348 if (altmedisable)
1349 fpsba->pchstrp[10] |= (1 << 7);
1350 else
1351 fpsba->pchstrp[10] &= ~(1 << 7);
1352 }
1353 }
1354}
1355
Jacob Garber595d9262019-06-27 17:33:10 -06001356static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001357 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001358{
Bill XIE612ec0e2017-08-30 16:10:27 +08001359 frba_t *frba = find_frba(image, size);
1360 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001361 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001362
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001363 region_t region = get_region(frba, region_type);
1364 if (region.size <= 0xfff) {
1365 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1366 region_name(region_type));
1367 exit(EXIT_FAILURE);
1368 }
1369
Scott Duplichanf2c98372014-12-12 21:03:06 -06001370 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001371 if (region_fd == -1) {
1372 perror("Could not open file");
1373 exit(EXIT_FAILURE);
1374 }
1375 struct stat buf;
1376 if (fstat(region_fd, &buf) == -1) {
1377 perror("Could not stat file");
1378 exit(EXIT_FAILURE);
1379 }
1380 int region_size = buf.st_size;
1381
1382 printf("File %s is %d bytes\n", region_fname, region_size);
1383
1384 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001385 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001386 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1387 " bytes. Not injecting.\n",
1388 region_name(region_type), region.size,
1389 region.size, region_size, region_size);
1390 exit(EXIT_FAILURE);
1391 }
1392
1393 int offset = 0;
1394 if ((region_type == 1) && (region_size < region.size)) {
1395 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1396 " bytes. Padding before injecting.\n",
1397 region_name(region_type), region.size,
1398 region.size, region_size, region_size);
1399 offset = region.size - region_size;
1400 memset(image + region.base, 0xff, offset);
1401 }
1402
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001403 if (size < region.base + offset + region_size) {
1404 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1405 size, region.base + offset + region_size);
1406 exit(EXIT_FAILURE);
1407 }
1408
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001409 if (read(region_fd, image + region.base + offset, region_size)
1410 != region_size) {
1411 perror("Could not read file");
1412 exit(EXIT_FAILURE);
1413 }
1414
1415 close(region_fd);
1416
1417 printf("Adding %s as the %s section of %s\n",
1418 region_fname, region_name(region_type), filename);
1419 write_image(filename, image, size);
1420}
1421
Jacob Garber595d9262019-06-27 17:33:10 -06001422static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001423{
1424 unsigned int y = 1;
1425 if (x == 0)
1426 return 0;
1427 while (y <= x)
1428 y = y << 1;
1429
1430 return y;
1431}
1432
1433/**
1434 * Determine if two memory regions overlap.
1435 *
1436 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001437 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001438 * @return 1 if the two regions overlap
1439 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001440static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001441{
Bill XIEfa5f9942017-09-12 11:22:29 +08001442 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001443 return 0;
1444
Nico Huber844eda02019-01-05 00:06:19 +01001445 /* r1 should be either completely below or completely above r2 */
1446 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001447}
1448
Jacob Garber595d9262019-06-27 17:33:10 -06001449static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001450 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001451{
1452 FILE *romlayout;
1453 char tempstr[256];
1454 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001455 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001456 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001457 region_t current_regions[MAX_REGIONS];
1458 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001459 int new_extent = 0;
1460 char *new_image;
1461
1462 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001463 frba_t *frba = find_frba(image, size);
1464 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001465 exit(EXIT_FAILURE);
1466
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001467 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001468 current_regions[i] = get_region(frba, i);
1469 new_regions[i] = get_region(frba, i);
1470 }
1471
1472 /* read new layout */
1473 romlayout = fopen(layout_fname, "r");
1474
1475 if (!romlayout) {
1476 perror("Could not read layout file.\n");
1477 exit(EXIT_FAILURE);
1478 }
1479
1480 while (!feof(romlayout)) {
1481 char *tstr1, *tstr2;
1482
Patrick Georgi802ad522014-08-09 17:12:23 +02001483 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001484 layout_region_name))
1485 continue;
1486
1487 region_number = region_num(layout_region_name);
1488 if (region_number < 0)
1489 continue;
1490
1491 tstr1 = strtok(tempstr, ":");
1492 tstr2 = strtok(NULL, ":");
1493 if (!tstr1 || !tstr2) {
1494 fprintf(stderr, "Could not parse layout file.\n");
1495 exit(EXIT_FAILURE);
1496 }
1497 new_regions[region_number].base = strtol(tstr1,
1498 (char **)NULL, 16);
1499 new_regions[region_number].limit = strtol(tstr2,
1500 (char **)NULL, 16);
1501 new_regions[region_number].size =
1502 new_regions[region_number].limit -
1503 new_regions[region_number].base + 1;
1504
1505 if (new_regions[region_number].size < 0)
1506 new_regions[region_number].size = 0;
1507 }
1508 fclose(romlayout);
1509
1510 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001511 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001512 if (new_regions[i].size == 0)
1513 continue;
1514
1515 if (new_regions[i].size < current_regions[i].size) {
1516 printf("DANGER: Region %s is shrinking.\n",
1517 region_name(i));
1518 printf(" The region will be truncated to fit.\n");
1519 printf(" This may result in an unusable image.\n");
1520 }
1521
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001522 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001523 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001524 fprintf(stderr, "Regions would overlap.\n");
1525 exit(EXIT_FAILURE);
1526 }
1527 }
1528
1529 /* detect if the image size should grow */
1530 if (new_extent < new_regions[i].limit)
1531 new_extent = new_regions[i].limit;
1532 }
1533
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001534 /* check if the image is actually a Flash Descriptor region */
1535 if (size == new_regions[0].size) {
1536 printf("The image is a single Flash Descriptor:\n");
1537 printf(" Only the descriptor will be modified\n");
1538 new_extent = size;
1539 } else {
1540 new_extent = next_pow2(new_extent - 1);
1541 if (new_extent != size) {
1542 printf("The image has changed in size.\n");
1543 printf("The old image is %d bytes.\n", size);
1544 printf("The new image is %d bytes.\n", new_extent);
1545 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001546 }
1547
1548 /* copy regions to a new image */
1549 new_image = malloc(new_extent);
1550 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001551 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001552 int copy_size = new_regions[i].size;
1553 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001554 const region_t *current = &current_regions[i];
1555 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001556
Bill XIEfa5f9942017-09-12 11:22:29 +08001557 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001558 continue;
1559
Bill XIEfa5f9942017-09-12 11:22:29 +08001560 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001561 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001562 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001563 if (i == REGION_BIOS)
1564 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001565 }
1566
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001567 if ((i == REGION_BIOS) && (new->size < current->size)) {
1568 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001569 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001570 }
1571
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001572 if (size < current->base + offset_current + copy_size) {
1573 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1574 region_name(i));
1575 continue;
1576 };
1577
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001578 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1579 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001580 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1581 offset_current, current->limit, current->size);
1582 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1583 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001584
Bill XIEfa5f9942017-09-12 11:22:29 +08001585 memcpy(new_image + new->base + offset_new,
1586 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001587 copy_size);
1588 }
1589
1590 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001591 frba = find_frba(new_image, new_extent);
1592 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001593 exit(EXIT_FAILURE);
1594
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001595 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001596 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001597 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001598
1599 write_image(filename, new_image, new_extent);
1600 free(new_image);
1601}
1602
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001603static void print_version(void)
1604{
1605 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1606 printf("Copyright (C) 2011 Google Inc.\n\n");
1607 printf
1608 ("This program is free software: you can redistribute it and/or modify\n"
1609 "it under the terms of the GNU General Public License as published by\n"
1610 "the Free Software Foundation, version 2 of the License.\n\n"
1611 "This program is distributed in the hope that it will be useful,\n"
1612 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1613 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001614 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001615}
1616
1617static void print_usage(const char *name)
1618{
1619 printf("usage: %s [-vhdix?] <filename>\n", name);
1620 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001621 " -d | --dump: dump intel firmware descriptor\n"
1622 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1623 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1624 " -x | --extract: extract intel fd modules\n"
1625 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1626 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001627 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001628 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1629 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1630 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1631 " can only be used once per run:\n"
1632 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1633 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1634 " Dual Output Fast Read Support\n"
1635 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301636 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001637 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001638 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1639 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001640 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301641 " adl - Alder Lake\n"
1642 " aplk - Apollo Lake\n"
1643 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08001644 " lbg - Lewisburg PCH\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001645 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301646 " glk - Gemini Lake\n"
1647 " icl - Ice Lake\n"
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001648 " ifd2 - IFDv2 Platform\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301649 " jsl - Jasper Lake\n"
1650 " sklkbl - Sky Lake/Kaby Lake\n"
1651 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001652 " -S | --setpchstrap Write a PCH strap\n"
1653 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001654 " -v | --version: print the version\n"
1655 " -h | --help: print this help\n\n"
Jeff Daly3623eca2022-01-05 23:51:40 -05001656 "<region> is one of Descriptor, BIOS, ME, GbE, Platform Data, Secondary BIOS, "
1657 "Device Exp1, EC, Device Exp2, IE, 10GbE_0, 10GbE_1, PTT\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001658 "\n");
1659}
1660
1661int main(int argc, char *argv[])
1662{
1663 int opt, option_index = 0;
1664 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001665 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001666 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Usha P412679d2020-10-15 11:25:08 +05301667 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001668 char *region_type_string = NULL, *region_fname = NULL;
1669 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001670 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001671 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001672 unsigned int value = 0;
1673 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001674 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001675 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1676
Bill XIEfa5f9942017-09-12 11:22:29 +08001677 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001678 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001679 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001680 {"extract", 0, NULL, 'x'},
1681 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001682 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001683 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001684 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001685 {"density", 1, NULL, 'D'},
1686 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001687 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001688 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001689 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301690 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001691 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001692 {"version", 0, NULL, 'v'},
1693 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001694 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001695 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001696 {"setpchstrap", 1, NULL, 'S'},
1697 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001698 {0, 0, 0, 0}
1699 };
1700
Usha P412679d2020-10-15 11:25:08 +05301701 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 -07001702 long_options, &option_index)) != EOF) {
1703 switch (opt) {
1704 case 'd':
1705 mode_dump = 1;
1706 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001707 case 'S':
1708 mode_setstrap = 1;
1709 pchstrap = strtoul(optarg, NULL, 0);
1710 break;
1711 case 'V':
1712 value = strtoul(optarg, NULL, 0);
1713 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001714 case 'f':
1715 mode_layout = 1;
1716 layout_fname = strdup(optarg);
1717 if (!layout_fname) {
1718 fprintf(stderr, "No layout file specified\n");
1719 print_usage(argv[0]);
1720 exit(EXIT_FAILURE);
1721 }
1722 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001723 case 'x':
1724 mode_extract = 1;
1725 break;
1726 case 'i':
1727 // separate type and file name
1728 region_type_string = strdup(optarg);
1729 region_fname = strchr(region_type_string, ':');
1730 if (!region_fname) {
1731 print_usage(argv[0]);
1732 exit(EXIT_FAILURE);
1733 }
1734 region_fname[0] = '\0';
1735 region_fname++;
1736 // Descriptor, BIOS, ME, GbE, Platform
1737 // valid type?
1738 if (!strcasecmp("Descriptor", region_type_string))
1739 region_type = 0;
1740 else if (!strcasecmp("BIOS", region_type_string))
1741 region_type = 1;
1742 else if (!strcasecmp("ME", region_type_string))
1743 region_type = 2;
1744 else if (!strcasecmp("GbE", region_type_string))
1745 region_type = 3;
Jeff Daly3623eca2022-01-05 23:51:40 -05001746 else if (!strcasecmp("Platform Data", region_type_string))
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001747 region_type = 4;
Jeff Daly3623eca2022-01-05 23:51:40 -05001748 else if (!strcasecmp("Device Exp1", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001749 region_type = 5;
Jeff Daly3623eca2022-01-05 23:51:40 -05001750 else if (!strcasecmp("Secondary BIOS", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001751 region_type = 6;
Jeff Daly3623eca2022-01-05 23:51:40 -05001752 else if (!strcasecmp("Reserved", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001753 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001754 else if (!strcasecmp("EC", region_type_string))
1755 region_type = 8;
Jeff Daly3623eca2022-01-05 23:51:40 -05001756 else if (!strcasecmp("Device Exp2", region_type_string))
1757 region_type = 9;
1758 else if (!strcasecmp("IE", region_type_string))
1759 region_type = 10;
1760 else if (!strcasecmp("10GbE_0", region_type_string))
1761 region_type = 11;
1762 else if (!strcasecmp("10GbE_1", region_type_string))
1763 region_type = 12;
1764 else if (!strcasecmp("PTT", region_type_string))
1765 region_type = 15;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001766 if (region_type == -1) {
1767 fprintf(stderr, "No such region type: '%s'\n\n",
1768 region_type_string);
1769 print_usage(argv[0]);
1770 exit(EXIT_FAILURE);
1771 }
1772 mode_inject = 1;
1773 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001774 case 'n':
1775 mode_newlayout = 1;
1776 layout_fname = strdup(optarg);
1777 if (!layout_fname) {
1778 fprintf(stderr, "No layout file specified\n");
1779 print_usage(argv[0]);
1780 exit(EXIT_FAILURE);
1781 }
1782 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001783 case 'O':
1784 new_filename = strdup(optarg);
1785 if (!new_filename) {
1786 fprintf(stderr, "No output filename specified\n");
1787 print_usage(argv[0]);
1788 exit(EXIT_FAILURE);
1789 }
1790 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001791 case 'D':
1792 mode_density = 1;
1793 new_density = strtoul(optarg, NULL, 0);
1794 switch (new_density) {
1795 case 512:
1796 new_density = COMPONENT_DENSITY_512KB;
1797 break;
1798 case 1:
1799 new_density = COMPONENT_DENSITY_1MB;
1800 break;
1801 case 2:
1802 new_density = COMPONENT_DENSITY_2MB;
1803 break;
1804 case 4:
1805 new_density = COMPONENT_DENSITY_4MB;
1806 break;
1807 case 8:
1808 new_density = COMPONENT_DENSITY_8MB;
1809 break;
1810 case 16:
1811 new_density = COMPONENT_DENSITY_16MB;
1812 break;
1813 case 32:
1814 new_density = COMPONENT_DENSITY_32MB;
1815 break;
1816 case 64:
1817 new_density = COMPONENT_DENSITY_64MB;
1818 break;
1819 case 0:
1820 new_density = COMPONENT_DENSITY_UNUSED;
1821 break;
1822 default:
1823 printf("error: Unknown density\n");
1824 print_usage(argv[0]);
1825 exit(EXIT_FAILURE);
1826 }
1827 break;
1828 case 'C':
1829 selected_chip = strtol(optarg, NULL, 0);
1830 if (selected_chip > 2) {
1831 fprintf(stderr, "error: Invalid chip selection\n");
1832 print_usage(argv[0]);
1833 exit(EXIT_FAILURE);
1834 }
1835 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001836 case 'M':
1837 mode_altmedisable = 1;
1838 altmedisable = strtol(optarg, NULL, 0);
1839 if (altmedisable > 1) {
1840 fprintf(stderr, "error: Illegal value\n");
1841 print_usage(argv[0]);
1842 exit(EXIT_FAILURE);
1843 }
1844 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001845 case 's':
1846 // Parse the requested SPI frequency
1847 inputfreq = strtol(optarg, NULL, 0);
1848 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001849 case 17:
1850 spifreq = SPI_FREQUENCY_17MHZ;
1851 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001852 case 20:
1853 spifreq = SPI_FREQUENCY_20MHZ;
1854 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001855 case 30:
1856 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1857 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001858 case 33:
1859 spifreq = SPI_FREQUENCY_33MHZ;
1860 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001861 case 48:
1862 spifreq = SPI_FREQUENCY_48MHZ;
1863 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001864 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001865 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001866 break;
1867 default:
1868 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1869 inputfreq);
1870 print_usage(argv[0]);
1871 exit(EXIT_FAILURE);
1872 }
1873 mode_spifreq = 1;
1874 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001875 case 'e':
1876 mode_em100 = 1;
1877 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001878 case 'l':
1879 mode_locked = 1;
1880 if (mode_unlocked == 1) {
1881 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1882 exit(EXIT_FAILURE);
1883 }
1884 break;
Usha P412679d2020-10-15 11:25:08 +05301885 case 'r':
1886 mode_read = 1;
1887 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001888 case 'u':
1889 mode_unlocked = 1;
1890 if (mode_locked == 1) {
1891 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1892 exit(EXIT_FAILURE);
1893 }
1894 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001895 case 'p':
1896 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001897 platform = PLATFORM_APL;
1898 } else if (!strcmp(optarg, "cnl")) {
1899 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08001900 } else if (!strcmp(optarg, "lbg")) {
1901 platform = PLATFORM_LBG;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001902 } else if (!strcmp(optarg, "ehl")) {
1903 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001904 } else if (!strcmp(optarg, "glk")) {
1905 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301906 } else if (!strcmp(optarg, "icl")) {
1907 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301908 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001909 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001910 } else if (!strcmp(optarg, "sklkbl")) {
1911 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001912 } else if (!strcmp(optarg, "tgl")) {
1913 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301914 } else if (!strcmp(optarg, "adl")) {
1915 platform = PLATFORM_ADL;
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001916 } else if (!strcmp(optarg, "ifd2")) {
1917 platform = PLATFORM_IFD2;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001918 } else {
1919 fprintf(stderr, "Unknown platform: %s\n", optarg);
1920 exit(EXIT_FAILURE);
1921 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001922 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001923 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001924 case 't':
1925 mode_validate = 1;
1926 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001927 case 'v':
1928 print_version();
1929 exit(EXIT_SUCCESS);
1930 break;
1931 case 'h':
1932 case '?':
1933 default:
1934 print_usage(argv[0]);
1935 exit(EXIT_SUCCESS);
1936 break;
1937 }
1938 }
1939
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001940 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001941 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001942 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001943 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001944 print_usage(argv[0]);
1945 exit(EXIT_FAILURE);
1946 }
1947
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001948 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001949 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001950 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001951 fprintf(stderr, "You need to specify a mode.\n\n");
1952 print_usage(argv[0]);
1953 exit(EXIT_FAILURE);
1954 }
1955
1956 if (optind + 1 != argc) {
1957 fprintf(stderr, "You need to specify a file.\n\n");
1958 print_usage(argv[0]);
1959 exit(EXIT_FAILURE);
1960 }
1961
1962 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001963 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001964 if (bios_fd == -1) {
1965 perror("Could not open file");
1966 exit(EXIT_FAILURE);
1967 }
1968 struct stat buf;
1969 if (fstat(bios_fd, &buf) == -1) {
1970 perror("Could not stat file");
1971 exit(EXIT_FAILURE);
1972 }
1973 int size = buf.st_size;
1974
1975 printf("File %s is %d bytes\n", filename, size);
1976
1977 char *image = malloc(size);
1978 if (!image) {
1979 printf("Out of memory.\n");
1980 exit(EXIT_FAILURE);
1981 }
1982
1983 if (read(bios_fd, image, size) != size) {
1984 perror("Could not read file");
1985 exit(EXIT_FAILURE);
1986 }
1987
1988 close(bios_fd);
1989
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001990 // generate new filename
1991 if (new_filename == NULL) {
1992 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1993 if (!new_filename) {
1994 printf("Out of memory.\n");
1995 exit(EXIT_FAILURE);
1996 }
1997 // - 5: leave room for ".new\0"
1998 strcpy(new_filename, filename);
1999 strcat(new_filename, ".new");
2000 }
2001
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002002 check_ifd_version(image, size);
2003
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002004 if (mode_dump)
2005 dump_fd(image, size);
2006
Chris Douglass03ce0142014-02-26 13:30:13 -05002007 if (mode_layout)
2008 dump_layout(image, size, layout_fname);
2009
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002010 if (mode_extract)
2011 write_regions(image, size);
2012
Mathew Kingc7ddc992019-08-08 14:59:25 -06002013 if (mode_validate)
2014 validate_layout(image, size);
2015
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002016 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002017 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002018 region_fname);
2019
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002020 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002021 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002022
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002023 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002024 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002025
Jan Tatjefa317512016-03-11 00:52:07 +01002026 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002027 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002028
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002029 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002030 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002031
Alexander Couzensd12ea112016-09-10 13:33:05 +02002032 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002033 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002034
Usha P412679d2020-10-15 11:25:08 +05302035 if (mode_read)
2036 enable_cpu_read_me(new_filename, image, size);
2037
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002038 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002039 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002040
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002041 if (mode_setstrap) {
2042 fpsba_t *fpsba = find_fpsba(image, size);
2043 const fdbar_t *fdb = find_fd(image, size);
2044 set_pchstrap(fpsba, fdb, pchstrap, value);
2045 write_image(new_filename, image, size);
2046 }
2047
Bill XIEb3e15a22017-09-07 18:34:50 +08002048 if (mode_altmedisable) {
2049 fpsba_t *fpsba = find_fpsba(image, size);
2050 fmsba_t *fmsba = find_fmsba(image, size);
2051 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002052 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002053 }
2054
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002055 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002056 free(image);
2057
2058 return 0;
2059}