blob: ada120b0017a75bfe9bf39d40002097092007ad2 [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
Jeff Dalyabd4b962022-01-06 00:52:30 -050031/**
32 * PLATFORM_HAS_GBE_REGION - some platforms do not support the PCH GbE LAN region
33 */
34#define PLATFORM_HAS_GBE_REGION (platform != PLATFORM_DNV)
35
36/*
37 * PLATFORM_HAS_EC_REGION - some platforms do not support the EC region
38 */
39#define PLATFORM_HAS_EC_REGION (ifd_version >= IFD_VERSION_2 && platform != PLATFORM_DNV)
40
41/*
42 * PLATFORM_HAS_10GBE_X_REGION - some platforms have 1 or more 10GbE LAN regions
43 */
44#define PLATFORM_HAS_10GBE_0_REGION (platform == PLATFORM_DNV)
45#define PLATFORM_HAS_10GBE_1_REGION (platform == PLATFORM_DNV)
46
Maximilian Bruneab0e6802023-03-05 04:34:40 +010047static int max_regions_from_fdbar(const struct fdbar *fdb);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +020048
Duncan Laurie1f7fd722015-06-22 11:14:48 -070049static int ifd_version;
Bill XIEb3e15a22017-09-07 18:34:50 +080050static int chipset;
Bill XIEfa5f9942017-09-12 11:22:29 +080051static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010052static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070053static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050054
Duncan Laurie1f7fd722015-06-22 11:14:48 -070055static const struct region_name region_names[MAX_REGIONS] = {
Mathew Kingc7ddc992019-08-08 14:59:25 -060056 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin", "SI_DESC" },
57 { "BIOS", "bios", "flashregion_1_bios.bin", "SI_BIOS" },
58 { "Intel ME", "me", "flashregion_2_intel_me.bin", "SI_ME" },
59 { "GbE", "gbe", "flashregion_3_gbe.bin", "SI_GBE" },
60 { "Platform Data", "pd", "flashregion_4_platform_data.bin", "SI_PDR" },
Jeff Daly3623eca2022-01-05 23:51:40 -050061 { "Device Exp1", "devexp", "flashregion_5_device_exp.bin", "SI_DEVICEEXT" },
62 { "Secondary BIOS", "bios2", "flashregion_6_bios2.bin", "SI_BIOS2" },
63 { "Reserved", "res7", "flashregion_7_reserved.bin", NULL },
Mathew Kingc7ddc992019-08-08 14:59:25 -060064 { "EC", "ec", "flashregion_8_ec.bin", "SI_EC" },
Jeff Daly3623eca2022-01-05 23:51:40 -050065 { "Device Exp2", "devexp2", "flashregion_9_device_exp.bin", "SI_DEVICEEXT2" },
66 { "IE", "ie", "flashregion_10_ie.bin", "SI_IE" },
67 { "10GbE_0", "10gbe_0", "flashregion_11_10gbe0.bin", "SI_10GBE0" },
68 { "10GbE_1", "10gbe_1", "flashregion_12_10gbe1.bin", "SI_10GBE1" },
69 { "Reserved", "res13", "flashregion_13_reserved.bin", NULL },
70 { "Reserved", "res14", "flashregion_14_reserved.bin", NULL },
71 { "PTT", "ptt", "flashregion_15_ptt.bin", "SI_PTT" },
Chris Douglass03ce0142014-02-26 13:30:13 -050072};
73
Bill XIEb3e15a22017-09-07 18:34:50 +080074/* port from flashrom */
75static const char *const ich_chipset_names[] = {
76 "Unknown ICH",
Bill XIEb3e15a22017-09-07 18:34:50 +080077 "ICH8",
78 "ICH9",
79 "ICH10",
Subrata Banik89db2252020-08-26 14:49:17 +053080 "Unknown PCH",
Bill XIEb3e15a22017-09-07 18:34:50 +080081 "5 series Ibex Peak",
82 "6 series Cougar Point",
83 "7 series Panther Point",
84 "8 series Lynx Point",
85 "Baytrail",
86 "8 series Lynx Point LP",
87 "8 series Wellsburg",
88 "9 series Wildcat Point",
89 "9 series Wildcat Point LP",
Subrata Banik8c082e52021-06-10 23:02:29 +053090 "Apollo Lake: N3xxx, J3xxx",
Subrata Banik89db2252020-08-26 14:49:17 +053091 "Gemini Lake: N5xxx, J5xxx, N4xxx, J4xxx",
Subrata Banik8c082e52021-06-10 23:02:29 +053092 "Jasper Lake: N6xxx, N51xx, N45xx",
93 "Elkhart Lake: x6000 series Atom",
Subrata Banik89db2252020-08-26 14:49:17 +053094 "100/200 series Sunrise Point",
Subrata Banik8c082e52021-06-10 23:02:29 +053095 "300 series Cannon Point",
96 "400 series Ice Point",
Subrata Banika5f47812020-09-29 11:43:01 +053097 "500 series Tiger Point/ 600 series Alder Point",
Bill XIEb3e15a22017-09-07 18:34:50 +080098 "C620 series Lewisburg",
Patrick Rudolph19209002022-10-22 10:34:05 +020099 "Denverton: C39xx",
Bill XIEb3e15a22017-09-07 18:34:50 +0800100 NULL
101};
102
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100103static struct fdbar *find_fd(char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700104{
105 int i, found = 0;
106
107 /* Scan for FD signature */
108 for (i = 0; i < (size - 4); i += 4) {
109 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
110 found = 1;
111 break; // signature found.
112 }
113 }
114
115 if (!found) {
116 printf("No Flash Descriptor found in this image\n");
117 return NULL;
118 }
119
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100120 struct fdbar *fdb = (struct fdbar *) (image + i);
Bill XIE612ec0e2017-08-30 16:10:27 +0800121 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
122}
123
Stefan Tauner0d226142018-08-05 18:56:53 +0200124static char *find_flumap(char *image, int size)
125{
126 /* The upper map is located in the word before the 256B-long OEM section
127 * at the end of the 4kB-long flash descriptor. In the official
128 * documentation this is defined as FDBAR + 0xEFC. However, starting
129 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
130 * has moved 16 bytes back to offset 0x10 of the image. Although
131 * official documentation still maintains the offset relative to FDBAR
132 * this is wrong and a simple fixed offset from the start of the image
133 * works.
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100134 */
Stefan Tauner0d226142018-08-05 18:56:53 +0200135 char *flumap = image + 4096 - 256 - 4;
136 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
137}
138
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100139static struct fcba *find_fcba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800140{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100141 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800142 if (!fdb)
143 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100144 struct fcba *fcba = (struct fcba *) (image + ((fdb->flmap0 & 0xff) << 4));
Bill XIE612ec0e2017-08-30 16:10:27 +0800145 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
146
147}
148
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100149static struct fmba *find_fmba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800150{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100151 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800152 if (!fdb)
153 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100154 struct fmba *fmba = (struct fmba *) (image + ((fdb->flmap1 & 0xff) << 4));
Bill XIE612ec0e2017-08-30 16:10:27 +0800155 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
156}
157
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100158static struct frba *find_frba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800159{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100160 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800161 if (!fdb)
162 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100163 struct frba *frba =
164 (struct frba *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
Bill XIE612ec0e2017-08-30 16:10:27 +0800165 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
166}
167
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100168static struct fpsba *find_fpsba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800169{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100170 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800171 if (!fdb)
172 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100173 struct fpsba *fpsba =
174 (struct fpsba *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200175
176 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
177 if ((((char *)fpsba) + SSL) >= (image + size))
178 return NULL;
179 return fpsba;
Bill XIE612ec0e2017-08-30 16:10:27 +0800180}
181
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100182static struct fmsba *find_fmsba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800183{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100184 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800185 if (!fdb)
186 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100187 struct fmsba *fmsba = (struct fmsba *) (image + ((fdb->flmap2 & 0xff) << 4));
Bill XIE612ec0e2017-08-30 16:10:27 +0800188 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700189}
190
Bill XIEb3e15a22017-09-07 18:34:50 +0800191/* port from flashrom */
Subrata Banik8c082e52021-06-10 23:02:29 +0530192static enum ich_chipset ifd1_guess_chipset(char *image, int size)
Bill XIEb3e15a22017-09-07 18:34:50 +0800193{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100194 const struct fdbar *fdb = find_fd(image, size);
Subrata Banik8c082e52021-06-10 23:02:29 +0530195 if (!fdb)
196 exit(EXIT_FAILURE);
Bill XIEb3e15a22017-09-07 18:34:50 +0800197 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
198 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
199 uint32_t isl = (fdb->flmap1 >> 24);
Subrata Banik89db2252020-08-26 14:49:17 +0530200
201 /* Rest for IFD1 chipset type */
Bill XIEb3e15a22017-09-07 18:34:50 +0800202 if (iccriba == 0x00) {
203 if (msl == 0 && isl <= 2)
204 return CHIPSET_ICH8;
205 else if (isl <= 2)
206 return CHIPSET_ICH9;
207 else if (isl <= 10)
208 return CHIPSET_ICH10;
209 else if (isl <= 16)
210 return CHIPSET_5_SERIES_IBEX_PEAK;
211 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
212 return CHIPSET_5_SERIES_IBEX_PEAK;
213 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
214 if (msl == 0 && isl <= 17)
215 return CHIPSET_BAYTRAIL;
216 else if (msl <= 1 && isl <= 18)
217 return CHIPSET_6_SERIES_COUGAR_POINT;
218 else if (msl <= 1 && isl <= 21)
219 return CHIPSET_8_SERIES_LYNX_POINT;
220 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
221 return CHIPSET_9_SERIES_WILDCAT_POINT;
Bill XIEb3e15a22017-09-07 18:34:50 +0800222 }
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200223 return CHIPSET_PCH_UNKNOWN;
Bill XIEb3e15a22017-09-07 18:34:50 +0800224}
225
Subrata Banik8c082e52021-06-10 23:02:29 +0530226static enum ich_chipset ifd2_platform_to_chipset(const int pindex)
227{
228 switch (pindex) {
Subrata Banik6da003c2021-07-14 13:52:03 +0530229 case PLATFORM_APL:
230 return CHIPSET_N_J_SERIES_APOLLO_LAKE;
Subrata Banik8c082e52021-06-10 23:02:29 +0530231 case PLATFORM_GLK:
232 return CHIPSET_N_J_SERIES_GEMINI_LAKE;
233 case PLATFORM_JSL:
234 return CHIPSET_N_SERIES_JASPER_LAKE;
235 case PLATFORM_EHL:
236 return CHIPSET_x6000_SERIES_ELKHART_LAKE;
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200237 case PLATFORM_SKLKBL:
238 return CHIPSET_100_200_SERIES_SUNRISE_POINT;
Subrata Banik8c082e52021-06-10 23:02:29 +0530239 case PLATFORM_CNL:
240 return CHIPSET_300_SERIES_CANNON_POINT;
241 case PLATFORM_TGL:
242 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800243 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +0530244 case PLATFORM_MTL:
Subrata Banik8c082e52021-06-10 23:02:29 +0530245 return CHIPSET_500_600_SERIES_TIGER_ALDER_POINT;
246 case PLATFORM_ICL:
247 return CHIPSET_400_SERIES_ICE_POINT;
Johnny Line273a022021-06-22 11:26:46 +0800248 case PLATFORM_LBG:
249 return CHIPSET_C620_SERIES_LEWISBURG;
Jeff Dalyabd4b962022-01-06 00:52:30 -0500250 case PLATFORM_DNV:
251 return CHIPSET_DENVERTON;
Patrick Rudolph16598742022-10-21 15:13:43 +0200252 case PLATFORM_WBG:
253 return CHIPSET_8_SERIES_WELLSBURG;
Subrata Banik8c082e52021-06-10 23:02:29 +0530254 default:
255 return CHIPSET_PCH_UNKNOWN;
256 }
257}
258
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700259/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700260 * Some newer platforms have re-defined the FCBA field that was used to
261 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
262 * have the required FCBA field, but are IFD v2 and return true if current
263 * platform is one of them.
264 */
265static int is_platform_ifd_2(void)
266{
267 static const int ifd_2_platforms[] = {
Subrata Banik6da003c2021-07-14 13:52:03 +0530268 PLATFORM_APL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700269 PLATFORM_GLK,
270 PLATFORM_CNL,
Johnny Line273a022021-06-22 11:26:46 +0800271 PLATFORM_LBG,
Jeff Dalyabd4b962022-01-06 00:52:30 -0500272 PLATFORM_DNV,
Aamir Bohra1018be22018-06-29 15:08:50 +0530273 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700274 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530275 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700276 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530277 PLATFORM_ADL,
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200278 PLATFORM_SKLKBL,
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800279 PLATFORM_IFD2,
Subrata Banikca82e612022-01-20 18:51:21 +0530280 PLATFORM_MTL,
Patrick Rudolph16598742022-10-21 15:13:43 +0200281 PLATFORM_WBG,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700282 };
283 unsigned int i;
284
285 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
286 if (platform == ifd_2_platforms[i])
287 return 1;
288 }
289
290 return 0;
291}
292
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700293static void check_ifd_version(char *image, int size)
294{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100295 const struct fdbar *fdb = find_fd(image, size);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200296
Subrata Banik8c082e52021-06-10 23:02:29 +0530297 if (is_platform_ifd_2()) {
Subrata Banik8c082e52021-06-10 23:02:29 +0530298 chipset = ifd2_platform_to_chipset(platform);
Patrick Rudolph16598742022-10-21 15:13:43 +0200299 if (chipset == CHIPSET_8_SERIES_WELLSBURG)
300 ifd_version = IFD_VERSION_1_5;
301 else
302 ifd_version = IFD_VERSION_2;
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200303 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS);
Subrata Banik8c082e52021-06-10 23:02:29 +0530304 } else {
305 ifd_version = IFD_VERSION_1;
306 chipset = ifd1_guess_chipset(image, size);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200307 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS_OLD);
Subrata Banik8c082e52021-06-10 23:02:29 +0530308 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700309}
310
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100311static struct region get_region(const struct frba *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700312{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500313 int base_mask;
314 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700315 uint32_t flreg;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100316 struct region region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500317
318 if (ifd_version >= IFD_VERSION_2)
319 base_mask = 0x7fff;
320 else
321 base_mask = 0xfff;
322
323 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700324
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400325 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800326 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700327 exit (EXIT_FAILURE);
328 }
329
Bill XIE4651d452017-09-12 11:54:48 +0800330 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700331 region.base = (flreg & base_mask) << 12;
332 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700333 region.size = region.limit - region.base + 1;
Maximilian Brune347596a2023-03-05 20:55:32 +0100334 region.type = region_type;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500335
Chris Douglass03ce0142014-02-26 13:30:13 -0500336 if (region.size < 0)
337 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700338
339 return region;
340}
341
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100342static void set_region(struct frba *frba, unsigned int region_type,
343 const struct region *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500344{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400345 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800346 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500347 exit (EXIT_FAILURE);
348 }
Bill XIE4651d452017-09-12 11:54:48 +0800349
350 frba->flreg[region_type] =
351 (((region->limit >> 12) & 0x7fff) << 16) |
352 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500353}
354
Bill XIEfa5f9942017-09-12 11:22:29 +0800355static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700356{
Bill XIEfa5f9942017-09-12 11:22:29 +0800357 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700358 fprintf(stderr, "Invalid region type.\n");
359 exit (EXIT_FAILURE);
360 }
361
Chris Douglass03ce0142014-02-26 13:30:13 -0500362 return region_names[region_type].pretty;
363}
364
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500365static int region_num(const char *name)
366{
Bill XIEfa5f9942017-09-12 11:22:29 +0800367 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500368
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200369 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500370 if (strcasecmp(name, region_names[i].pretty) == 0)
371 return i;
372 if (strcasecmp(name, region_names[i].terse) == 0)
373 return i;
374 }
375
376 return -1;
377}
378
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100379static void dump_region(unsigned int num, const struct frba *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700380{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100381 struct region region = get_region(frba, num);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700382 printf(" Flash Region %d (%s): %08x - %08x %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100383 num, region_name(num), region.base, region.limit,
384 region.size < 1 ? "(unused)" : "");
Chris Douglass03ce0142014-02-26 13:30:13 -0500385}
386
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200387static int sort_compare(const void *a, const void *b)
388{
389 return *(size_t *)a - *(size_t *)b;
390}
391
392/*
393 * IFDv1 always has 8 regions, while IFDv2 always has 16 regions.
394 *
395 * It's platform specific which regions are used or are reserved.
396 * The 'SPI programming guide' as the name says is a guide only,
397 * not a specification what the hardware actually does.
398 * The best to do is not to rely on the guide, but detect how many
399 * regions are present in the IFD and expose them all.
400 *
401 * Very early IFDv2 chipsets, sometimes unofficially referred to as
402 * IFDv1.5 platforms, only have 8 regions. To not corrupt the IFD when
403 * operating on an IFDv1.5 detect how much space is actually present
404 * in the IFD.
405 */
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100406static int max_regions_from_fdbar(const struct fdbar *fdb)
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200407{
408 const size_t fcba = (fdb->flmap0 & 0xff) << 4;
409 const size_t fmba = (fdb->flmap1 & 0xff) << 4;
410 const size_t frba = ((fdb->flmap0 >> 16) & 0xff) << 4;
411 const size_t fpsba = ((fdb->flmap1 >> 16) & 0xff) << 4;
412 const size_t flumap = 4096 - 256 - 4;
413 size_t sorted[5] = {fcba, fmba, frba, fpsba, flumap};
414
415 qsort(sorted, ARRAY_SIZE(sorted), sizeof(size_t), sort_compare);
416
417 for (size_t i = 0; i < 4; i++) {
418 /*
419 * Find FRBA in the sorted array and determine the size of the
420 * region by the start of the next region. Every region requires
421 * 4 bytes of space.
422 */
423 if (sorted[i] == frba)
424 return MIN((sorted[i+1] - sorted[i])/4, MAX_REGIONS);
425 }
426 /* Never reaches this point */
427 return 0;
428}
429
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100430static void dump_frba(const struct frba *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700431{
Bill XIE4651d452017-09-12 11:54:48 +0800432 unsigned int i;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100433 struct region region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700434 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800435 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530436 region = get_region(frba, i);
437 /* Skip unused & reserved Flash Region */
438 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
439 continue;
440
Bill XIE4651d452017-09-12 11:54:48 +0800441 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
442 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700443 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700444}
445
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100446static void dump_flashrom_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500447{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100448 const struct frba *frba = find_frba(image, size);
449 if (!frba)
450 exit(EXIT_FAILURE);
Chris Douglass03ce0142014-02-26 13:30:13 -0500451
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100452 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
Chris Douglass03ce0142014-02-26 13:30:13 -0500453 if (layout_fd == -1) {
454 perror("Could not open file");
455 exit(EXIT_FAILURE);
456 }
457
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100458 for (unsigned int i = 0; i < max_regions; i++) {
459 struct region region = get_region(frba, i);
Maximilian Brune2c895aa2023-04-24 19:28:21 +0200460
461 /* A region limit of 0 is an indicator of an unused region
462 * A region base of 7FFFh is an indicator of a reserved region
463 */
464 if (region.limit == 0 || region.base == 0x07FFF000)
Alexander Couzenseff596b2016-10-08 00:53:09 +0200465 continue;
466
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100467 char buf[LAYOUT_LINELEN];
468 snprintf(buf, LAYOUT_LINELEN, "%08x:%08x %s\n", region.base, region.limit, region_names[i].terse);
Chris Douglass03ce0142014-02-26 13:30:13 -0500469 if (write(layout_fd, buf, strlen(buf)) < 0) {
470 perror("Could not write to file");
471 exit(EXIT_FAILURE);
472 }
473 }
474 close(layout_fd);
475 printf("Wrote layout to %s\n", layout_fname);
476}
477
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530478static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700479{
480 switch (freq) {
481 case SPI_FREQUENCY_20MHZ:
482 printf("20MHz");
483 break;
484 case SPI_FREQUENCY_33MHZ:
485 printf("33MHz");
486 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700487 case SPI_FREQUENCY_48MHZ:
488 printf("48MHz");
489 break;
490 case SPI_FREQUENCY_50MHZ_30MHZ:
491 switch (ifd_version) {
492 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +0200493 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700494 printf("50MHz");
495 break;
496 case IFD_VERSION_2:
497 printf("30MHz");
498 break;
499 }
500 break;
501 case SPI_FREQUENCY_17MHZ:
502 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700503 break;
504 default:
505 printf("unknown<%x>MHz", freq);
506 }
507}
508
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530509static void _decode_spi_frequency_500_series(unsigned int freq)
510{
511 switch (freq) {
512 case SPI_FREQUENCY_100MHZ:
513 printf("100MHz");
514 break;
515 case SPI_FREQUENCY_50MHZ:
516 printf("50MHz");
517 break;
518 case SPI_FREQUENCY_500SERIES_33MHZ:
519 printf("33MHz");
520 break;
521 case SPI_FREQUENCY_25MHZ:
522 printf("25MHz");
523 break;
524 case SPI_FREQUENCY_14MHZ:
525 printf("14MHz");
526 break;
527 default:
528 printf("unknown<%x>MHz", freq);
529 }
530}
531
532static void decode_spi_frequency(unsigned int freq)
533{
Subrata Banika5f47812020-09-29 11:43:01 +0530534 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530535 _decode_spi_frequency_500_series(freq);
536 else
537 _decode_spi_frequency(freq);
538}
539
Subrata Banike5d39922020-08-26 16:01:42 +0530540static void _decode_espi_frequency(unsigned int freq)
541{
542 switch (freq) {
543 case ESPI_FREQUENCY_20MHZ:
544 printf("20MHz");
545 break;
546 case ESPI_FREQUENCY_24MHZ:
547 printf("24MHz");
548 break;
549 case ESPI_FREQUENCY_30MHZ:
550 printf("30MHz");
551 break;
552 case ESPI_FREQUENCY_48MHZ:
553 printf("48MHz");
554 break;
555 case ESPI_FREQUENCY_60MHZ:
556 printf("60MHz");
557 break;
558 case ESPI_FREQUENCY_17MHZ:
559 printf("17MHz");
560 break;
561 default:
562 printf("unknown<%x>MHz", freq);
563 }
564}
565
566static void _decode_espi_frequency_500_series(unsigned int freq)
567{
568 switch (freq) {
569 case ESPI_FREQUENCY_500SERIES_20MHZ:
570 printf("20MHz");
571 break;
572 case ESPI_FREQUENCY_500SERIES_24MHZ:
573 printf("24MHz");
574 break;
575 case ESPI_FREQUENCY_500SERIES_25MHZ:
576 printf("25MHz");
577 break;
578 case ESPI_FREQUENCY_500SERIES_48MHZ:
579 printf("48MHz");
580 break;
581 case ESPI_FREQUENCY_500SERIES_60MHZ:
582 printf("60MHz");
583 break;
584 default:
585 printf("unknown<%x>MHz", freq);
586 }
587}
588
589static void decode_espi_frequency(unsigned int freq)
590{
Subrata Banika5f47812020-09-29 11:43:01 +0530591 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530592 _decode_espi_frequency_500_series(freq);
593 else
594 _decode_espi_frequency(freq);
595}
596
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700597static void decode_component_density(unsigned int density)
598{
599 switch (density) {
600 case COMPONENT_DENSITY_512KB:
601 printf("512KB");
602 break;
603 case COMPONENT_DENSITY_1MB:
604 printf("1MB");
605 break;
606 case COMPONENT_DENSITY_2MB:
607 printf("2MB");
608 break;
609 case COMPONENT_DENSITY_4MB:
610 printf("4MB");
611 break;
612 case COMPONENT_DENSITY_8MB:
613 printf("8MB");
614 break;
615 case COMPONENT_DENSITY_16MB:
616 printf("16MB");
617 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700618 case COMPONENT_DENSITY_32MB:
619 printf("32MB");
620 break;
621 case COMPONENT_DENSITY_64MB:
622 printf("64MB");
623 break;
624 case COMPONENT_DENSITY_UNUSED:
625 printf("UNUSED");
626 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700627 default:
628 printf("unknown<%x>MB", density);
629 }
630}
631
Subrata Banik26058dc2020-08-26 15:12:16 +0530632static int is_platform_with_pch(void)
633{
634 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
635 return 1;
636
637 return 0;
638}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530639
640/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
641static int is_platform_with_100x_series_pch(void)
642{
643 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530644 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530645 return 1;
646
647 return 0;
648}
649
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100650static void dump_fcba(const struct fcba *fcba, const struct fpsba *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700651{
Subrata Banike5d39922020-08-26 16:01:42 +0530652 unsigned int freq;
653
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700654 printf("\nFound Component Section\n");
655 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700656 printf(" Dual Output Fast Read Support: %ssupported\n",
657 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700658 printf(" Read ID/Read Status Clock Frequency: ");
659 decode_spi_frequency((fcba->flcomp >> 27) & 7);
660 printf("\n Write/Erase Clock Frequency: ");
661 decode_spi_frequency((fcba->flcomp >> 24) & 7);
662 printf("\n Fast Read Clock Frequency: ");
663 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700664 printf("\n Fast Read Support: %ssupported",
665 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530666 if (is_platform_with_100x_series_pch() &&
667 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
668 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530669 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530670 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
671 else
672 freq = (fcba->flcomp >> 17) & 7;
673 decode_espi_frequency(freq);
674 } else {
675 printf("\n Read Clock Frequency: ");
676 decode_spi_frequency((fcba->flcomp >> 17) & 7);
677 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700678
679 switch (ifd_version) {
680 case IFD_VERSION_1:
681 printf("\n Component 2 Density: ");
682 decode_component_density((fcba->flcomp >> 3) & 7);
683 printf("\n Component 1 Density: ");
684 decode_component_density(fcba->flcomp & 7);
685 break;
Patrick Rudolph16598742022-10-21 15:13:43 +0200686 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700687 case IFD_VERSION_2:
688 printf("\n Component 2 Density: ");
689 decode_component_density((fcba->flcomp >> 4) & 0xf);
690 printf("\n Component 1 Density: ");
691 decode_component_density(fcba->flcomp & 0xf);
692 break;
693 }
694
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700695 printf("\n");
696 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700697 printf(" Invalid Instruction 3: 0x%02x\n",
698 (fcba->flill >> 24) & 0xff);
699 printf(" Invalid Instruction 2: 0x%02x\n",
700 (fcba->flill >> 16) & 0xff);
701 printf(" Invalid Instruction 1: 0x%02x\n",
702 (fcba->flill >> 8) & 0xff);
703 printf(" Invalid Instruction 0: 0x%02x\n",
704 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530705 if (is_platform_with_100x_series_pch()) {
706 printf("FLILL1 0x%08x\n", fcba->flpb);
707 printf(" Invalid Instruction 7: 0x%02x\n",
708 (fcba->flpb >> 24) & 0xff);
709 printf(" Invalid Instruction 6: 0x%02x\n",
710 (fcba->flpb >> 16) & 0xff);
711 printf(" Invalid Instruction 5: 0x%02x\n",
712 (fcba->flpb >> 8) & 0xff);
713 printf(" Invalid Instruction 4: 0x%02x\n",
714 fcba->flpb & 0xff);
715 } else {
716 printf("FLPB 0x%08x\n", fcba->flpb);
717 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
718 (fcba->flpb & 0xfff) << 12);
719 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700720}
721
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100722static void dump_fpsba(const struct fdbar *fdb, const struct fpsba *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700723{
Bill XIE4651d452017-09-12 11:54:48 +0800724 unsigned int i;
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200725 /* SoC Straps, aka PSL, aka ISL */
726 unsigned int SS = (fdb->flmap1 >> 24) & 0xff;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200727
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700728 printf("Found PCH Strap Section\n");
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200729 for (i = 0; i < SS; i++)
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200730 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800731
732 if (ifd_version >= IFD_VERSION_2) {
733 printf("HAP bit is %sset\n",
734 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100735 } else if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
Bill XIEb3e15a22017-09-07 18:34:50 +0800736 printf("ICH_MeDisable bit is %sset\n",
737 fpsba->pchstrp[0] & 1 ? "" : "not ");
738 } else {
739 printf("AltMeDisable bit is %sset\n",
740 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
741 }
742
Bill XIE4651d452017-09-12 11:54:48 +0800743 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700744}
745
746static void decode_flmstr(uint32_t flmstr)
747{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700748 int wr_shift, rd_shift;
749 if (ifd_version >= IFD_VERSION_2) {
750 wr_shift = FLMSTR_WR_SHIFT_V2;
751 rd_shift = FLMSTR_RD_SHIFT_V2;
752 } else {
753 wr_shift = FLMSTR_WR_SHIFT_V1;
754 rd_shift = FLMSTR_RD_SHIFT_V1;
755 }
756
757 /* EC region access only available on v2+ */
Jeff Dalyabd4b962022-01-06 00:52:30 -0500758 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700759 printf(" EC Region Write Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100760 (flmstr & (1 << (wr_shift + 8))) ?
761 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700762 printf(" Platform Data Region Write Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100763 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500764 if (PLATFORM_HAS_GBE_REGION) {
765 printf(" GbE Region Write Access: %s\n",
766 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
767 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700768 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700769 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700770 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700771 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700772 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700773 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500774 if (PLATFORM_HAS_10GBE_0_REGION) {
775 printf(" 10GbE_0 Write Access: %s\n",
776 (flmstr & (1 << (wr_shift + 11))) ? "enabled" : "disabled");
777 }
778 if (PLATFORM_HAS_10GBE_1_REGION) {
779 printf(" 10GbE_1 Write Access: %s\n",
780 (flmstr & (1 << 4)) ? "enabled" : "disabled");
781 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700782
Jeff Dalyabd4b962022-01-06 00:52:30 -0500783 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700784 printf(" EC Region Read Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100785 (flmstr & (1 << (rd_shift + 8))) ?
786 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700787 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700788 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500789 if (PLATFORM_HAS_GBE_REGION) {
790 printf(" GbE Region Read Access: %s\n",
791 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
792 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700793 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700794 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700795 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700796 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700797 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700798 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500799 if (PLATFORM_HAS_10GBE_0_REGION) {
800 printf(" 10GbE_0 Read Access: %s\n",
801 (flmstr & (1 << (rd_shift + 11))) ? "enabled" : "disabled");
802 }
803 if (PLATFORM_HAS_10GBE_1_REGION) {
804 printf(" 10GbE_1 Read Access: %s\n",
805 (flmstr & (1 << 0)) ? "enabled" : "disabled");
806 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700807
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700808 /* Requestor ID doesn't exist for ifd 2 */
809 if (ifd_version < IFD_VERSION_2)
810 printf(" Requester ID: 0x%04x\n\n",
811 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700812}
813
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100814static void dump_fmba(const struct fmba *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700815{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700816 printf("Found Master Section\n");
817 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
818 decode_flmstr(fmba->flmstr1);
819 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
820 decode_flmstr(fmba->flmstr2);
Jeff Dalyabd4b962022-01-06 00:52:30 -0500821 if (PLATFORM_HAS_GBE_REGION) {
822 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
823 decode_flmstr(fmba->flmstr3);
824 if (ifd_version >= IFD_VERSION_2) {
825 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
826 decode_flmstr(fmba->flmstr5);
827 }
828 } else {
829 printf("FLMSTR6: 0x%08x (IE)\n", fmba->flmstr6);
830 decode_flmstr(fmba->flmstr6);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700831 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700832}
833
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100834static void dump_fmsba(const struct fmsba *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700835{
Bill XIE612ec0e2017-08-30 16:10:27 +0800836 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700837 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800838 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
839 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800840
841 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
842 printf("MCH_MeDisable bit is %sset\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100843 fmsba->data[0] & 1 ? "" : "not ");
Bill XIEb3e15a22017-09-07 18:34:50 +0800844 printf("MCH_AltMeDisable bit is %sset\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100845 fmsba->data[0] & (1 << 7) ? "" : "not ");
Bill XIEb3e15a22017-09-07 18:34:50 +0800846 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700847}
848
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700849static void dump_jid(uint32_t jid)
850{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100851 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700852 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100853 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200854 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100855 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200856 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700857}
858
859static void dump_vscc(uint32_t vscc)
860{
861 printf(" Lower Erase Opcode: 0x%02x\n",
862 vscc >> 24);
863 printf(" Lower Write Enable on Write Status: 0x%02x\n",
864 vscc & (1 << 20) ? 0x06 : 0x50);
865 printf(" Lower Write Status Required: %s\n",
866 vscc & (1 << 19) ? "Yes" : "No");
867 printf(" Lower Write Granularity: %d bytes\n",
868 vscc & (1 << 18) ? 64 : 1);
869 printf(" Lower Block / Sector Erase Size: ");
870 switch ((vscc >> 16) & 0x3) {
871 case 0:
872 printf("256 Byte\n");
873 break;
874 case 1:
875 printf("4KB\n");
876 break;
877 case 2:
878 printf("8KB\n");
879 break;
880 case 3:
881 printf("64KB\n");
882 break;
883 }
884
885 printf(" Upper Erase Opcode: 0x%02x\n",
886 (vscc >> 8) & 0xff);
887 printf(" Upper Write Enable on Write Status: 0x%02x\n",
888 vscc & (1 << 4) ? 0x06 : 0x50);
889 printf(" Upper Write Status Required: %s\n",
890 vscc & (1 << 3) ? "Yes" : "No");
891 printf(" Upper Write Granularity: %d bytes\n",
892 vscc & (1 << 2) ? 64 : 1);
893 printf(" Upper Block / Sector Erase Size: ");
894 switch (vscc & 0x3) {
895 case 0:
896 printf("256 Byte\n");
897 break;
898 case 1:
899 printf("4KB\n");
900 break;
901 case 2:
902 printf("8KB\n");
903 break;
904 case 3:
905 printf("64KB\n");
906 break;
907 }
908}
909
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100910static void dump_vtba(const struct vtba *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700911{
912 int i;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100913 int max_len = sizeof(struct vtba)/sizeof(struct vscc);
Stefan Tauner0d226142018-08-05 18:56:53 +0200914 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700915
916 printf("ME VSCC table:\n");
917 for (i = 0; i < num; i++) {
918 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
919 dump_jid(vtba->entry[i].jid);
920 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
921 dump_vscc(vtba->entry[i].vscc);
922 }
923 printf("\n");
924}
925
Bill XIEfa5f9942017-09-12 11:22:29 +0800926static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700927{
928 int i, j;
929 printf("OEM Section:\n");
930 for (i = 0; i < 4; i++) {
931 printf("%02x:", i << 4);
932 for (j = 0; j < 16; j++)
933 printf(" %02x", oem[(i<<4)+j]);
934 printf ("\n");
935 }
936 printf ("\n");
937}
938
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700939static void dump_fd(char *image, int size)
940{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100941 const struct fdbar *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700942 if (!fdb)
943 exit(EXIT_FAILURE);
944
Subrata Banik26058dc2020-08-26 15:12:16 +0530945 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
946 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700947 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530948 if (!is_platform_with_100x_series_pch())
949 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700950 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
951 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
952 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
953
954 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530955 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
956 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700957 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
958 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
959 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
960
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530961 if (!is_platform_with_100x_series_pch()) {
962 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
963 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
964 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
965 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700966
Subrata Banika5f47812020-09-29 11:43:01 +0530967 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530968 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
969 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
970 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
971 }
972
Stefan Tauner0d226142018-08-05 18:56:53 +0200973 char *flumap = find_flumap(image, size);
974 uint32_t flumap1 = *(uint32_t *)flumap;
975 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700976 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200977 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700978 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200979 (flumap1 & 0xff) << 4);
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100980 dump_vtba((struct vtba *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200981 (image + ((flumap1 & 0xff) << 4)),
982 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800983 dump_oem((const uint8_t *)image + 0xf00);
984
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100985 const struct frba *frba = find_frba(image, size);
986 const struct fcba *fcba = find_fcba(image, size);
987 const struct fpsba *fpsba = find_fpsba(image, size);
988 const struct fmba *fmba = find_fmba(image, size);
989 const struct fmsba *fmsba = find_fmsba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800990
991 if (frba && fcba && fpsba && fmba && fmsba) {
992 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +0530993 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200994 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800995 dump_fmba(fmba);
996 dump_fmsba(fmsba);
997 } else {
998 printf("FD is corrupted!\n");
999 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001000}
1001
Maximilian Brune347596a2023-03-05 20:55:32 +01001002/* Takes an image containing an IFD and creates a Flashmap .fmd file template.
1003 * This flashmap will contain all IFD regions except the BIOS region.
1004 * The BIOS region is created by coreboot itself and 'should' match the IFD region
1005 * anyway (CONFIG_VALIDATE_INTEL_DESCRIPTOR should make sure). coreboot built system will use
1006 * this template to generate the final Flashmap file.
1007 */
1008static void create_fmap_template(char *image, int size, const char *layout_fname)
1009{
1010 const struct frba *frba = find_frba(image, size);
1011 if (!frba)
1012 exit(EXIT_FAILURE);
1013
1014 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1015 if (layout_fd == -1) {
1016 perror("Could not open file");
1017 exit(EXIT_FAILURE);
1018 }
1019
1020 char *bbuf = "FLASH@##ROM_BASE## ##ROM_SIZE## {\n";
1021 if (write(layout_fd, bbuf, strlen(bbuf)) < 0) {
1022 perror("Could not write to file");
1023 exit(EXIT_FAILURE);
1024 }
1025
1026 /* fmaptool requires regions in .fmd to be sorted.
1027 * => We need to sort the regions by base address before writing them in .fmd File
1028 */
1029 int count_regions = 0;
1030 struct region sorted_regions[MAX_REGIONS] = { 0 };
1031 for (unsigned int i = 0; i < max_regions; i++) {
1032 struct region region = get_region(frba, i);
Maximilian Brune2c895aa2023-04-24 19:28:21 +02001033
1034 /* A region limit of 0 is an indicator of an unused region
1035 * A region base of 7FFFh is an indicator of a reserved region
1036 */
1037 if (region.limit == 0 || region.base == 0x07FFF000)
Maximilian Brune347596a2023-03-05 20:55:32 +01001038 continue;
1039
1040 /* Here we decide to use the coreboot generated FMAP BIOS region, instead of
1041 * the one specified in the IFD. The case when IFD and FMAP BIOS region do not
1042 * match cannot be caught here, therefore one should still validate IFD and
1043 * FMAP via CONFIG_VALIDATE_INTEL_DESCRIPTOR
1044 */
1045 if (i == REGION_BIOS)
1046 continue;
1047
1048 sorted_regions[count_regions] = region;
1049 // basically insertion sort
1050 for (int i = count_regions-1; i >= 0 ; i--) {
1051 if (sorted_regions[i].base > sorted_regions[i+1].base) {
1052 struct region tmp = sorted_regions[i];
1053 sorted_regions[i] = sorted_regions[i+1];
1054 sorted_regions[i+1] = tmp;
1055 }
1056 }
1057 count_regions++;
1058 }
1059
1060 // Now write regions sorted by base address in the fmap file
1061 for (int i = 0; i < count_regions; i++) {
1062 struct region region = sorted_regions[i];
1063 char buf[LAYOUT_LINELEN];
1064 snprintf(buf, LAYOUT_LINELEN, "\t%s@0x%X 0x%X\n", region_names[region.type].fmapname, region.base, region.size);
1065 if (write(layout_fd, buf, strlen(buf)) < 0) {
1066 perror("Could not write to file");
1067 exit(EXIT_FAILURE);
1068 }
1069 }
1070
1071 char *ebuf = "\tSI_BIOS@##BIOS_BASE## ##BIOS_SIZE## {\n"
1072 "\t\t##CONSOLE_ENTRY##\n"
1073 "\t\t##MRC_CACHE_ENTRY##\n"
1074 "\t\t##SMMSTORE_ENTRY##\n"
1075 "\t\t##SPD_CACHE_ENTRY##\n"
1076 "\t\t##VPD_ENTRY##\n"
1077 "\t\tFMAP@##FMAP_BASE## ##FMAP_SIZE##\n"
1078 "\t\tCOREBOOT(CBFS)@##CBFS_BASE## ##CBFS_SIZE##\n"
1079 "\t}\n"
1080 "}\n";
1081 if (write(layout_fd, ebuf, strlen(ebuf)) < 0) {
1082 perror("Could not write to file");
1083 exit(EXIT_FAILURE);
1084 }
1085
1086 close(layout_fd);
1087 printf("Wrote layout to %s\n", layout_fname);
1088}
1089
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001090static void write_regions(char *image, int size)
1091{
Bill XIEfa5f9942017-09-12 11:22:29 +08001092 unsigned int i;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001093 const struct frba *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001094
Bill XIE612ec0e2017-08-30 16:10:27 +08001095 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001096 exit(EXIT_FAILURE);
1097
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001098 for (i = 0; i < max_regions; i++) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001099 struct region region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001100 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001101 if (region.size > 0) {
1102 int region_fd;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001103 region_fd = open(region_names[i].filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001104 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001105 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001106 if (region_fd < 0) {
1107 perror("Error while trying to open file");
1108 exit(EXIT_FAILURE);
1109 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001110 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001111 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001112 close(region_fd);
1113 }
1114 }
1115}
1116
Mathew Kingc7ddc992019-08-08 14:59:25 -06001117static void validate_layout(char *image, int size)
1118{
1119 uint i, errors = 0;
1120 struct fmap *fmap;
1121 long int fmap_loc = fmap_find((uint8_t *)image, size);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001122 const struct frba *frba = find_frba(image, size);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001123
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001124 if (fmap_loc < 0 || !frba) {
1125 printf("Could not find FMAP (%p) or Intel Flash Descriptor (%p)\n",
1126 (void *)fmap_loc, frba);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001127 exit(EXIT_FAILURE);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001128 }
Mathew Kingc7ddc992019-08-08 14:59:25 -06001129
1130 fmap = (struct fmap *)(image + fmap_loc);
1131
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001132 int matches = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001133 for (i = 0; i < max_regions; i++) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001134 struct region region = get_region(frba, i);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001135 if (region.size == 0)
1136 continue;
1137
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001138 const struct fmap_area *area = fmap_find_area(fmap, region_names[i].fmapname);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001139 if (!area)
1140 continue;
1141
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001142 matches++; // found a match between FMAP and IFD region
1143
1144 if ((uint)region.base != area->offset || (uint)region.size != area->size) {
1145 printf("Region mismatch between %s and %s\n", region_names[i].terse, area->name);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001146 printf(" Descriptor region %s:\n", region_names[i].terse);
1147 printf(" offset: 0x%08x\n", region.base);
1148 printf(" length: 0x%08x\n", region.size);
1149 printf(" FMAP area %s:\n", area->name);
1150 printf(" offset: 0x%08x\n", area->offset);
1151 printf(" length: 0x%08x\n", area->size);
1152 errors++;
1153 }
1154 }
1155
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001156 if (!matches) {
1157 // At least a BIOS region should be present in both IFD and FMAP
1158 fprintf(stderr, "Warning: Not a single IFD region found in FMAP\n");
1159 }
1160
Mathew Kingc7ddc992019-08-08 14:59:25 -06001161 if (errors > 0)
1162 exit(EXIT_FAILURE);
1163}
1164
Bill XIEfa5f9942017-09-12 11:22:29 +08001165static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001166{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001167 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001168 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001169
1170 // Now write out new image
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001171 new_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001172 if (new_fd < 0) {
1173 perror("Error while trying to open file");
1174 exit(EXIT_FAILURE);
1175 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001176 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001177 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001178 close(new_fd);
1179}
1180
Bill XIEfa5f9942017-09-12 11:22:29 +08001181static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001182 enum spi_frequency freq)
1183{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001184 struct fcba *fcba = find_fcba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001185 if (!fcba)
1186 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001187
1188 /* clear bits 21-29 */
1189 fcba->flcomp &= ~0x3fe00000;
1190 /* Read ID and Read Status Clock Frequency */
1191 fcba->flcomp |= freq << 27;
1192 /* Write and Erase Clock Frequency */
1193 fcba->flcomp |= freq << 24;
1194 /* Fast Read Clock Frequency */
1195 fcba->flcomp |= freq << 21;
1196
1197 write_image(filename, image, size);
1198}
1199
Bill XIEfa5f9942017-09-12 11:22:29 +08001200static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001201{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001202 struct fcba *fcba = find_fcba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001203 if (!fcba)
1204 exit(EXIT_FAILURE);
1205
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001206 int freq;
1207
1208 switch (ifd_version) {
1209 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +02001210 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001211 freq = SPI_FREQUENCY_20MHZ;
1212 break;
1213 case IFD_VERSION_2:
1214 freq = SPI_FREQUENCY_17MHZ;
1215 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001216 default:
1217 freq = SPI_FREQUENCY_17MHZ;
1218 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001219 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001220
1221 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001222 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001223}
1224
Bill XIEfa5f9942017-09-12 11:22:29 +08001225static void set_chipdensity(const char *filename, char *image, int size,
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001226 unsigned int density)
Jan Tatjefa317512016-03-11 00:52:07 +01001227{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001228 struct fcba *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001229 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001230 if (!fcba)
1231 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001232
1233 printf("Setting chip density to ");
1234 decode_component_density(density);
1235 printf("\n");
1236
1237 switch (ifd_version) {
1238 case IFD_VERSION_1:
1239 /* fail if selected density is not supported by this version */
1240 if ( (density == COMPONENT_DENSITY_32MB) ||
1241 (density == COMPONENT_DENSITY_64MB) ||
1242 (density == COMPONENT_DENSITY_UNUSED) ) {
1243 printf("error: Selected density not supported in IFD version 1.\n");
1244 exit(EXIT_FAILURE);
1245 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001246 mask = 0x7;
1247 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001248 break;
Patrick Rudolph16598742022-10-21 15:13:43 +02001249 case IFD_VERSION_1_5:
Jan Tatjefa317512016-03-11 00:52:07 +01001250 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001251 mask = 0xf;
1252 chip2_offset = 4;
1253 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001254 default:
1255 printf("error: Unknown IFD version\n");
1256 exit(EXIT_FAILURE);
1257 break;
1258 }
1259
1260 /* clear chip density for corresponding chip */
1261 switch (selected_chip) {
1262 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001263 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001264 break;
1265 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001266 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001267 break;
1268 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001269 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001270 break;
1271 }
1272
1273 /* set the new density */
1274 if (selected_chip == 1 || selected_chip == 0)
1275 fcba->flcomp |= (density); /* first chip */
1276 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001277 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001278
1279 write_image(filename, image, size);
1280}
1281
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001282static int check_region(const struct frba *frba, unsigned int region_type)
Duncan Laurie7775d672019-06-06 13:39:26 -07001283{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001284 struct region region;
Duncan Laurie7775d672019-06-06 13:39:26 -07001285
1286 if (!frba)
1287 return 0;
1288
1289 region = get_region(frba, region_type);
1290 return !!((region.base < region.limit) && (region.size > 0));
1291}
1292
Bill XIEfa5f9942017-09-12 11:22:29 +08001293static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001294{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001295 int wr_shift, rd_shift;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001296 struct fmba *fmba = find_fmba(image, size);
1297 const struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001298 if (!fmba)
1299 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001300
1301 if (ifd_version >= IFD_VERSION_2) {
1302 wr_shift = FLMSTR_WR_SHIFT_V2;
1303 rd_shift = FLMSTR_RD_SHIFT_V2;
1304
1305 /* Clear non-reserved bits */
1306 fmba->flmstr1 &= 0xff;
1307 fmba->flmstr2 &= 0xff;
1308 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001309 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001310 } else {
1311 wr_shift = FLMSTR_WR_SHIFT_V1;
1312 rd_shift = FLMSTR_RD_SHIFT_V1;
1313
1314 fmba->flmstr1 = 0;
1315 fmba->flmstr2 = 0;
1316 /* Requestor ID */
1317 fmba->flmstr3 = 0x118;
1318 }
1319
Andrey Petrov96ecb772016-10-31 19:31:54 -07001320 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001321 case PLATFORM_APL:
1322 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001323 /* CPU/BIOS can read descriptor and BIOS */
1324 fmba->flmstr1 |= 0x3 << rd_shift;
1325 /* CPU/BIOS can write BIOS */
1326 fmba->flmstr1 |= 0x2 << wr_shift;
1327 /* TXE can read descriptor, BIOS and Device Expansion */
1328 fmba->flmstr2 |= 0x23 << rd_shift;
1329 /* TXE can only write Device Expansion */
1330 fmba->flmstr2 |= 0x20 << wr_shift;
1331 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001332 case PLATFORM_CNL:
1333 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001334 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001335 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301336 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001337 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301338 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001339 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +05301340 case PLATFORM_MTL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001341 /* CPU/BIOS can read descriptor and BIOS. */
1342 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1343 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1344 /* CPU/BIOS can write BIOS. */
1345 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1346 /* ME can read descriptor and ME. */
1347 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1348 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001349 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001350 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1351 if (check_region(frba, REGION_GBE)) {
1352 /* BIOS can read/write GbE. */
1353 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1354 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1355 /* ME can read GbE. */
1356 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1357 /* GbE can read descriptor and read/write GbE.. */
1358 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1359 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1360 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1361 }
1362 if (check_region(frba, REGION_PDR)) {
1363 /* BIOS can read/write PDR. */
1364 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1365 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1366 }
1367 if (check_region(frba, REGION_EC)) {
1368 /* BIOS can read EC. */
1369 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1370 /* EC can read descriptor and read/write EC. */
1371 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1372 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1373 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1374 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001375 break;
Jeff Dalyabd4b962022-01-06 00:52:30 -05001376 case PLATFORM_DNV:
Patrick Rudolph16598742022-10-21 15:13:43 +02001377 case PLATFORM_WBG:
Jeff Dalyabd4b962022-01-06 00:52:30 -05001378 /* CPU/BIOS can read descriptor and BIOS. */
1379 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1380 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1381 /* CPU/BIOS can write BIOS. */
1382 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1383 /* ME can read descriptor and ME. */
1384 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1385 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1386 /* ME can write ME. */
1387 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1388 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001389 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001390 /* CPU/BIOS can read descriptor and BIOS. */
1391 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1392 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1393 /* CPU/BIOS can write BIOS. */
1394 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1395 /* ME can read descriptor and ME. */
1396 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1397 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1398 /* ME can write ME. */
1399 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1400 if (check_region(frba, REGION_GBE)) {
1401 /* BIOS can read GbE. */
1402 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1403 /* BIOS can write GbE. */
1404 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1405 /* ME can read GbE. */
1406 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1407 /* ME can write GbE. */
1408 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1409 /* GbE can write GbE. */
1410 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1411 /* GbE can read GbE. */
1412 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1413 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001414 break;
1415 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001416
1417 write_image(filename, image, size);
1418}
1419
Usha P412679d2020-10-15 11:25:08 +05301420static void enable_cpu_read_me(const char *filename, char *image, int size)
1421{
1422 int rd_shift;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001423 struct fmba *fmba = find_fmba(image, size);
Usha P412679d2020-10-15 11:25:08 +05301424
1425 if (!fmba)
1426 exit(EXIT_FAILURE);
1427
1428 if (ifd_version >= IFD_VERSION_2)
1429 rd_shift = FLMSTR_RD_SHIFT_V2;
1430 else
1431 rd_shift = FLMSTR_RD_SHIFT_V1;
1432
1433 /* CPU/BIOS can read ME. */
1434 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1435
1436 write_image(filename, image, size);
1437}
1438
Bill XIEfa5f9942017-09-12 11:22:29 +08001439static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001440{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001441 struct fmba *fmba = find_fmba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001442 if (!fmba)
1443 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001444
1445 if (ifd_version >= IFD_VERSION_2) {
1446 /* Access bits for each region are read: 19:8 write: 31:20 */
1447 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1448 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1449 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001450 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001451 } else {
1452 fmba->flmstr1 = 0xffff0000;
1453 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001454 /* Keep chipset specific Requester ID */
1455 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001456 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001457
1458 write_image(filename, image, size);
1459}
1460
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001461static void set_pchstrap(struct fpsba *fpsba, const struct fdbar *fdb, const int strap,
1462 const unsigned int value)
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001463{
1464 if (!fpsba || !fdb) {
1465 fprintf(stderr, "Internal error\n");
1466 exit(EXIT_FAILURE);
1467 }
1468
Arthur Heymans0424a2c2021-06-22 11:14:24 +02001469 /* SoC Strap, aka PSL, aka ISL */
1470 int SS = (fdb->flmap1 >> 24) & 0xff;
1471 if (strap >= SS) {
1472 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SS);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001473 exit(EXIT_FAILURE);
1474 }
1475 fpsba->pchstrp[strap] = value;
1476}
1477
Bill XIEb3e15a22017-09-07 18:34:50 +08001478/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001479static void fpsba_set_altmedisable(struct fpsba *fpsba, struct fmsba *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001480{
1481 if (ifd_version >= IFD_VERSION_2) {
1482 printf("%sting the HAP bit to %s Intel ME...\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001483 altmedisable?"Set":"Unset",
1484 altmedisable?"disable":"enable");
Bill XIEb3e15a22017-09-07 18:34:50 +08001485 if (altmedisable)
1486 fpsba->pchstrp[0] |= (1 << 16);
1487 else
1488 fpsba->pchstrp[0] &= ~(1 << 16);
1489 } else {
1490 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1491 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1492 "and MCH_AltMeDisable to %s Intel ME...\n",
1493 altmedisable?"Set":"Unset",
1494 altmedisable?"disable":"enable");
1495 if (altmedisable) {
1496 /* MCH_MeDisable */
1497 fmsba->data[0] |= 1;
1498 /* MCH_AltMeDisable */
1499 fmsba->data[0] |= (1 << 7);
1500 /* ICH_MeDisable */
1501 fpsba->pchstrp[0] |= 1;
1502 } else {
1503 fmsba->data[0] &= ~1;
1504 fmsba->data[0] &= ~(1 << 7);
1505 fpsba->pchstrp[0] &= ~1;
1506 }
1507 } else {
1508 printf("%sting the AltMeDisable to %s Intel ME...\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001509 altmedisable?"Set":"Unset",
1510 altmedisable?"disable":"enable");
Bill XIEb3e15a22017-09-07 18:34:50 +08001511 if (altmedisable)
1512 fpsba->pchstrp[10] |= (1 << 7);
1513 else
1514 fpsba->pchstrp[10] &= ~(1 << 7);
1515 }
1516 }
1517}
1518
Jacob Garber595d9262019-06-27 17:33:10 -06001519static void inject_region(const char *filename, char *image, int size,
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001520 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001521{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001522 struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001523 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001524 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001525
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001526 struct region region = get_region(frba, region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001527 if (region.size <= 0xfff) {
1528 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1529 region_name(region_type));
1530 exit(EXIT_FAILURE);
1531 }
1532
Scott Duplichanf2c98372014-12-12 21:03:06 -06001533 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001534 if (region_fd == -1) {
1535 perror("Could not open file");
1536 exit(EXIT_FAILURE);
1537 }
1538 struct stat buf;
1539 if (fstat(region_fd, &buf) == -1) {
1540 perror("Could not stat file");
1541 exit(EXIT_FAILURE);
1542 }
1543 int region_size = buf.st_size;
1544
1545 printf("File %s is %d bytes\n", region_fname, region_size);
1546
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001547 if (region_size > region.size) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001548 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1549 " bytes. Not injecting.\n",
1550 region_name(region_type), region.size,
1551 region.size, region_size, region_size);
1552 exit(EXIT_FAILURE);
1553 }
1554
1555 int offset = 0;
1556 if ((region_type == 1) && (region_size < region.size)) {
1557 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1558 " bytes. Padding before injecting.\n",
1559 region_name(region_type), region.size,
1560 region.size, region_size, region_size);
1561 offset = region.size - region_size;
1562 memset(image + region.base, 0xff, offset);
1563 }
1564
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001565 if (size < region.base + offset + region_size) {
1566 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1567 size, region.base + offset + region_size);
1568 exit(EXIT_FAILURE);
1569 }
1570
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001571 if (read(region_fd, image + region.base + offset, region_size) != region_size) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001572 perror("Could not read file");
1573 exit(EXIT_FAILURE);
1574 }
1575
1576 close(region_fd);
1577
1578 printf("Adding %s as the %s section of %s\n",
1579 region_fname, region_name(region_type), filename);
1580 write_image(filename, image, size);
1581}
1582
Jacob Garber595d9262019-06-27 17:33:10 -06001583static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001584{
1585 unsigned int y = 1;
1586 if (x == 0)
1587 return 0;
1588 while (y <= x)
1589 y = y << 1;
1590
1591 return y;
1592}
1593
1594/**
1595 * Determine if two memory regions overlap.
1596 *
1597 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001598 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001599 * @return 1 if the two regions overlap
1600 */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001601static int regions_collide(const struct region *r1, const struct region *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001602{
Bill XIEfa5f9942017-09-12 11:22:29 +08001603 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001604 return 0;
1605
Nico Huber844eda02019-01-05 00:06:19 +01001606 /* r1 should be either completely below or completely above r2 */
1607 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001608}
1609
Jacob Garber595d9262019-06-27 17:33:10 -06001610static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001611 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001612{
1613 FILE *romlayout;
1614 char tempstr[256];
1615 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001616 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001617 int region_number;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001618 struct region current_regions[MAX_REGIONS];
1619 struct region new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001620 int new_extent = 0;
1621 char *new_image;
1622
1623 /* load current descriptor map and regions */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001624 struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001625 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001626 exit(EXIT_FAILURE);
1627
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001628 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001629 current_regions[i] = get_region(frba, i);
1630 new_regions[i] = get_region(frba, i);
1631 }
1632
1633 /* read new layout */
1634 romlayout = fopen(layout_fname, "r");
1635
1636 if (!romlayout) {
1637 perror("Could not read layout file.\n");
1638 exit(EXIT_FAILURE);
1639 }
1640
1641 while (!feof(romlayout)) {
1642 char *tstr1, *tstr2;
1643
Patrick Georgi802ad522014-08-09 17:12:23 +02001644 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001645 layout_region_name))
1646 continue;
1647
1648 region_number = region_num(layout_region_name);
1649 if (region_number < 0)
1650 continue;
1651
1652 tstr1 = strtok(tempstr, ":");
1653 tstr2 = strtok(NULL, ":");
1654 if (!tstr1 || !tstr2) {
1655 fprintf(stderr, "Could not parse layout file.\n");
1656 exit(EXIT_FAILURE);
1657 }
1658 new_regions[region_number].base = strtol(tstr1,
1659 (char **)NULL, 16);
1660 new_regions[region_number].limit = strtol(tstr2,
1661 (char **)NULL, 16);
1662 new_regions[region_number].size =
1663 new_regions[region_number].limit -
1664 new_regions[region_number].base + 1;
1665
1666 if (new_regions[region_number].size < 0)
1667 new_regions[region_number].size = 0;
1668 }
1669 fclose(romlayout);
1670
1671 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001672 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001673 if (new_regions[i].size == 0)
1674 continue;
1675
1676 if (new_regions[i].size < current_regions[i].size) {
1677 printf("DANGER: Region %s is shrinking.\n",
1678 region_name(i));
1679 printf(" The region will be truncated to fit.\n");
1680 printf(" This may result in an unusable image.\n");
1681 }
1682
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001683 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001684 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001685 fprintf(stderr, "Regions would overlap.\n");
1686 exit(EXIT_FAILURE);
1687 }
1688 }
1689
1690 /* detect if the image size should grow */
1691 if (new_extent < new_regions[i].limit)
1692 new_extent = new_regions[i].limit;
1693 }
1694
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001695 /* check if the image is actually a Flash Descriptor region */
1696 if (size == new_regions[0].size) {
1697 printf("The image is a single Flash Descriptor:\n");
1698 printf(" Only the descriptor will be modified\n");
1699 new_extent = size;
1700 } else {
1701 new_extent = next_pow2(new_extent - 1);
1702 if (new_extent != size) {
1703 printf("The image has changed in size.\n");
1704 printf("The old image is %d bytes.\n", size);
1705 printf("The new image is %d bytes.\n", new_extent);
1706 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001707 }
1708
1709 /* copy regions to a new image */
1710 new_image = malloc(new_extent);
1711 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001712 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001713 int copy_size = new_regions[i].size;
1714 int offset_current = 0, offset_new = 0;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001715 const struct region *current = &current_regions[i];
1716 const struct region *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001717
Bill XIEfa5f9942017-09-12 11:22:29 +08001718 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001719 continue;
1720
Bill XIEfa5f9942017-09-12 11:22:29 +08001721 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001722 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001723 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001724 if (i == REGION_BIOS)
1725 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001726 }
1727
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001728 if ((i == REGION_BIOS) && (new->size < current->size)) {
1729 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001730 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001731 }
1732
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001733 if (size < current->base + offset_current + copy_size) {
1734 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1735 region_name(i));
1736 continue;
1737 };
1738
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001739 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1740 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001741 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1742 offset_current, current->limit, current->size);
1743 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1744 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001745
Bill XIEfa5f9942017-09-12 11:22:29 +08001746 memcpy(new_image + new->base + offset_new,
1747 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001748 copy_size);
1749 }
1750
1751 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001752 frba = find_frba(new_image, new_extent);
1753 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001754 exit(EXIT_FAILURE);
1755
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001756 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001757 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001758 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001759
1760 write_image(filename, new_image, new_extent);
1761 free(new_image);
1762}
1763
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001764static void print_version(void)
1765{
1766 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1767 printf("Copyright (C) 2011 Google Inc.\n\n");
1768 printf
1769 ("This program is free software: you can redistribute it and/or modify\n"
1770 "it under the terms of the GNU General Public License as published by\n"
1771 "the Free Software Foundation, version 2 of the License.\n\n"
1772 "This program is distributed in the hope that it will be useful,\n"
1773 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1774 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001775 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001776}
1777
1778static void print_usage(const char *name)
1779{
1780 printf("usage: %s [-vhdix?] <filename>\n", name);
1781 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001782 " -d | --dump: dump intel firmware descriptor\n"
1783 " -f | --layout <filename> dump regions into a flashrom layout file\n"
Maximilian Brune347596a2023-03-05 20:55:32 +01001784 " -F | --fmap-layout <filename> dump IFD regions into a fmap layout template (.fmd) file\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001785 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1786 " -x | --extract: extract intel fd modules\n"
1787 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1788 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001789 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001790 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1791 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1792 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1793 " can only be used once per run:\n"
1794 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1795 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1796 " Dual Output Fast Read Support\n"
1797 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301798 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001799 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001800 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1801 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001802 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301803 " adl - Alder Lake\n"
1804 " aplk - Apollo Lake\n"
1805 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08001806 " lbg - Lewisburg PCH\n"
Jeff Dalyabd4b962022-01-06 00:52:30 -05001807 " dnv - Denverton\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001808 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301809 " glk - Gemini Lake\n"
1810 " icl - Ice Lake\n"
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001811 " ifd2 - IFDv2 Platform\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301812 " jsl - Jasper Lake\n"
1813 " sklkbl - Sky Lake/Kaby Lake\n"
1814 " tgl - Tiger Lake\n"
Patrick Rudolph16598742022-10-21 15:13:43 +02001815 " wbg - Wellsburg\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001816 " -S | --setpchstrap Write a PCH strap\n"
1817 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001818 " -v | --version: print the version\n"
1819 " -h | --help: print this help\n\n"
Jeff Daly3623eca2022-01-05 23:51:40 -05001820 "<region> is one of Descriptor, BIOS, ME, GbE, Platform Data, Secondary BIOS, "
1821 "Device Exp1, EC, Device Exp2, IE, 10GbE_0, 10GbE_1, PTT\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001822 "\n");
1823}
1824
1825int main(int argc, char *argv[])
1826{
1827 int opt, option_index = 0;
1828 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001829 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001830 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Maximilian Brune347596a2023-03-05 20:55:32 +01001831 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0, mode_fmap_template = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001832 char *region_type_string = NULL, *region_fname = NULL;
1833 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001834 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001835 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001836 unsigned int value = 0;
1837 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001838 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001839 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1840
Bill XIEfa5f9942017-09-12 11:22:29 +08001841 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001842 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001843 {"layout", 1, NULL, 'f'},
Maximilian Brune347596a2023-03-05 20:55:32 +01001844 {"fmap-template", 1, NULL, 'F'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001845 {"extract", 0, NULL, 'x'},
1846 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001847 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001848 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001849 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001850 {"density", 1, NULL, 'D'},
1851 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001852 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001853 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001854 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301855 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001856 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001857 {"version", 0, NULL, 'v'},
1858 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001859 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001860 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001861 {"setpchstrap", 1, NULL, 'S'},
1862 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001863 {0, 0, 0, 0}
1864 };
1865
Maximilian Brune347596a2023-03-05 20:55:32 +01001866 while ((opt = getopt_long(argc, argv, "S:V:df:F:D:C:M:xi:n:O:s:p:elruvth?",
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001867 long_options, &option_index)) != EOF) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001868 switch (opt) {
1869 case 'd':
1870 mode_dump = 1;
1871 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001872 case 'S':
1873 mode_setstrap = 1;
1874 pchstrap = strtoul(optarg, NULL, 0);
1875 break;
1876 case 'V':
1877 value = strtoul(optarg, NULL, 0);
1878 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001879 case 'f':
1880 mode_layout = 1;
1881 layout_fname = strdup(optarg);
1882 if (!layout_fname) {
1883 fprintf(stderr, "No layout file specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001884 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Chris Douglass03ce0142014-02-26 13:30:13 -05001885 exit(EXIT_FAILURE);
1886 }
1887 break;
Maximilian Brune347596a2023-03-05 20:55:32 +01001888 case 'F':
1889 mode_fmap_template = 1;
1890 layout_fname = strdup(optarg);
1891 if (!layout_fname) {
1892 fprintf(stderr, "No layout file specified\n");
1893 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
1894 exit(EXIT_FAILURE);
1895 }
1896 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001897 case 'x':
1898 mode_extract = 1;
1899 break;
1900 case 'i':
1901 // separate type and file name
1902 region_type_string = strdup(optarg);
1903 region_fname = strchr(region_type_string, ':');
1904 if (!region_fname) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001905 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001906 exit(EXIT_FAILURE);
1907 }
1908 region_fname[0] = '\0';
1909 region_fname++;
1910 // Descriptor, BIOS, ME, GbE, Platform
1911 // valid type?
1912 if (!strcasecmp("Descriptor", region_type_string))
1913 region_type = 0;
1914 else if (!strcasecmp("BIOS", region_type_string))
1915 region_type = 1;
1916 else if (!strcasecmp("ME", region_type_string))
1917 region_type = 2;
1918 else if (!strcasecmp("GbE", region_type_string))
1919 region_type = 3;
Jeff Daly3623eca2022-01-05 23:51:40 -05001920 else if (!strcasecmp("Platform Data", region_type_string))
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001921 region_type = 4;
Jeff Daly3623eca2022-01-05 23:51:40 -05001922 else if (!strcasecmp("Device Exp1", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001923 region_type = 5;
Jeff Daly3623eca2022-01-05 23:51:40 -05001924 else if (!strcasecmp("Secondary BIOS", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001925 region_type = 6;
Jeff Daly3623eca2022-01-05 23:51:40 -05001926 else if (!strcasecmp("Reserved", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001927 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001928 else if (!strcasecmp("EC", region_type_string))
1929 region_type = 8;
Jeff Daly3623eca2022-01-05 23:51:40 -05001930 else if (!strcasecmp("Device Exp2", region_type_string))
1931 region_type = 9;
1932 else if (!strcasecmp("IE", region_type_string))
1933 region_type = 10;
1934 else if (!strcasecmp("10GbE_0", region_type_string))
1935 region_type = 11;
1936 else if (!strcasecmp("10GbE_1", region_type_string))
1937 region_type = 12;
1938 else if (!strcasecmp("PTT", region_type_string))
1939 region_type = 15;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001940 if (region_type == -1) {
1941 fprintf(stderr, "No such region type: '%s'\n\n",
1942 region_type_string);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001943 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001944 exit(EXIT_FAILURE);
1945 }
1946 mode_inject = 1;
1947 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001948 case 'n':
1949 mode_newlayout = 1;
1950 layout_fname = strdup(optarg);
1951 if (!layout_fname) {
1952 fprintf(stderr, "No layout file specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001953 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001954 exit(EXIT_FAILURE);
1955 }
1956 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001957 case 'O':
1958 new_filename = strdup(optarg);
1959 if (!new_filename) {
1960 fprintf(stderr, "No output filename specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001961 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001962 exit(EXIT_FAILURE);
1963 }
1964 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001965 case 'D':
1966 mode_density = 1;
1967 new_density = strtoul(optarg, NULL, 0);
1968 switch (new_density) {
1969 case 512:
1970 new_density = COMPONENT_DENSITY_512KB;
1971 break;
1972 case 1:
1973 new_density = COMPONENT_DENSITY_1MB;
1974 break;
1975 case 2:
1976 new_density = COMPONENT_DENSITY_2MB;
1977 break;
1978 case 4:
1979 new_density = COMPONENT_DENSITY_4MB;
1980 break;
1981 case 8:
1982 new_density = COMPONENT_DENSITY_8MB;
1983 break;
1984 case 16:
1985 new_density = COMPONENT_DENSITY_16MB;
1986 break;
1987 case 32:
1988 new_density = COMPONENT_DENSITY_32MB;
1989 break;
1990 case 64:
1991 new_density = COMPONENT_DENSITY_64MB;
1992 break;
1993 case 0:
1994 new_density = COMPONENT_DENSITY_UNUSED;
1995 break;
1996 default:
1997 printf("error: Unknown density\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001998 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Jan Tatjefa317512016-03-11 00:52:07 +01001999 exit(EXIT_FAILURE);
2000 }
2001 break;
2002 case 'C':
2003 selected_chip = strtol(optarg, NULL, 0);
2004 if (selected_chip > 2) {
2005 fprintf(stderr, "error: Invalid chip selection\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002006 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Jan Tatjefa317512016-03-11 00:52:07 +01002007 exit(EXIT_FAILURE);
2008 }
2009 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08002010 case 'M':
2011 mode_altmedisable = 1;
2012 altmedisable = strtol(optarg, NULL, 0);
2013 if (altmedisable > 1) {
2014 fprintf(stderr, "error: Illegal value\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002015 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Bill XIEb3e15a22017-09-07 18:34:50 +08002016 exit(EXIT_FAILURE);
2017 }
2018 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002019 case 's':
2020 // Parse the requested SPI frequency
2021 inputfreq = strtol(optarg, NULL, 0);
2022 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002023 case 17:
2024 spifreq = SPI_FREQUENCY_17MHZ;
2025 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002026 case 20:
2027 spifreq = SPI_FREQUENCY_20MHZ;
2028 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002029 case 30:
2030 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
2031 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002032 case 33:
2033 spifreq = SPI_FREQUENCY_33MHZ;
2034 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002035 case 48:
2036 spifreq = SPI_FREQUENCY_48MHZ;
2037 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002038 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002039 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002040 break;
2041 default:
2042 fprintf(stderr, "Invalid SPI Frequency: %d\n",
2043 inputfreq);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002044 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002045 exit(EXIT_FAILURE);
2046 }
2047 mode_spifreq = 1;
2048 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002049 case 'e':
2050 mode_em100 = 1;
2051 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002052 case 'l':
2053 mode_locked = 1;
2054 if (mode_unlocked == 1) {
2055 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
2056 exit(EXIT_FAILURE);
2057 }
2058 break;
Usha P412679d2020-10-15 11:25:08 +05302059 case 'r':
2060 mode_read = 1;
2061 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002062 case 'u':
2063 mode_unlocked = 1;
2064 if (mode_locked == 1) {
2065 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
2066 exit(EXIT_FAILURE);
2067 }
2068 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002069 case 'p':
2070 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002071 platform = PLATFORM_APL;
2072 } else if (!strcmp(optarg, "cnl")) {
2073 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08002074 } else if (!strcmp(optarg, "lbg")) {
2075 platform = PLATFORM_LBG;
Jeff Dalyabd4b962022-01-06 00:52:30 -05002076 } else if (!strcmp(optarg, "dnv")) {
2077 platform = PLATFORM_DNV;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002078 } else if (!strcmp(optarg, "ehl")) {
2079 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002080 } else if (!strcmp(optarg, "glk")) {
2081 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05302082 } else if (!strcmp(optarg, "icl")) {
2083 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05302084 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002085 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07002086 } else if (!strcmp(optarg, "sklkbl")) {
2087 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07002088 } else if (!strcmp(optarg, "tgl")) {
2089 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05302090 } else if (!strcmp(optarg, "adl")) {
2091 platform = PLATFORM_ADL;
Wonkyu Kim3922aa52022-02-02 15:19:05 -08002092 } else if (!strcmp(optarg, "ifd2")) {
2093 platform = PLATFORM_IFD2;
Subrata Banikca82e612022-01-20 18:51:21 +05302094 } else if (!strcmp(optarg, "mtl")) {
2095 platform = PLATFORM_MTL;
Patrick Rudolph16598742022-10-21 15:13:43 +02002096 } else if (!strcmp(optarg, "wbg")) {
2097 platform = PLATFORM_WBG;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002098 } else {
2099 fprintf(stderr, "Unknown platform: %s\n", optarg);
2100 exit(EXIT_FAILURE);
2101 }
2102 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06002103 case 't':
2104 mode_validate = 1;
2105 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002106 case 'v':
2107 print_version();
2108 exit(EXIT_SUCCESS);
2109 break;
2110 case 'h':
2111 case '?':
2112 default:
2113 print_usage(argv[0]);
2114 exit(EXIT_SUCCESS);
2115 break;
2116 }
2117 }
2118
Maximilian Brune347596a2023-03-05 20:55:32 +01002119 if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject +
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002120 mode_setstrap + mode_newlayout + (mode_spifreq | mode_em100 |
2121 mode_unlocked | mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002122 fprintf(stderr, "You may not specify more than one mode.\n\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002123 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002124 exit(EXIT_FAILURE);
2125 }
2126
Maximilian Brune347596a2023-03-05 20:55:32 +01002127 if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject +
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002128 mode_setstrap + mode_newlayout + mode_spifreq + mode_em100 +
2129 mode_locked + mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002130 fprintf(stderr, "You need to specify a mode.\n\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002131 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002132 exit(EXIT_FAILURE);
2133 }
2134
2135 if (optind + 1 != argc) {
2136 fprintf(stderr, "You need to specify a file.\n\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002137 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002138 exit(EXIT_FAILURE);
2139 }
2140
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002141 if (platform == -1)
2142 fprintf(stderr, "Warning: No platform specified. Output may be incomplete\n");
2143
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002144 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06002145 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002146 if (bios_fd == -1) {
2147 perror("Could not open file");
2148 exit(EXIT_FAILURE);
2149 }
2150 struct stat buf;
2151 if (fstat(bios_fd, &buf) == -1) {
2152 perror("Could not stat file");
2153 exit(EXIT_FAILURE);
2154 }
2155 int size = buf.st_size;
2156
2157 printf("File %s is %d bytes\n", filename, size);
2158
2159 char *image = malloc(size);
2160 if (!image) {
2161 printf("Out of memory.\n");
2162 exit(EXIT_FAILURE);
2163 }
2164
2165 if (read(bios_fd, image, size) != size) {
2166 perror("Could not read file");
2167 exit(EXIT_FAILURE);
2168 }
2169
2170 close(bios_fd);
2171
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002172 // generate new filename
2173 if (new_filename == NULL) {
2174 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
2175 if (!new_filename) {
2176 printf("Out of memory.\n");
2177 exit(EXIT_FAILURE);
2178 }
2179 // - 5: leave room for ".new\0"
2180 strcpy(new_filename, filename);
2181 strcat(new_filename, ".new");
2182 }
2183
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002184 check_ifd_version(image, size);
2185
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002186 if (mode_dump)
2187 dump_fd(image, size);
2188
Chris Douglass03ce0142014-02-26 13:30:13 -05002189 if (mode_layout)
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002190 dump_flashrom_layout(image, size, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -05002191
Maximilian Brune347596a2023-03-05 20:55:32 +01002192 if (mode_fmap_template)
2193 create_fmap_template(image, size, layout_fname);
2194
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002195 if (mode_extract)
2196 write_regions(image, size);
2197
Mathew Kingc7ddc992019-08-08 14:59:25 -06002198 if (mode_validate)
2199 validate_layout(image, size);
2200
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002201 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002202 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002203 region_fname);
2204
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002205 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002206 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002207
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002208 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002209 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002210
Jan Tatjefa317512016-03-11 00:52:07 +01002211 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002212 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002213
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002214 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002215 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002216
Alexander Couzensd12ea112016-09-10 13:33:05 +02002217 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002218 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002219
Usha P412679d2020-10-15 11:25:08 +05302220 if (mode_read)
2221 enable_cpu_read_me(new_filename, image, size);
2222
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002223 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002224 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002225
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002226 if (mode_setstrap) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002227 struct fpsba *fpsba = find_fpsba(image, size);
2228 const struct fdbar *fdb = find_fd(image, size);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002229 set_pchstrap(fpsba, fdb, pchstrap, value);
2230 write_image(new_filename, image, size);
2231 }
2232
Bill XIEb3e15a22017-09-07 18:34:50 +08002233 if (mode_altmedisable) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002234 struct fpsba *fpsba = find_fpsba(image, size);
2235 struct fmsba *fmsba = find_fmsba(image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002236 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002237 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002238 }
2239
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002240 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002241 free(image);
2242
2243 return 0;
2244}