blob: 586f50f2f72639c10adf9bdfa9dc2e744e8bb7d3 [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:
234 return CHIPSET_500_600_SERIES_TIGER_ALDER_POINT;
235 case PLATFORM_ICL:
236 return CHIPSET_400_SERIES_ICE_POINT;
Johnny Line273a022021-06-22 11:26:46 +0800237 case PLATFORM_LBG:
238 return CHIPSET_C620_SERIES_LEWISBURG;
Subrata Banik8c082e52021-06-10 23:02:29 +0530239 default:
240 return CHIPSET_PCH_UNKNOWN;
241 }
242}
243
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700244/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700245 * Some newer platforms have re-defined the FCBA field that was used to
246 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
247 * have the required FCBA field, but are IFD v2 and return true if current
248 * platform is one of them.
249 */
250static int is_platform_ifd_2(void)
251{
252 static const int ifd_2_platforms[] = {
Subrata Banik6da003c2021-07-14 13:52:03 +0530253 PLATFORM_APL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700254 PLATFORM_GLK,
255 PLATFORM_CNL,
Johnny Line273a022021-06-22 11:26:46 +0800256 PLATFORM_LBG,
Aamir Bohra1018be22018-06-29 15:08:50 +0530257 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700258 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530259 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700260 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530261 PLATFORM_ADL,
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200262 PLATFORM_SKLKBL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700263 };
264 unsigned int i;
265
266 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
267 if (platform == ifd_2_platforms[i])
268 return 1;
269 }
270
271 return 0;
272}
273
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700274static void check_ifd_version(char *image, int size)
275{
Subrata Banik8c082e52021-06-10 23:02:29 +0530276 if (is_platform_ifd_2()) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700277 ifd_version = IFD_VERSION_2;
Subrata Banik8c082e52021-06-10 23:02:29 +0530278 chipset = ifd2_platform_to_chipset(platform);
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700279 max_regions = MAX_REGIONS;
Subrata Banik8c082e52021-06-10 23:02:29 +0530280 } else {
281 ifd_version = IFD_VERSION_1;
282 chipset = ifd1_guess_chipset(image, size);
283 max_regions = MAX_REGIONS_OLD;
284 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700285}
286
Bill XIEfa5f9942017-09-12 11:22:29 +0800287static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700288{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500289 int base_mask;
290 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700291 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700292 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500293
294 if (ifd_version >= IFD_VERSION_2)
295 base_mask = 0x7fff;
296 else
297 base_mask = 0xfff;
298
299 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700300
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400301 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800302 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700303 exit (EXIT_FAILURE);
304 }
305
Bill XIE4651d452017-09-12 11:54:48 +0800306 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700307 region.base = (flreg & base_mask) << 12;
308 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700309 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500310
Chris Douglass03ce0142014-02-26 13:30:13 -0500311 if (region.size < 0)
312 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700313
314 return region;
315}
316
Bill XIEfa5f9942017-09-12 11:22:29 +0800317static void set_region(frba_t *frba, unsigned int region_type,
318 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500319{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400320 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800321 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500322 exit (EXIT_FAILURE);
323 }
Bill XIE4651d452017-09-12 11:54:48 +0800324
325 frba->flreg[region_type] =
326 (((region->limit >> 12) & 0x7fff) << 16) |
327 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500328}
329
Bill XIEfa5f9942017-09-12 11:22:29 +0800330static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700331{
Bill XIEfa5f9942017-09-12 11:22:29 +0800332 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700333 fprintf(stderr, "Invalid region type.\n");
334 exit (EXIT_FAILURE);
335 }
336
Chris Douglass03ce0142014-02-26 13:30:13 -0500337 return region_names[region_type].pretty;
338}
339
Bill XIEfa5f9942017-09-12 11:22:29 +0800340static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500341{
Bill XIEfa5f9942017-09-12 11:22:29 +0800342 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500343 fprintf(stderr, "Invalid region type.\n");
344 exit (EXIT_FAILURE);
345 }
346
347 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700348}
349
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500350static int region_num(const char *name)
351{
Bill XIEfa5f9942017-09-12 11:22:29 +0800352 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500353
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200354 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500355 if (strcasecmp(name, region_names[i].pretty) == 0)
356 return i;
357 if (strcasecmp(name, region_names[i].terse) == 0)
358 return i;
359 }
360
361 return -1;
362}
363
Bill XIEfa5f9942017-09-12 11:22:29 +0800364static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700365{
Bill XIEfa5f9942017-09-12 11:22:29 +0800366 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700367 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700368 exit (EXIT_FAILURE);
369 }
370
Bill XIE1bf65062017-09-12 11:31:37 +0800371 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700372}
373
Bill XIEfa5f9942017-09-12 11:22:29 +0800374static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700375{
376 region_t region = get_region(frba, num);
377 printf(" Flash Region %d (%s): %08x - %08x %s\n",
378 num, region_name(num), region.base, region.limit,
379 region.size < 1 ? "(unused)" : "");
380}
381
Bill XIEfa5f9942017-09-12 11:22:29 +0800382static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
383 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500384{
385 region_t region = get_region(frba, num);
386 snprintf(buf, bufsize, "%08x:%08x %s\n",
387 region.base, region.limit, region_name_short(num));
388}
389
Bill XIEfa5f9942017-09-12 11:22:29 +0800390static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700391{
Bill XIE4651d452017-09-12 11:54:48 +0800392 unsigned int i;
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530393 region_t region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700394 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800395 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530396 region = get_region(frba, i);
397 /* Skip unused & reserved Flash Region */
398 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
399 continue;
400
Bill XIE4651d452017-09-12 11:54:48 +0800401 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
402 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700403 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700404}
405
Bill XIEfa5f9942017-09-12 11:22:29 +0800406static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500407{
408 char buf[LAYOUT_LINELEN];
409 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800410 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500411
412 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
413 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
414 if (layout_fd == -1) {
415 perror("Could not open file");
416 exit(EXIT_FAILURE);
417 }
418
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200419 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200420 region_t region = get_region(frba, i);
421 /* is region invalid? */
422 if (region.size < 1)
423 continue;
424
Chris Douglass03ce0142014-02-26 13:30:13 -0500425 dump_region_layout(buf, bufsize, i, frba);
426 if (write(layout_fd, buf, strlen(buf)) < 0) {
427 perror("Could not write to file");
428 exit(EXIT_FAILURE);
429 }
430 }
431 close(layout_fd);
432 printf("Wrote layout to %s\n", layout_fname);
433}
434
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530435static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700436{
437 switch (freq) {
438 case SPI_FREQUENCY_20MHZ:
439 printf("20MHz");
440 break;
441 case SPI_FREQUENCY_33MHZ:
442 printf("33MHz");
443 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700444 case SPI_FREQUENCY_48MHZ:
445 printf("48MHz");
446 break;
447 case SPI_FREQUENCY_50MHZ_30MHZ:
448 switch (ifd_version) {
449 case IFD_VERSION_1:
450 printf("50MHz");
451 break;
452 case IFD_VERSION_2:
453 printf("30MHz");
454 break;
455 }
456 break;
457 case SPI_FREQUENCY_17MHZ:
458 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700459 break;
460 default:
461 printf("unknown<%x>MHz", freq);
462 }
463}
464
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530465static void _decode_spi_frequency_500_series(unsigned int freq)
466{
467 switch (freq) {
468 case SPI_FREQUENCY_100MHZ:
469 printf("100MHz");
470 break;
471 case SPI_FREQUENCY_50MHZ:
472 printf("50MHz");
473 break;
474 case SPI_FREQUENCY_500SERIES_33MHZ:
475 printf("33MHz");
476 break;
477 case SPI_FREQUENCY_25MHZ:
478 printf("25MHz");
479 break;
480 case SPI_FREQUENCY_14MHZ:
481 printf("14MHz");
482 break;
483 default:
484 printf("unknown<%x>MHz", freq);
485 }
486}
487
488static void decode_spi_frequency(unsigned int freq)
489{
Subrata Banika5f47812020-09-29 11:43:01 +0530490 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530491 _decode_spi_frequency_500_series(freq);
492 else
493 _decode_spi_frequency(freq);
494}
495
Subrata Banike5d39922020-08-26 16:01:42 +0530496static void _decode_espi_frequency(unsigned int freq)
497{
498 switch (freq) {
499 case ESPI_FREQUENCY_20MHZ:
500 printf("20MHz");
501 break;
502 case ESPI_FREQUENCY_24MHZ:
503 printf("24MHz");
504 break;
505 case ESPI_FREQUENCY_30MHZ:
506 printf("30MHz");
507 break;
508 case ESPI_FREQUENCY_48MHZ:
509 printf("48MHz");
510 break;
511 case ESPI_FREQUENCY_60MHZ:
512 printf("60MHz");
513 break;
514 case ESPI_FREQUENCY_17MHZ:
515 printf("17MHz");
516 break;
517 default:
518 printf("unknown<%x>MHz", freq);
519 }
520}
521
522static void _decode_espi_frequency_500_series(unsigned int freq)
523{
524 switch (freq) {
525 case ESPI_FREQUENCY_500SERIES_20MHZ:
526 printf("20MHz");
527 break;
528 case ESPI_FREQUENCY_500SERIES_24MHZ:
529 printf("24MHz");
530 break;
531 case ESPI_FREQUENCY_500SERIES_25MHZ:
532 printf("25MHz");
533 break;
534 case ESPI_FREQUENCY_500SERIES_48MHZ:
535 printf("48MHz");
536 break;
537 case ESPI_FREQUENCY_500SERIES_60MHZ:
538 printf("60MHz");
539 break;
540 default:
541 printf("unknown<%x>MHz", freq);
542 }
543}
544
545static void decode_espi_frequency(unsigned int freq)
546{
Subrata Banika5f47812020-09-29 11:43:01 +0530547 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530548 _decode_espi_frequency_500_series(freq);
549 else
550 _decode_espi_frequency(freq);
551}
552
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700553static void decode_component_density(unsigned int density)
554{
555 switch (density) {
556 case COMPONENT_DENSITY_512KB:
557 printf("512KB");
558 break;
559 case COMPONENT_DENSITY_1MB:
560 printf("1MB");
561 break;
562 case COMPONENT_DENSITY_2MB:
563 printf("2MB");
564 break;
565 case COMPONENT_DENSITY_4MB:
566 printf("4MB");
567 break;
568 case COMPONENT_DENSITY_8MB:
569 printf("8MB");
570 break;
571 case COMPONENT_DENSITY_16MB:
572 printf("16MB");
573 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700574 case COMPONENT_DENSITY_32MB:
575 printf("32MB");
576 break;
577 case COMPONENT_DENSITY_64MB:
578 printf("64MB");
579 break;
580 case COMPONENT_DENSITY_UNUSED:
581 printf("UNUSED");
582 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700583 default:
584 printf("unknown<%x>MB", density);
585 }
586}
587
Subrata Banik26058dc2020-08-26 15:12:16 +0530588static int is_platform_with_pch(void)
589{
590 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
591 return 1;
592
593 return 0;
594}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530595
596/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
597static int is_platform_with_100x_series_pch(void)
598{
599 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530600 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530601 return 1;
602
603 return 0;
604}
605
Subrata Banike5d39922020-08-26 16:01:42 +0530606static void dump_fcba(const fcba_t *fcba, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700607{
Subrata Banike5d39922020-08-26 16:01:42 +0530608 unsigned int freq;
609
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700610 printf("\nFound Component Section\n");
611 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700612 printf(" Dual Output Fast Read Support: %ssupported\n",
613 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700614 printf(" Read ID/Read Status Clock Frequency: ");
615 decode_spi_frequency((fcba->flcomp >> 27) & 7);
616 printf("\n Write/Erase Clock Frequency: ");
617 decode_spi_frequency((fcba->flcomp >> 24) & 7);
618 printf("\n Fast Read Clock Frequency: ");
619 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700620 printf("\n Fast Read Support: %ssupported",
621 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530622 if (is_platform_with_100x_series_pch() &&
623 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
624 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530625 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530626 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
627 else
628 freq = (fcba->flcomp >> 17) & 7;
629 decode_espi_frequency(freq);
630 } else {
631 printf("\n Read Clock Frequency: ");
632 decode_spi_frequency((fcba->flcomp >> 17) & 7);
633 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700634
635 switch (ifd_version) {
636 case IFD_VERSION_1:
637 printf("\n Component 2 Density: ");
638 decode_component_density((fcba->flcomp >> 3) & 7);
639 printf("\n Component 1 Density: ");
640 decode_component_density(fcba->flcomp & 7);
641 break;
642 case IFD_VERSION_2:
643 printf("\n Component 2 Density: ");
644 decode_component_density((fcba->flcomp >> 4) & 0xf);
645 printf("\n Component 1 Density: ");
646 decode_component_density(fcba->flcomp & 0xf);
647 break;
648 }
649
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700650 printf("\n");
651 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700652 printf(" Invalid Instruction 3: 0x%02x\n",
653 (fcba->flill >> 24) & 0xff);
654 printf(" Invalid Instruction 2: 0x%02x\n",
655 (fcba->flill >> 16) & 0xff);
656 printf(" Invalid Instruction 1: 0x%02x\n",
657 (fcba->flill >> 8) & 0xff);
658 printf(" Invalid Instruction 0: 0x%02x\n",
659 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530660 if (is_platform_with_100x_series_pch()) {
661 printf("FLILL1 0x%08x\n", fcba->flpb);
662 printf(" Invalid Instruction 7: 0x%02x\n",
663 (fcba->flpb >> 24) & 0xff);
664 printf(" Invalid Instruction 6: 0x%02x\n",
665 (fcba->flpb >> 16) & 0xff);
666 printf(" Invalid Instruction 5: 0x%02x\n",
667 (fcba->flpb >> 8) & 0xff);
668 printf(" Invalid Instruction 4: 0x%02x\n",
669 fcba->flpb & 0xff);
670 } else {
671 printf("FLPB 0x%08x\n", fcba->flpb);
672 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
673 (fcba->flpb & 0xfff) << 12);
674 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700675}
676
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200677static void dump_fpsba(const fdbar_t *fdb, const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700678{
Bill XIE4651d452017-09-12 11:54:48 +0800679 unsigned int i;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200680 /* SoC Strap Length, aka PSL, aka ISL */
681 unsigned int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
682
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700683 printf("Found PCH Strap Section\n");
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200684 for (i = 0; i < SSL; i++)
685 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800686
687 if (ifd_version >= IFD_VERSION_2) {
688 printf("HAP bit is %sset\n",
689 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
690 } else if (chipset >= CHIPSET_ICH8
691 && chipset <= CHIPSET_ICH10) {
692 printf("ICH_MeDisable bit is %sset\n",
693 fpsba->pchstrp[0] & 1 ? "" : "not ");
694 } else {
695 printf("AltMeDisable bit is %sset\n",
696 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
697 }
698
Bill XIE4651d452017-09-12 11:54:48 +0800699 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700700}
701
702static void decode_flmstr(uint32_t flmstr)
703{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700704 int wr_shift, rd_shift;
705 if (ifd_version >= IFD_VERSION_2) {
706 wr_shift = FLMSTR_WR_SHIFT_V2;
707 rd_shift = FLMSTR_RD_SHIFT_V2;
708 } else {
709 wr_shift = FLMSTR_WR_SHIFT_V1;
710 rd_shift = FLMSTR_RD_SHIFT_V1;
711 }
712
713 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700714 if (ifd_version >= IFD_VERSION_2)
715 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700716 (flmstr & (1 << (wr_shift + 8))) ?
717 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700718 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700719 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700720 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700721 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700722 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700723 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700724 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700725 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700726 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700727 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700728
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700729 if (ifd_version >= IFD_VERSION_2)
730 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700731 (flmstr & (1 << (rd_shift + 8))) ?
732 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700733 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700734 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700735 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700736 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700737 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700738 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700739 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700740 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700741 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700742 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700743
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700744 /* Requestor ID doesn't exist for ifd 2 */
745 if (ifd_version < IFD_VERSION_2)
746 printf(" Requester ID: 0x%04x\n\n",
747 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700748}
749
Bill XIEfa5f9942017-09-12 11:22:29 +0800750static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700751{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700752 printf("Found Master Section\n");
753 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
754 decode_flmstr(fmba->flmstr1);
755 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
756 decode_flmstr(fmba->flmstr2);
757 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
758 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700759 if (ifd_version >= IFD_VERSION_2) {
760 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
761 decode_flmstr(fmba->flmstr5);
762 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700763}
764
Bill XIEfa5f9942017-09-12 11:22:29 +0800765static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700766{
Bill XIE612ec0e2017-08-30 16:10:27 +0800767 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700768 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800769 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
770 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800771
772 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
773 printf("MCH_MeDisable bit is %sset\n",
774 fmsba->data[0] & 1 ? "" : "not ");
775 printf("MCH_AltMeDisable bit is %sset\n",
776 fmsba->data[0] & (1 << 7) ? "" : "not ");
777 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700778}
779
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700780static void dump_jid(uint32_t jid)
781{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100782 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700783 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100784 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200785 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100786 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200787 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700788}
789
790static void dump_vscc(uint32_t vscc)
791{
792 printf(" Lower Erase Opcode: 0x%02x\n",
793 vscc >> 24);
794 printf(" Lower Write Enable on Write Status: 0x%02x\n",
795 vscc & (1 << 20) ? 0x06 : 0x50);
796 printf(" Lower Write Status Required: %s\n",
797 vscc & (1 << 19) ? "Yes" : "No");
798 printf(" Lower Write Granularity: %d bytes\n",
799 vscc & (1 << 18) ? 64 : 1);
800 printf(" Lower Block / Sector Erase Size: ");
801 switch ((vscc >> 16) & 0x3) {
802 case 0:
803 printf("256 Byte\n");
804 break;
805 case 1:
806 printf("4KB\n");
807 break;
808 case 2:
809 printf("8KB\n");
810 break;
811 case 3:
812 printf("64KB\n");
813 break;
814 }
815
816 printf(" Upper Erase Opcode: 0x%02x\n",
817 (vscc >> 8) & 0xff);
818 printf(" Upper Write Enable on Write Status: 0x%02x\n",
819 vscc & (1 << 4) ? 0x06 : 0x50);
820 printf(" Upper Write Status Required: %s\n",
821 vscc & (1 << 3) ? "Yes" : "No");
822 printf(" Upper Write Granularity: %d bytes\n",
823 vscc & (1 << 2) ? 64 : 1);
824 printf(" Upper Block / Sector Erase Size: ");
825 switch (vscc & 0x3) {
826 case 0:
827 printf("256 Byte\n");
828 break;
829 case 1:
830 printf("4KB\n");
831 break;
832 case 2:
833 printf("8KB\n");
834 break;
835 case 3:
836 printf("64KB\n");
837 break;
838 }
839}
840
Bill XIEfa5f9942017-09-12 11:22:29 +0800841static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700842{
843 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200844 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
845 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700846
847 printf("ME VSCC table:\n");
848 for (i = 0; i < num; i++) {
849 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
850 dump_jid(vtba->entry[i].jid);
851 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
852 dump_vscc(vtba->entry[i].vscc);
853 }
854 printf("\n");
855}
856
Bill XIEfa5f9942017-09-12 11:22:29 +0800857static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700858{
859 int i, j;
860 printf("OEM Section:\n");
861 for (i = 0; i < 4; i++) {
862 printf("%02x:", i << 4);
863 for (j = 0; j < 16; j++)
864 printf(" %02x", oem[(i<<4)+j]);
865 printf ("\n");
866 }
867 printf ("\n");
868}
869
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700870static void dump_fd(char *image, int size)
871{
Bill XIE612ec0e2017-08-30 16:10:27 +0800872 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700873 if (!fdb)
874 exit(EXIT_FAILURE);
875
Subrata Banik26058dc2020-08-26 15:12:16 +0530876 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
877 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700878 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530879 if (!is_platform_with_100x_series_pch())
880 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700881 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
882 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
883 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
884
885 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530886 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
887 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700888 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
889 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
890 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
891
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530892 if (!is_platform_with_100x_series_pch()) {
893 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
894 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
895 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
896 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700897
Subrata Banika5f47812020-09-29 11:43:01 +0530898 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530899 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
900 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
901 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
902 }
903
Stefan Tauner0d226142018-08-05 18:56:53 +0200904 char *flumap = find_flumap(image, size);
905 uint32_t flumap1 = *(uint32_t *)flumap;
906 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700907 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200908 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700909 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200910 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700911 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200912 (image + ((flumap1 & 0xff) << 4)),
913 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800914 dump_oem((const uint8_t *)image + 0xf00);
915
916 const frba_t *frba = find_frba(image, size);
917 const fcba_t *fcba = find_fcba(image, size);
918 const fpsba_t *fpsba = find_fpsba(image, size);
919 const fmba_t *fmba = find_fmba(image, size);
920 const fmsba_t *fmsba = find_fmsba(image, size);
921
922 if (frba && fcba && fpsba && fmba && fmsba) {
923 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +0530924 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200925 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800926 dump_fmba(fmba);
927 dump_fmsba(fmsba);
928 } else {
929 printf("FD is corrupted!\n");
930 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700931}
932
Bill XIEfa5f9942017-09-12 11:22:29 +0800933static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500934{
Bill XIE612ec0e2017-08-30 16:10:27 +0800935 const frba_t *frba = find_frba(image, size);
936 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500937 exit(EXIT_FAILURE);
938
Bill XIE612ec0e2017-08-30 16:10:27 +0800939 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500940}
941
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700942static void write_regions(char *image, int size)
943{
Bill XIEfa5f9942017-09-12 11:22:29 +0800944 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800945 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700946
Bill XIE612ec0e2017-08-30 16:10:27 +0800947 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700948 exit(EXIT_FAILURE);
949
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700950 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700951 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700952 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700953 if (region.size > 0) {
954 int region_fd;
955 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600956 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700957 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200958 if (region_fd < 0) {
959 perror("Error while trying to open file");
960 exit(EXIT_FAILURE);
961 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700962 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700963 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700964 close(region_fd);
965 }
966 }
967}
968
Mathew Kingc7ddc992019-08-08 14:59:25 -0600969static void validate_layout(char *image, int size)
970{
971 uint i, errors = 0;
972 struct fmap *fmap;
973 long int fmap_loc = fmap_find((uint8_t *)image, size);
974 const frba_t *frba = find_frba(image, size);
975
976 if (fmap_loc < 0 || !frba)
977 exit(EXIT_FAILURE);
978
979 fmap = (struct fmap *)(image + fmap_loc);
980
981 for (i = 0; i < max_regions; i++) {
982 if (region_names[i].fmapname == NULL)
983 continue;
984
985 region_t region = get_region(frba, i);
986
987 if (region.size == 0)
988 continue;
989
990 const struct fmap_area *area =
991 fmap_find_area(fmap, region_names[i].fmapname);
992
993 if (!area)
994 continue;
995
996 if ((uint)region.base != area->offset ||
997 (uint)region.size != area->size) {
998 printf("Region mismatch between %s and %s\n",
999 region_names[i].terse, area->name);
1000 printf(" Descriptor region %s:\n", region_names[i].terse);
1001 printf(" offset: 0x%08x\n", region.base);
1002 printf(" length: 0x%08x\n", region.size);
1003 printf(" FMAP area %s:\n", area->name);
1004 printf(" offset: 0x%08x\n", area->offset);
1005 printf(" length: 0x%08x\n", area->size);
1006 errors++;
1007 }
1008 }
1009
1010 if (errors > 0)
1011 exit(EXIT_FAILURE);
1012}
1013
Bill XIEfa5f9942017-09-12 11:22:29 +08001014static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001015{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001016 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001017 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001018
1019 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001020 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001021 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001022 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001023 if (new_fd < 0) {
1024 perror("Error while trying to open file");
1025 exit(EXIT_FAILURE);
1026 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001027 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001028 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001029 close(new_fd);
1030}
1031
Bill XIEfa5f9942017-09-12 11:22:29 +08001032static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001033 enum spi_frequency freq)
1034{
Bill XIE612ec0e2017-08-30 16:10:27 +08001035 fcba_t *fcba = find_fcba(image, size);
1036 if (!fcba)
1037 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001038
1039 /* clear bits 21-29 */
1040 fcba->flcomp &= ~0x3fe00000;
1041 /* Read ID and Read Status Clock Frequency */
1042 fcba->flcomp |= freq << 27;
1043 /* Write and Erase Clock Frequency */
1044 fcba->flcomp |= freq << 24;
1045 /* Fast Read Clock Frequency */
1046 fcba->flcomp |= freq << 21;
1047
1048 write_image(filename, image, size);
1049}
1050
Bill XIEfa5f9942017-09-12 11:22:29 +08001051static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001052{
Bill XIE612ec0e2017-08-30 16:10:27 +08001053 fcba_t *fcba = find_fcba(image, size);
1054 if (!fcba)
1055 exit(EXIT_FAILURE);
1056
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001057 int freq;
1058
1059 switch (ifd_version) {
1060 case IFD_VERSION_1:
1061 freq = SPI_FREQUENCY_20MHZ;
1062 break;
1063 case IFD_VERSION_2:
1064 freq = SPI_FREQUENCY_17MHZ;
1065 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001066 default:
1067 freq = SPI_FREQUENCY_17MHZ;
1068 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001069 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001070
1071 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001072 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001073}
1074
Bill XIEfa5f9942017-09-12 11:22:29 +08001075static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +01001076 unsigned int density)
1077{
Bill XIE612ec0e2017-08-30 16:10:27 +08001078 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001079 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001080 if (!fcba)
1081 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001082
1083 printf("Setting chip density to ");
1084 decode_component_density(density);
1085 printf("\n");
1086
1087 switch (ifd_version) {
1088 case IFD_VERSION_1:
1089 /* fail if selected density is not supported by this version */
1090 if ( (density == COMPONENT_DENSITY_32MB) ||
1091 (density == COMPONENT_DENSITY_64MB) ||
1092 (density == COMPONENT_DENSITY_UNUSED) ) {
1093 printf("error: Selected density not supported in IFD version 1.\n");
1094 exit(EXIT_FAILURE);
1095 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001096 mask = 0x7;
1097 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001098 break;
1099 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001100 mask = 0xf;
1101 chip2_offset = 4;
1102 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001103 default:
1104 printf("error: Unknown IFD version\n");
1105 exit(EXIT_FAILURE);
1106 break;
1107 }
1108
1109 /* clear chip density for corresponding chip */
1110 switch (selected_chip) {
1111 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001112 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001113 break;
1114 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001115 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001116 break;
1117 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001118 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001119 break;
1120 }
1121
1122 /* set the new density */
1123 if (selected_chip == 1 || selected_chip == 0)
1124 fcba->flcomp |= (density); /* first chip */
1125 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001126 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001127
1128 write_image(filename, image, size);
1129}
1130
Duncan Laurie7775d672019-06-06 13:39:26 -07001131static int check_region(const frba_t *frba, unsigned int region_type)
1132{
1133 region_t region;
1134
1135 if (!frba)
1136 return 0;
1137
1138 region = get_region(frba, region_type);
1139 return !!((region.base < region.limit) && (region.size > 0));
1140}
1141
Bill XIEfa5f9942017-09-12 11:22:29 +08001142static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001143{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001144 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +08001145 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -07001146 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001147 if (!fmba)
1148 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001149
1150 if (ifd_version >= IFD_VERSION_2) {
1151 wr_shift = FLMSTR_WR_SHIFT_V2;
1152 rd_shift = FLMSTR_RD_SHIFT_V2;
1153
1154 /* Clear non-reserved bits */
1155 fmba->flmstr1 &= 0xff;
1156 fmba->flmstr2 &= 0xff;
1157 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001158 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001159 } else {
1160 wr_shift = FLMSTR_WR_SHIFT_V1;
1161 rd_shift = FLMSTR_RD_SHIFT_V1;
1162
1163 fmba->flmstr1 = 0;
1164 fmba->flmstr2 = 0;
1165 /* Requestor ID */
1166 fmba->flmstr3 = 0x118;
1167 }
1168
Andrey Petrov96ecb772016-10-31 19:31:54 -07001169 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001170 case PLATFORM_APL:
1171 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001172 /* CPU/BIOS can read descriptor and BIOS */
1173 fmba->flmstr1 |= 0x3 << rd_shift;
1174 /* CPU/BIOS can write BIOS */
1175 fmba->flmstr1 |= 0x2 << wr_shift;
1176 /* TXE can read descriptor, BIOS and Device Expansion */
1177 fmba->flmstr2 |= 0x23 << rd_shift;
1178 /* TXE can only write Device Expansion */
1179 fmba->flmstr2 |= 0x20 << wr_shift;
1180 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001181 case PLATFORM_CNL:
1182 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001183 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001184 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301185 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001186 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301187 case PLATFORM_ADL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001188 /* CPU/BIOS can read descriptor and BIOS. */
1189 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1190 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1191 /* CPU/BIOS can write BIOS. */
1192 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1193 /* ME can read descriptor and ME. */
1194 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1195 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001196 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001197 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1198 if (check_region(frba, REGION_GBE)) {
1199 /* BIOS can read/write GbE. */
1200 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1201 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1202 /* ME can read GbE. */
1203 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1204 /* GbE can read descriptor and read/write GbE.. */
1205 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1206 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1207 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1208 }
1209 if (check_region(frba, REGION_PDR)) {
1210 /* BIOS can read/write PDR. */
1211 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1212 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1213 }
1214 if (check_region(frba, REGION_EC)) {
1215 /* BIOS can read EC. */
1216 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1217 /* EC can read descriptor and read/write EC. */
1218 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1219 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1220 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1221 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001222 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001223 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001224 /* CPU/BIOS can read descriptor and BIOS. */
1225 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1226 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1227 /* CPU/BIOS can write BIOS. */
1228 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1229 /* ME can read descriptor and ME. */
1230 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1231 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1232 /* ME can write ME. */
1233 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1234 if (check_region(frba, REGION_GBE)) {
1235 /* BIOS can read GbE. */
1236 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1237 /* BIOS can write GbE. */
1238 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1239 /* ME can read GbE. */
1240 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1241 /* ME can write GbE. */
1242 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1243 /* GbE can write GbE. */
1244 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1245 /* GbE can read GbE. */
1246 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1247 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001248 break;
1249 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001250
1251 write_image(filename, image, size);
1252}
1253
Usha P412679d2020-10-15 11:25:08 +05301254static void enable_cpu_read_me(const char *filename, char *image, int size)
1255{
1256 int rd_shift;
1257 fmba_t *fmba = find_fmba(image, size);
1258
1259 if (!fmba)
1260 exit(EXIT_FAILURE);
1261
1262 if (ifd_version >= IFD_VERSION_2)
1263 rd_shift = FLMSTR_RD_SHIFT_V2;
1264 else
1265 rd_shift = FLMSTR_RD_SHIFT_V1;
1266
1267 /* CPU/BIOS can read ME. */
1268 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1269
1270 write_image(filename, image, size);
1271}
1272
Bill XIEfa5f9942017-09-12 11:22:29 +08001273static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001274{
Bill XIE612ec0e2017-08-30 16:10:27 +08001275 fmba_t *fmba = find_fmba(image, size);
1276 if (!fmba)
1277 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001278
1279 if (ifd_version >= IFD_VERSION_2) {
1280 /* Access bits for each region are read: 19:8 write: 31:20 */
1281 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1282 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1283 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001284 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001285 } else {
1286 fmba->flmstr1 = 0xffff0000;
1287 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001288 /* Keep chipset specific Requester ID */
1289 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001290 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001291
1292 write_image(filename, image, size);
1293}
1294
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001295static void set_pchstrap(fpsba_t *fpsba, const fdbar_t *fdb, const int strap,
1296 const unsigned int value)
1297{
1298 if (!fpsba || !fdb) {
1299 fprintf(stderr, "Internal error\n");
1300 exit(EXIT_FAILURE);
1301 }
1302
1303 /* SoC Strap Length, aka PSL, aka ISL */
1304 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
1305 if (strap >= SSL) {
1306 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SSL);
1307 exit(EXIT_FAILURE);
1308 }
1309 fpsba->pchstrp[strap] = value;
1310}
1311
Bill XIEb3e15a22017-09-07 18:34:50 +08001312/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001313static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001314{
1315 if (ifd_version >= IFD_VERSION_2) {
1316 printf("%sting the HAP bit to %s Intel ME...\n",
1317 altmedisable?"Set":"Unset",
1318 altmedisable?"disable":"enable");
1319 if (altmedisable)
1320 fpsba->pchstrp[0] |= (1 << 16);
1321 else
1322 fpsba->pchstrp[0] &= ~(1 << 16);
1323 } else {
1324 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1325 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1326 "and MCH_AltMeDisable to %s Intel ME...\n",
1327 altmedisable?"Set":"Unset",
1328 altmedisable?"disable":"enable");
1329 if (altmedisable) {
1330 /* MCH_MeDisable */
1331 fmsba->data[0] |= 1;
1332 /* MCH_AltMeDisable */
1333 fmsba->data[0] |= (1 << 7);
1334 /* ICH_MeDisable */
1335 fpsba->pchstrp[0] |= 1;
1336 } else {
1337 fmsba->data[0] &= ~1;
1338 fmsba->data[0] &= ~(1 << 7);
1339 fpsba->pchstrp[0] &= ~1;
1340 }
1341 } else {
1342 printf("%sting the AltMeDisable to %s Intel ME...\n",
1343 altmedisable?"Set":"Unset",
1344 altmedisable?"disable":"enable");
1345 if (altmedisable)
1346 fpsba->pchstrp[10] |= (1 << 7);
1347 else
1348 fpsba->pchstrp[10] &= ~(1 << 7);
1349 }
1350 }
1351}
1352
Jacob Garber595d9262019-06-27 17:33:10 -06001353static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001354 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001355{
Bill XIE612ec0e2017-08-30 16:10:27 +08001356 frba_t *frba = find_frba(image, size);
1357 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001358 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001359
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001360 region_t region = get_region(frba, region_type);
1361 if (region.size <= 0xfff) {
1362 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1363 region_name(region_type));
1364 exit(EXIT_FAILURE);
1365 }
1366
Scott Duplichanf2c98372014-12-12 21:03:06 -06001367 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001368 if (region_fd == -1) {
1369 perror("Could not open file");
1370 exit(EXIT_FAILURE);
1371 }
1372 struct stat buf;
1373 if (fstat(region_fd, &buf) == -1) {
1374 perror("Could not stat file");
1375 exit(EXIT_FAILURE);
1376 }
1377 int region_size = buf.st_size;
1378
1379 printf("File %s is %d bytes\n", region_fname, region_size);
1380
1381 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001382 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001383 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1384 " bytes. Not injecting.\n",
1385 region_name(region_type), region.size,
1386 region.size, region_size, region_size);
1387 exit(EXIT_FAILURE);
1388 }
1389
1390 int offset = 0;
1391 if ((region_type == 1) && (region_size < region.size)) {
1392 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1393 " bytes. Padding before injecting.\n",
1394 region_name(region_type), region.size,
1395 region.size, region_size, region_size);
1396 offset = region.size - region_size;
1397 memset(image + region.base, 0xff, offset);
1398 }
1399
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001400 if (size < region.base + offset + region_size) {
1401 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1402 size, region.base + offset + region_size);
1403 exit(EXIT_FAILURE);
1404 }
1405
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001406 if (read(region_fd, image + region.base + offset, region_size)
1407 != region_size) {
1408 perror("Could not read file");
1409 exit(EXIT_FAILURE);
1410 }
1411
1412 close(region_fd);
1413
1414 printf("Adding %s as the %s section of %s\n",
1415 region_fname, region_name(region_type), filename);
1416 write_image(filename, image, size);
1417}
1418
Jacob Garber595d9262019-06-27 17:33:10 -06001419static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001420{
1421 unsigned int y = 1;
1422 if (x == 0)
1423 return 0;
1424 while (y <= x)
1425 y = y << 1;
1426
1427 return y;
1428}
1429
1430/**
1431 * Determine if two memory regions overlap.
1432 *
1433 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001434 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001435 * @return 1 if the two regions overlap
1436 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001437static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001438{
Bill XIEfa5f9942017-09-12 11:22:29 +08001439 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001440 return 0;
1441
Nico Huber844eda02019-01-05 00:06:19 +01001442 /* r1 should be either completely below or completely above r2 */
1443 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001444}
1445
Jacob Garber595d9262019-06-27 17:33:10 -06001446static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001447 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001448{
1449 FILE *romlayout;
1450 char tempstr[256];
1451 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001452 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001453 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001454 region_t current_regions[MAX_REGIONS];
1455 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001456 int new_extent = 0;
1457 char *new_image;
1458
1459 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001460 frba_t *frba = find_frba(image, size);
1461 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001462 exit(EXIT_FAILURE);
1463
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001464 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001465 current_regions[i] = get_region(frba, i);
1466 new_regions[i] = get_region(frba, i);
1467 }
1468
1469 /* read new layout */
1470 romlayout = fopen(layout_fname, "r");
1471
1472 if (!romlayout) {
1473 perror("Could not read layout file.\n");
1474 exit(EXIT_FAILURE);
1475 }
1476
1477 while (!feof(romlayout)) {
1478 char *tstr1, *tstr2;
1479
Patrick Georgi802ad522014-08-09 17:12:23 +02001480 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001481 layout_region_name))
1482 continue;
1483
1484 region_number = region_num(layout_region_name);
1485 if (region_number < 0)
1486 continue;
1487
1488 tstr1 = strtok(tempstr, ":");
1489 tstr2 = strtok(NULL, ":");
1490 if (!tstr1 || !tstr2) {
1491 fprintf(stderr, "Could not parse layout file.\n");
1492 exit(EXIT_FAILURE);
1493 }
1494 new_regions[region_number].base = strtol(tstr1,
1495 (char **)NULL, 16);
1496 new_regions[region_number].limit = strtol(tstr2,
1497 (char **)NULL, 16);
1498 new_regions[region_number].size =
1499 new_regions[region_number].limit -
1500 new_regions[region_number].base + 1;
1501
1502 if (new_regions[region_number].size < 0)
1503 new_regions[region_number].size = 0;
1504 }
1505 fclose(romlayout);
1506
1507 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001508 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001509 if (new_regions[i].size == 0)
1510 continue;
1511
1512 if (new_regions[i].size < current_regions[i].size) {
1513 printf("DANGER: Region %s is shrinking.\n",
1514 region_name(i));
1515 printf(" The region will be truncated to fit.\n");
1516 printf(" This may result in an unusable image.\n");
1517 }
1518
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001519 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001520 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001521 fprintf(stderr, "Regions would overlap.\n");
1522 exit(EXIT_FAILURE);
1523 }
1524 }
1525
1526 /* detect if the image size should grow */
1527 if (new_extent < new_regions[i].limit)
1528 new_extent = new_regions[i].limit;
1529 }
1530
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001531 /* check if the image is actually a Flash Descriptor region */
1532 if (size == new_regions[0].size) {
1533 printf("The image is a single Flash Descriptor:\n");
1534 printf(" Only the descriptor will be modified\n");
1535 new_extent = size;
1536 } else {
1537 new_extent = next_pow2(new_extent - 1);
1538 if (new_extent != size) {
1539 printf("The image has changed in size.\n");
1540 printf("The old image is %d bytes.\n", size);
1541 printf("The new image is %d bytes.\n", new_extent);
1542 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001543 }
1544
1545 /* copy regions to a new image */
1546 new_image = malloc(new_extent);
1547 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001548 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001549 int copy_size = new_regions[i].size;
1550 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001551 const region_t *current = &current_regions[i];
1552 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001553
Bill XIEfa5f9942017-09-12 11:22:29 +08001554 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001555 continue;
1556
Bill XIEfa5f9942017-09-12 11:22:29 +08001557 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001558 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001559 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001560 if (i == REGION_BIOS)
1561 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001562 }
1563
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001564 if ((i == REGION_BIOS) && (new->size < current->size)) {
1565 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001566 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001567 }
1568
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001569 if (size < current->base + offset_current + copy_size) {
1570 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1571 region_name(i));
1572 continue;
1573 };
1574
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001575 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1576 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001577 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1578 offset_current, current->limit, current->size);
1579 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1580 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001581
Bill XIEfa5f9942017-09-12 11:22:29 +08001582 memcpy(new_image + new->base + offset_new,
1583 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001584 copy_size);
1585 }
1586
1587 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001588 frba = find_frba(new_image, new_extent);
1589 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001590 exit(EXIT_FAILURE);
1591
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001592 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001593 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001594 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001595
1596 write_image(filename, new_image, new_extent);
1597 free(new_image);
1598}
1599
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001600static void print_version(void)
1601{
1602 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1603 printf("Copyright (C) 2011 Google Inc.\n\n");
1604 printf
1605 ("This program is free software: you can redistribute it and/or modify\n"
1606 "it under the terms of the GNU General Public License as published by\n"
1607 "the Free Software Foundation, version 2 of the License.\n\n"
1608 "This program is distributed in the hope that it will be useful,\n"
1609 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1610 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001611 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001612}
1613
1614static void print_usage(const char *name)
1615{
1616 printf("usage: %s [-vhdix?] <filename>\n", name);
1617 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001618 " -d | --dump: dump intel firmware descriptor\n"
1619 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1620 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1621 " -x | --extract: extract intel fd modules\n"
1622 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1623 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001624 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001625 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1626 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1627 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1628 " can only be used once per run:\n"
1629 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1630 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1631 " Dual Output Fast Read Support\n"
1632 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301633 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001634 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001635 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1636 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001637 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301638 " adl - Alder Lake\n"
1639 " aplk - Apollo Lake\n"
1640 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08001641 " lbg - Lewisburg PCH\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001642 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301643 " glk - Gemini Lake\n"
1644 " icl - Ice Lake\n"
1645 " jsl - Jasper Lake\n"
1646 " sklkbl - Sky Lake/Kaby Lake\n"
1647 " tgl - Tiger Lake\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001648 " -S | --setpchstrap Write a PCH strap\n"
1649 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001650 " -v | --version: print the version\n"
1651 " -h | --help: print this help\n\n"
Jeff Daly3623eca2022-01-05 23:51:40 -05001652 "<region> is one of Descriptor, BIOS, ME, GbE, Platform Data, Secondary BIOS, "
1653 "Device Exp1, EC, Device Exp2, IE, 10GbE_0, 10GbE_1, PTT\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001654 "\n");
1655}
1656
1657int main(int argc, char *argv[])
1658{
1659 int opt, option_index = 0;
1660 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001661 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001662 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Usha P412679d2020-10-15 11:25:08 +05301663 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001664 char *region_type_string = NULL, *region_fname = NULL;
1665 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001666 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001667 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001668 unsigned int value = 0;
1669 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001670 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001671 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1672
Bill XIEfa5f9942017-09-12 11:22:29 +08001673 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001674 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001675 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001676 {"extract", 0, NULL, 'x'},
1677 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001678 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001679 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001680 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001681 {"density", 1, NULL, 'D'},
1682 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001683 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001684 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001685 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301686 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001687 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001688 {"version", 0, NULL, 'v'},
1689 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001690 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001691 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001692 {"setpchstrap", 1, NULL, 'S'},
1693 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001694 {0, 0, 0, 0}
1695 };
1696
Usha P412679d2020-10-15 11:25:08 +05301697 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 -07001698 long_options, &option_index)) != EOF) {
1699 switch (opt) {
1700 case 'd':
1701 mode_dump = 1;
1702 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001703 case 'S':
1704 mode_setstrap = 1;
1705 pchstrap = strtoul(optarg, NULL, 0);
1706 break;
1707 case 'V':
1708 value = strtoul(optarg, NULL, 0);
1709 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001710 case 'f':
1711 mode_layout = 1;
1712 layout_fname = strdup(optarg);
1713 if (!layout_fname) {
1714 fprintf(stderr, "No layout file specified\n");
1715 print_usage(argv[0]);
1716 exit(EXIT_FAILURE);
1717 }
1718 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001719 case 'x':
1720 mode_extract = 1;
1721 break;
1722 case 'i':
1723 // separate type and file name
1724 region_type_string = strdup(optarg);
1725 region_fname = strchr(region_type_string, ':');
1726 if (!region_fname) {
1727 print_usage(argv[0]);
1728 exit(EXIT_FAILURE);
1729 }
1730 region_fname[0] = '\0';
1731 region_fname++;
1732 // Descriptor, BIOS, ME, GbE, Platform
1733 // valid type?
1734 if (!strcasecmp("Descriptor", region_type_string))
1735 region_type = 0;
1736 else if (!strcasecmp("BIOS", region_type_string))
1737 region_type = 1;
1738 else if (!strcasecmp("ME", region_type_string))
1739 region_type = 2;
1740 else if (!strcasecmp("GbE", region_type_string))
1741 region_type = 3;
Jeff Daly3623eca2022-01-05 23:51:40 -05001742 else if (!strcasecmp("Platform Data", region_type_string))
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001743 region_type = 4;
Jeff Daly3623eca2022-01-05 23:51:40 -05001744 else if (!strcasecmp("Device Exp1", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001745 region_type = 5;
Jeff Daly3623eca2022-01-05 23:51:40 -05001746 else if (!strcasecmp("Secondary BIOS", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001747 region_type = 6;
Jeff Daly3623eca2022-01-05 23:51:40 -05001748 else if (!strcasecmp("Reserved", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001749 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001750 else if (!strcasecmp("EC", region_type_string))
1751 region_type = 8;
Jeff Daly3623eca2022-01-05 23:51:40 -05001752 else if (!strcasecmp("Device Exp2", region_type_string))
1753 region_type = 9;
1754 else if (!strcasecmp("IE", region_type_string))
1755 region_type = 10;
1756 else if (!strcasecmp("10GbE_0", region_type_string))
1757 region_type = 11;
1758 else if (!strcasecmp("10GbE_1", region_type_string))
1759 region_type = 12;
1760 else if (!strcasecmp("PTT", region_type_string))
1761 region_type = 15;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001762 if (region_type == -1) {
1763 fprintf(stderr, "No such region type: '%s'\n\n",
1764 region_type_string);
1765 print_usage(argv[0]);
1766 exit(EXIT_FAILURE);
1767 }
1768 mode_inject = 1;
1769 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001770 case 'n':
1771 mode_newlayout = 1;
1772 layout_fname = strdup(optarg);
1773 if (!layout_fname) {
1774 fprintf(stderr, "No layout file specified\n");
1775 print_usage(argv[0]);
1776 exit(EXIT_FAILURE);
1777 }
1778 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001779 case 'O':
1780 new_filename = strdup(optarg);
1781 if (!new_filename) {
1782 fprintf(stderr, "No output filename specified\n");
1783 print_usage(argv[0]);
1784 exit(EXIT_FAILURE);
1785 }
1786 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001787 case 'D':
1788 mode_density = 1;
1789 new_density = strtoul(optarg, NULL, 0);
1790 switch (new_density) {
1791 case 512:
1792 new_density = COMPONENT_DENSITY_512KB;
1793 break;
1794 case 1:
1795 new_density = COMPONENT_DENSITY_1MB;
1796 break;
1797 case 2:
1798 new_density = COMPONENT_DENSITY_2MB;
1799 break;
1800 case 4:
1801 new_density = COMPONENT_DENSITY_4MB;
1802 break;
1803 case 8:
1804 new_density = COMPONENT_DENSITY_8MB;
1805 break;
1806 case 16:
1807 new_density = COMPONENT_DENSITY_16MB;
1808 break;
1809 case 32:
1810 new_density = COMPONENT_DENSITY_32MB;
1811 break;
1812 case 64:
1813 new_density = COMPONENT_DENSITY_64MB;
1814 break;
1815 case 0:
1816 new_density = COMPONENT_DENSITY_UNUSED;
1817 break;
1818 default:
1819 printf("error: Unknown density\n");
1820 print_usage(argv[0]);
1821 exit(EXIT_FAILURE);
1822 }
1823 break;
1824 case 'C':
1825 selected_chip = strtol(optarg, NULL, 0);
1826 if (selected_chip > 2) {
1827 fprintf(stderr, "error: Invalid chip selection\n");
1828 print_usage(argv[0]);
1829 exit(EXIT_FAILURE);
1830 }
1831 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001832 case 'M':
1833 mode_altmedisable = 1;
1834 altmedisable = strtol(optarg, NULL, 0);
1835 if (altmedisable > 1) {
1836 fprintf(stderr, "error: Illegal value\n");
1837 print_usage(argv[0]);
1838 exit(EXIT_FAILURE);
1839 }
1840 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001841 case 's':
1842 // Parse the requested SPI frequency
1843 inputfreq = strtol(optarg, NULL, 0);
1844 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001845 case 17:
1846 spifreq = SPI_FREQUENCY_17MHZ;
1847 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001848 case 20:
1849 spifreq = SPI_FREQUENCY_20MHZ;
1850 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001851 case 30:
1852 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1853 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001854 case 33:
1855 spifreq = SPI_FREQUENCY_33MHZ;
1856 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001857 case 48:
1858 spifreq = SPI_FREQUENCY_48MHZ;
1859 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001860 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001861 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001862 break;
1863 default:
1864 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1865 inputfreq);
1866 print_usage(argv[0]);
1867 exit(EXIT_FAILURE);
1868 }
1869 mode_spifreq = 1;
1870 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001871 case 'e':
1872 mode_em100 = 1;
1873 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001874 case 'l':
1875 mode_locked = 1;
1876 if (mode_unlocked == 1) {
1877 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1878 exit(EXIT_FAILURE);
1879 }
1880 break;
Usha P412679d2020-10-15 11:25:08 +05301881 case 'r':
1882 mode_read = 1;
1883 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001884 case 'u':
1885 mode_unlocked = 1;
1886 if (mode_locked == 1) {
1887 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1888 exit(EXIT_FAILURE);
1889 }
1890 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001891 case 'p':
1892 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001893 platform = PLATFORM_APL;
1894 } else if (!strcmp(optarg, "cnl")) {
1895 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08001896 } else if (!strcmp(optarg, "lbg")) {
1897 platform = PLATFORM_LBG;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001898 } else if (!strcmp(optarg, "ehl")) {
1899 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001900 } else if (!strcmp(optarg, "glk")) {
1901 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301902 } else if (!strcmp(optarg, "icl")) {
1903 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301904 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001905 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001906 } else if (!strcmp(optarg, "sklkbl")) {
1907 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001908 } else if (!strcmp(optarg, "tgl")) {
1909 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301910 } else if (!strcmp(optarg, "adl")) {
1911 platform = PLATFORM_ADL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001912 } else {
1913 fprintf(stderr, "Unknown platform: %s\n", optarg);
1914 exit(EXIT_FAILURE);
1915 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001916 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001917 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001918 case 't':
1919 mode_validate = 1;
1920 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001921 case 'v':
1922 print_version();
1923 exit(EXIT_SUCCESS);
1924 break;
1925 case 'h':
1926 case '?':
1927 default:
1928 print_usage(argv[0]);
1929 exit(EXIT_SUCCESS);
1930 break;
1931 }
1932 }
1933
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001934 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001935 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001936 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001937 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001938 print_usage(argv[0]);
1939 exit(EXIT_FAILURE);
1940 }
1941
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001942 if ((mode_dump + mode_layout + mode_extract + mode_inject + mode_setstrap +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001943 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001944 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001945 fprintf(stderr, "You need to specify a mode.\n\n");
1946 print_usage(argv[0]);
1947 exit(EXIT_FAILURE);
1948 }
1949
1950 if (optind + 1 != argc) {
1951 fprintf(stderr, "You need to specify a file.\n\n");
1952 print_usage(argv[0]);
1953 exit(EXIT_FAILURE);
1954 }
1955
1956 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001957 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001958 if (bios_fd == -1) {
1959 perror("Could not open file");
1960 exit(EXIT_FAILURE);
1961 }
1962 struct stat buf;
1963 if (fstat(bios_fd, &buf) == -1) {
1964 perror("Could not stat file");
1965 exit(EXIT_FAILURE);
1966 }
1967 int size = buf.st_size;
1968
1969 printf("File %s is %d bytes\n", filename, size);
1970
1971 char *image = malloc(size);
1972 if (!image) {
1973 printf("Out of memory.\n");
1974 exit(EXIT_FAILURE);
1975 }
1976
1977 if (read(bios_fd, image, size) != size) {
1978 perror("Could not read file");
1979 exit(EXIT_FAILURE);
1980 }
1981
1982 close(bios_fd);
1983
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001984 // generate new filename
1985 if (new_filename == NULL) {
1986 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1987 if (!new_filename) {
1988 printf("Out of memory.\n");
1989 exit(EXIT_FAILURE);
1990 }
1991 // - 5: leave room for ".new\0"
1992 strcpy(new_filename, filename);
1993 strcat(new_filename, ".new");
1994 }
1995
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001996 check_ifd_version(image, size);
1997
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001998 if (mode_dump)
1999 dump_fd(image, size);
2000
Chris Douglass03ce0142014-02-26 13:30:13 -05002001 if (mode_layout)
2002 dump_layout(image, size, layout_fname);
2003
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002004 if (mode_extract)
2005 write_regions(image, size);
2006
Mathew Kingc7ddc992019-08-08 14:59:25 -06002007 if (mode_validate)
2008 validate_layout(image, size);
2009
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002010 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002011 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002012 region_fname);
2013
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002014 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002015 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002016
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002017 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002018 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002019
Jan Tatjefa317512016-03-11 00:52:07 +01002020 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002021 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002022
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002023 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002024 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002025
Alexander Couzensd12ea112016-09-10 13:33:05 +02002026 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002027 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002028
Usha P412679d2020-10-15 11:25:08 +05302029 if (mode_read)
2030 enable_cpu_read_me(new_filename, image, size);
2031
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002032 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002033 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002034
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002035 if (mode_setstrap) {
2036 fpsba_t *fpsba = find_fpsba(image, size);
2037 const fdbar_t *fdb = find_fd(image, size);
2038 set_pchstrap(fpsba, fdb, pchstrap, value);
2039 write_image(new_filename, image, size);
2040 }
2041
Bill XIEb3e15a22017-09-07 18:34:50 +08002042 if (mode_altmedisable) {
2043 fpsba_t *fpsba = find_fpsba(image, size);
2044 fmsba_t *fmsba = find_fmsba(image, size);
2045 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002046 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002047 }
2048
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002049 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002050 free(image);
2051
2052 return 0;
2053}