blob: 625b4cf5ac376113b52774c23bda8dbc3382fcac [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);
Alexander Couzenseff596b2016-10-08 00:53:09 +0200460 /* is region invalid? */
461 if (region.size < 1)
462 continue;
463
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100464 char buf[LAYOUT_LINELEN];
465 snprintf(buf, LAYOUT_LINELEN, "%08x:%08x %s\n", region.base, region.limit, region_names[i].terse);
Chris Douglass03ce0142014-02-26 13:30:13 -0500466 if (write(layout_fd, buf, strlen(buf)) < 0) {
467 perror("Could not write to file");
468 exit(EXIT_FAILURE);
469 }
470 }
471 close(layout_fd);
472 printf("Wrote layout to %s\n", layout_fname);
473}
474
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530475static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700476{
477 switch (freq) {
478 case SPI_FREQUENCY_20MHZ:
479 printf("20MHz");
480 break;
481 case SPI_FREQUENCY_33MHZ:
482 printf("33MHz");
483 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700484 case SPI_FREQUENCY_48MHZ:
485 printf("48MHz");
486 break;
487 case SPI_FREQUENCY_50MHZ_30MHZ:
488 switch (ifd_version) {
489 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +0200490 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700491 printf("50MHz");
492 break;
493 case IFD_VERSION_2:
494 printf("30MHz");
495 break;
496 }
497 break;
498 case SPI_FREQUENCY_17MHZ:
499 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700500 break;
501 default:
502 printf("unknown<%x>MHz", freq);
503 }
504}
505
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530506static void _decode_spi_frequency_500_series(unsigned int freq)
507{
508 switch (freq) {
509 case SPI_FREQUENCY_100MHZ:
510 printf("100MHz");
511 break;
512 case SPI_FREQUENCY_50MHZ:
513 printf("50MHz");
514 break;
515 case SPI_FREQUENCY_500SERIES_33MHZ:
516 printf("33MHz");
517 break;
518 case SPI_FREQUENCY_25MHZ:
519 printf("25MHz");
520 break;
521 case SPI_FREQUENCY_14MHZ:
522 printf("14MHz");
523 break;
524 default:
525 printf("unknown<%x>MHz", freq);
526 }
527}
528
529static void decode_spi_frequency(unsigned int freq)
530{
Subrata Banika5f47812020-09-29 11:43:01 +0530531 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530532 _decode_spi_frequency_500_series(freq);
533 else
534 _decode_spi_frequency(freq);
535}
536
Subrata Banike5d39922020-08-26 16:01:42 +0530537static void _decode_espi_frequency(unsigned int freq)
538{
539 switch (freq) {
540 case ESPI_FREQUENCY_20MHZ:
541 printf("20MHz");
542 break;
543 case ESPI_FREQUENCY_24MHZ:
544 printf("24MHz");
545 break;
546 case ESPI_FREQUENCY_30MHZ:
547 printf("30MHz");
548 break;
549 case ESPI_FREQUENCY_48MHZ:
550 printf("48MHz");
551 break;
552 case ESPI_FREQUENCY_60MHZ:
553 printf("60MHz");
554 break;
555 case ESPI_FREQUENCY_17MHZ:
556 printf("17MHz");
557 break;
558 default:
559 printf("unknown<%x>MHz", freq);
560 }
561}
562
563static void _decode_espi_frequency_500_series(unsigned int freq)
564{
565 switch (freq) {
566 case ESPI_FREQUENCY_500SERIES_20MHZ:
567 printf("20MHz");
568 break;
569 case ESPI_FREQUENCY_500SERIES_24MHZ:
570 printf("24MHz");
571 break;
572 case ESPI_FREQUENCY_500SERIES_25MHZ:
573 printf("25MHz");
574 break;
575 case ESPI_FREQUENCY_500SERIES_48MHZ:
576 printf("48MHz");
577 break;
578 case ESPI_FREQUENCY_500SERIES_60MHZ:
579 printf("60MHz");
580 break;
581 default:
582 printf("unknown<%x>MHz", freq);
583 }
584}
585
586static void decode_espi_frequency(unsigned int freq)
587{
Subrata Banika5f47812020-09-29 11:43:01 +0530588 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530589 _decode_espi_frequency_500_series(freq);
590 else
591 _decode_espi_frequency(freq);
592}
593
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700594static void decode_component_density(unsigned int density)
595{
596 switch (density) {
597 case COMPONENT_DENSITY_512KB:
598 printf("512KB");
599 break;
600 case COMPONENT_DENSITY_1MB:
601 printf("1MB");
602 break;
603 case COMPONENT_DENSITY_2MB:
604 printf("2MB");
605 break;
606 case COMPONENT_DENSITY_4MB:
607 printf("4MB");
608 break;
609 case COMPONENT_DENSITY_8MB:
610 printf("8MB");
611 break;
612 case COMPONENT_DENSITY_16MB:
613 printf("16MB");
614 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700615 case COMPONENT_DENSITY_32MB:
616 printf("32MB");
617 break;
618 case COMPONENT_DENSITY_64MB:
619 printf("64MB");
620 break;
621 case COMPONENT_DENSITY_UNUSED:
622 printf("UNUSED");
623 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700624 default:
625 printf("unknown<%x>MB", density);
626 }
627}
628
Subrata Banik26058dc2020-08-26 15:12:16 +0530629static int is_platform_with_pch(void)
630{
631 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
632 return 1;
633
634 return 0;
635}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530636
637/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
638static int is_platform_with_100x_series_pch(void)
639{
640 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530641 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530642 return 1;
643
644 return 0;
645}
646
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100647static void dump_fcba(const struct fcba *fcba, const struct fpsba *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700648{
Subrata Banike5d39922020-08-26 16:01:42 +0530649 unsigned int freq;
650
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700651 printf("\nFound Component Section\n");
652 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700653 printf(" Dual Output Fast Read Support: %ssupported\n",
654 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700655 printf(" Read ID/Read Status Clock Frequency: ");
656 decode_spi_frequency((fcba->flcomp >> 27) & 7);
657 printf("\n Write/Erase Clock Frequency: ");
658 decode_spi_frequency((fcba->flcomp >> 24) & 7);
659 printf("\n Fast Read Clock Frequency: ");
660 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700661 printf("\n Fast Read Support: %ssupported",
662 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530663 if (is_platform_with_100x_series_pch() &&
664 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
665 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530666 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530667 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
668 else
669 freq = (fcba->flcomp >> 17) & 7;
670 decode_espi_frequency(freq);
671 } else {
672 printf("\n Read Clock Frequency: ");
673 decode_spi_frequency((fcba->flcomp >> 17) & 7);
674 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700675
676 switch (ifd_version) {
677 case IFD_VERSION_1:
678 printf("\n Component 2 Density: ");
679 decode_component_density((fcba->flcomp >> 3) & 7);
680 printf("\n Component 1 Density: ");
681 decode_component_density(fcba->flcomp & 7);
682 break;
Patrick Rudolph16598742022-10-21 15:13:43 +0200683 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700684 case IFD_VERSION_2:
685 printf("\n Component 2 Density: ");
686 decode_component_density((fcba->flcomp >> 4) & 0xf);
687 printf("\n Component 1 Density: ");
688 decode_component_density(fcba->flcomp & 0xf);
689 break;
690 }
691
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700692 printf("\n");
693 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700694 printf(" Invalid Instruction 3: 0x%02x\n",
695 (fcba->flill >> 24) & 0xff);
696 printf(" Invalid Instruction 2: 0x%02x\n",
697 (fcba->flill >> 16) & 0xff);
698 printf(" Invalid Instruction 1: 0x%02x\n",
699 (fcba->flill >> 8) & 0xff);
700 printf(" Invalid Instruction 0: 0x%02x\n",
701 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530702 if (is_platform_with_100x_series_pch()) {
703 printf("FLILL1 0x%08x\n", fcba->flpb);
704 printf(" Invalid Instruction 7: 0x%02x\n",
705 (fcba->flpb >> 24) & 0xff);
706 printf(" Invalid Instruction 6: 0x%02x\n",
707 (fcba->flpb >> 16) & 0xff);
708 printf(" Invalid Instruction 5: 0x%02x\n",
709 (fcba->flpb >> 8) & 0xff);
710 printf(" Invalid Instruction 4: 0x%02x\n",
711 fcba->flpb & 0xff);
712 } else {
713 printf("FLPB 0x%08x\n", fcba->flpb);
714 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
715 (fcba->flpb & 0xfff) << 12);
716 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700717}
718
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100719static void dump_fpsba(const struct fdbar *fdb, const struct fpsba *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700720{
Bill XIE4651d452017-09-12 11:54:48 +0800721 unsigned int i;
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200722 /* SoC Straps, aka PSL, aka ISL */
723 unsigned int SS = (fdb->flmap1 >> 24) & 0xff;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200724
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700725 printf("Found PCH Strap Section\n");
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200726 for (i = 0; i < SS; i++)
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200727 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800728
729 if (ifd_version >= IFD_VERSION_2) {
730 printf("HAP bit is %sset\n",
731 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100732 } else if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
Bill XIEb3e15a22017-09-07 18:34:50 +0800733 printf("ICH_MeDisable bit is %sset\n",
734 fpsba->pchstrp[0] & 1 ? "" : "not ");
735 } else {
736 printf("AltMeDisable bit is %sset\n",
737 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
738 }
739
Bill XIE4651d452017-09-12 11:54:48 +0800740 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700741}
742
743static void decode_flmstr(uint32_t flmstr)
744{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700745 int wr_shift, rd_shift;
746 if (ifd_version >= IFD_VERSION_2) {
747 wr_shift = FLMSTR_WR_SHIFT_V2;
748 rd_shift = FLMSTR_RD_SHIFT_V2;
749 } else {
750 wr_shift = FLMSTR_WR_SHIFT_V1;
751 rd_shift = FLMSTR_RD_SHIFT_V1;
752 }
753
754 /* EC region access only available on v2+ */
Jeff Dalyabd4b962022-01-06 00:52:30 -0500755 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700756 printf(" EC Region Write Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100757 (flmstr & (1 << (wr_shift + 8))) ?
758 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700759 printf(" Platform Data Region Write Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100760 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500761 if (PLATFORM_HAS_GBE_REGION) {
762 printf(" GbE Region Write Access: %s\n",
763 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
764 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700765 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700766 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700767 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700768 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700769 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700770 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500771 if (PLATFORM_HAS_10GBE_0_REGION) {
772 printf(" 10GbE_0 Write Access: %s\n",
773 (flmstr & (1 << (wr_shift + 11))) ? "enabled" : "disabled");
774 }
775 if (PLATFORM_HAS_10GBE_1_REGION) {
776 printf(" 10GbE_1 Write Access: %s\n",
777 (flmstr & (1 << 4)) ? "enabled" : "disabled");
778 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700779
Jeff Dalyabd4b962022-01-06 00:52:30 -0500780 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700781 printf(" EC Region Read Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100782 (flmstr & (1 << (rd_shift + 8))) ?
783 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700784 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700785 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500786 if (PLATFORM_HAS_GBE_REGION) {
787 printf(" GbE Region Read Access: %s\n",
788 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
789 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700790 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700791 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700792 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700793 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700794 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700795 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500796 if (PLATFORM_HAS_10GBE_0_REGION) {
797 printf(" 10GbE_0 Read Access: %s\n",
798 (flmstr & (1 << (rd_shift + 11))) ? "enabled" : "disabled");
799 }
800 if (PLATFORM_HAS_10GBE_1_REGION) {
801 printf(" 10GbE_1 Read Access: %s\n",
802 (flmstr & (1 << 0)) ? "enabled" : "disabled");
803 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700804
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700805 /* Requestor ID doesn't exist for ifd 2 */
806 if (ifd_version < IFD_VERSION_2)
807 printf(" Requester ID: 0x%04x\n\n",
808 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700809}
810
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100811static void dump_fmba(const struct fmba *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700812{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700813 printf("Found Master Section\n");
814 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
815 decode_flmstr(fmba->flmstr1);
816 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
817 decode_flmstr(fmba->flmstr2);
Jeff Dalyabd4b962022-01-06 00:52:30 -0500818 if (PLATFORM_HAS_GBE_REGION) {
819 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
820 decode_flmstr(fmba->flmstr3);
821 if (ifd_version >= IFD_VERSION_2) {
822 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
823 decode_flmstr(fmba->flmstr5);
824 }
825 } else {
826 printf("FLMSTR6: 0x%08x (IE)\n", fmba->flmstr6);
827 decode_flmstr(fmba->flmstr6);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700828 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700829}
830
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100831static void dump_fmsba(const struct fmsba *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700832{
Bill XIE612ec0e2017-08-30 16:10:27 +0800833 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700834 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800835 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
836 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800837
838 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
839 printf("MCH_MeDisable bit is %sset\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100840 fmsba->data[0] & 1 ? "" : "not ");
Bill XIEb3e15a22017-09-07 18:34:50 +0800841 printf("MCH_AltMeDisable bit is %sset\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100842 fmsba->data[0] & (1 << 7) ? "" : "not ");
Bill XIEb3e15a22017-09-07 18:34:50 +0800843 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700844}
845
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700846static void dump_jid(uint32_t jid)
847{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100848 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700849 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100850 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200851 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100852 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200853 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700854}
855
856static void dump_vscc(uint32_t vscc)
857{
858 printf(" Lower Erase Opcode: 0x%02x\n",
859 vscc >> 24);
860 printf(" Lower Write Enable on Write Status: 0x%02x\n",
861 vscc & (1 << 20) ? 0x06 : 0x50);
862 printf(" Lower Write Status Required: %s\n",
863 vscc & (1 << 19) ? "Yes" : "No");
864 printf(" Lower Write Granularity: %d bytes\n",
865 vscc & (1 << 18) ? 64 : 1);
866 printf(" Lower Block / Sector Erase Size: ");
867 switch ((vscc >> 16) & 0x3) {
868 case 0:
869 printf("256 Byte\n");
870 break;
871 case 1:
872 printf("4KB\n");
873 break;
874 case 2:
875 printf("8KB\n");
876 break;
877 case 3:
878 printf("64KB\n");
879 break;
880 }
881
882 printf(" Upper Erase Opcode: 0x%02x\n",
883 (vscc >> 8) & 0xff);
884 printf(" Upper Write Enable on Write Status: 0x%02x\n",
885 vscc & (1 << 4) ? 0x06 : 0x50);
886 printf(" Upper Write Status Required: %s\n",
887 vscc & (1 << 3) ? "Yes" : "No");
888 printf(" Upper Write Granularity: %d bytes\n",
889 vscc & (1 << 2) ? 64 : 1);
890 printf(" Upper Block / Sector Erase Size: ");
891 switch (vscc & 0x3) {
892 case 0:
893 printf("256 Byte\n");
894 break;
895 case 1:
896 printf("4KB\n");
897 break;
898 case 2:
899 printf("8KB\n");
900 break;
901 case 3:
902 printf("64KB\n");
903 break;
904 }
905}
906
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100907static void dump_vtba(const struct vtba *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700908{
909 int i;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100910 int max_len = sizeof(struct vtba)/sizeof(struct vscc);
Stefan Tauner0d226142018-08-05 18:56:53 +0200911 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700912
913 printf("ME VSCC table:\n");
914 for (i = 0; i < num; i++) {
915 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
916 dump_jid(vtba->entry[i].jid);
917 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
918 dump_vscc(vtba->entry[i].vscc);
919 }
920 printf("\n");
921}
922
Bill XIEfa5f9942017-09-12 11:22:29 +0800923static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700924{
925 int i, j;
926 printf("OEM Section:\n");
927 for (i = 0; i < 4; i++) {
928 printf("%02x:", i << 4);
929 for (j = 0; j < 16; j++)
930 printf(" %02x", oem[(i<<4)+j]);
931 printf ("\n");
932 }
933 printf ("\n");
934}
935
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700936static void dump_fd(char *image, int size)
937{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100938 const struct fdbar *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700939 if (!fdb)
940 exit(EXIT_FAILURE);
941
Subrata Banik26058dc2020-08-26 15:12:16 +0530942 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
943 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700944 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530945 if (!is_platform_with_100x_series_pch())
946 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700947 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
948 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
949 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
950
951 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530952 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
953 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700954 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
955 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
956 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
957
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530958 if (!is_platform_with_100x_series_pch()) {
959 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
960 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
961 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
962 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700963
Subrata Banika5f47812020-09-29 11:43:01 +0530964 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530965 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
966 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
967 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
968 }
969
Stefan Tauner0d226142018-08-05 18:56:53 +0200970 char *flumap = find_flumap(image, size);
971 uint32_t flumap1 = *(uint32_t *)flumap;
972 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700973 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200974 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700975 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200976 (flumap1 & 0xff) << 4);
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100977 dump_vtba((struct vtba *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200978 (image + ((flumap1 & 0xff) << 4)),
979 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800980 dump_oem((const uint8_t *)image + 0xf00);
981
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100982 const struct frba *frba = find_frba(image, size);
983 const struct fcba *fcba = find_fcba(image, size);
984 const struct fpsba *fpsba = find_fpsba(image, size);
985 const struct fmba *fmba = find_fmba(image, size);
986 const struct fmsba *fmsba = find_fmsba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800987
988 if (frba && fcba && fpsba && fmba && fmsba) {
989 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +0530990 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200991 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800992 dump_fmba(fmba);
993 dump_fmsba(fmsba);
994 } else {
995 printf("FD is corrupted!\n");
996 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700997}
998
Maximilian Brune347596a2023-03-05 20:55:32 +0100999/* Takes an image containing an IFD and creates a Flashmap .fmd file template.
1000 * This flashmap will contain all IFD regions except the BIOS region.
1001 * The BIOS region is created by coreboot itself and 'should' match the IFD region
1002 * anyway (CONFIG_VALIDATE_INTEL_DESCRIPTOR should make sure). coreboot built system will use
1003 * this template to generate the final Flashmap file.
1004 */
1005static void create_fmap_template(char *image, int size, const char *layout_fname)
1006{
1007 const struct frba *frba = find_frba(image, size);
1008 if (!frba)
1009 exit(EXIT_FAILURE);
1010
1011 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1012 if (layout_fd == -1) {
1013 perror("Could not open file");
1014 exit(EXIT_FAILURE);
1015 }
1016
1017 char *bbuf = "FLASH@##ROM_BASE## ##ROM_SIZE## {\n";
1018 if (write(layout_fd, bbuf, strlen(bbuf)) < 0) {
1019 perror("Could not write to file");
1020 exit(EXIT_FAILURE);
1021 }
1022
1023 /* fmaptool requires regions in .fmd to be sorted.
1024 * => We need to sort the regions by base address before writing them in .fmd File
1025 */
1026 int count_regions = 0;
1027 struct region sorted_regions[MAX_REGIONS] = { 0 };
1028 for (unsigned int i = 0; i < max_regions; i++) {
1029 struct region region = get_region(frba, i);
1030 /* is region invalid? */
1031 if (region.size < 1)
1032 continue;
1033
1034 /* Here we decide to use the coreboot generated FMAP BIOS region, instead of
1035 * the one specified in the IFD. The case when IFD and FMAP BIOS region do not
1036 * match cannot be caught here, therefore one should still validate IFD and
1037 * FMAP via CONFIG_VALIDATE_INTEL_DESCRIPTOR
1038 */
1039 if (i == REGION_BIOS)
1040 continue;
1041
1042 sorted_regions[count_regions] = region;
1043 // basically insertion sort
1044 for (int i = count_regions-1; i >= 0 ; i--) {
1045 if (sorted_regions[i].base > sorted_regions[i+1].base) {
1046 struct region tmp = sorted_regions[i];
1047 sorted_regions[i] = sorted_regions[i+1];
1048 sorted_regions[i+1] = tmp;
1049 }
1050 }
1051 count_regions++;
1052 }
1053
1054 // Now write regions sorted by base address in the fmap file
1055 for (int i = 0; i < count_regions; i++) {
1056 struct region region = sorted_regions[i];
1057 char buf[LAYOUT_LINELEN];
1058 snprintf(buf, LAYOUT_LINELEN, "\t%s@0x%X 0x%X\n", region_names[region.type].fmapname, region.base, region.size);
1059 if (write(layout_fd, buf, strlen(buf)) < 0) {
1060 perror("Could not write to file");
1061 exit(EXIT_FAILURE);
1062 }
1063 }
1064
1065 char *ebuf = "\tSI_BIOS@##BIOS_BASE## ##BIOS_SIZE## {\n"
1066 "\t\t##CONSOLE_ENTRY##\n"
1067 "\t\t##MRC_CACHE_ENTRY##\n"
1068 "\t\t##SMMSTORE_ENTRY##\n"
1069 "\t\t##SPD_CACHE_ENTRY##\n"
1070 "\t\t##VPD_ENTRY##\n"
1071 "\t\tFMAP@##FMAP_BASE## ##FMAP_SIZE##\n"
1072 "\t\tCOREBOOT(CBFS)@##CBFS_BASE## ##CBFS_SIZE##\n"
1073 "\t}\n"
1074 "}\n";
1075 if (write(layout_fd, ebuf, strlen(ebuf)) < 0) {
1076 perror("Could not write to file");
1077 exit(EXIT_FAILURE);
1078 }
1079
1080 close(layout_fd);
1081 printf("Wrote layout to %s\n", layout_fname);
1082}
1083
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001084static void write_regions(char *image, int size)
1085{
Bill XIEfa5f9942017-09-12 11:22:29 +08001086 unsigned int i;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001087 const struct frba *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001088
Bill XIE612ec0e2017-08-30 16:10:27 +08001089 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001090 exit(EXIT_FAILURE);
1091
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001092 for (i = 0; i < max_regions; i++) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001093 struct region region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001094 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001095 if (region.size > 0) {
1096 int region_fd;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001097 region_fd = open(region_names[i].filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001098 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001099 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001100 if (region_fd < 0) {
1101 perror("Error while trying to open file");
1102 exit(EXIT_FAILURE);
1103 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001104 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001105 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001106 close(region_fd);
1107 }
1108 }
1109}
1110
Mathew Kingc7ddc992019-08-08 14:59:25 -06001111static void validate_layout(char *image, int size)
1112{
1113 uint i, errors = 0;
1114 struct fmap *fmap;
1115 long int fmap_loc = fmap_find((uint8_t *)image, size);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001116 const struct frba *frba = find_frba(image, size);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001117
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001118 if (fmap_loc < 0 || !frba) {
1119 printf("Could not find FMAP (%p) or Intel Flash Descriptor (%p)\n",
1120 (void *)fmap_loc, frba);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001121 exit(EXIT_FAILURE);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001122 }
Mathew Kingc7ddc992019-08-08 14:59:25 -06001123
1124 fmap = (struct fmap *)(image + fmap_loc);
1125
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001126 int matches = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001127 for (i = 0; i < max_regions; i++) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001128 struct region region = get_region(frba, i);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001129 if (region.size == 0)
1130 continue;
1131
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001132 const struct fmap_area *area = fmap_find_area(fmap, region_names[i].fmapname);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001133 if (!area)
1134 continue;
1135
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001136 matches++; // found a match between FMAP and IFD region
1137
1138 if ((uint)region.base != area->offset || (uint)region.size != area->size) {
1139 printf("Region mismatch between %s and %s\n", region_names[i].terse, area->name);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001140 printf(" Descriptor region %s:\n", region_names[i].terse);
1141 printf(" offset: 0x%08x\n", region.base);
1142 printf(" length: 0x%08x\n", region.size);
1143 printf(" FMAP area %s:\n", area->name);
1144 printf(" offset: 0x%08x\n", area->offset);
1145 printf(" length: 0x%08x\n", area->size);
1146 errors++;
1147 }
1148 }
1149
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001150 if (!matches) {
1151 // At least a BIOS region should be present in both IFD and FMAP
1152 fprintf(stderr, "Warning: Not a single IFD region found in FMAP\n");
1153 }
1154
Mathew Kingc7ddc992019-08-08 14:59:25 -06001155 if (errors > 0)
1156 exit(EXIT_FAILURE);
1157}
1158
Bill XIEfa5f9942017-09-12 11:22:29 +08001159static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001160{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001161 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001162 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001163
1164 // Now write out new image
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001165 new_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001166 if (new_fd < 0) {
1167 perror("Error while trying to open file");
1168 exit(EXIT_FAILURE);
1169 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001170 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001171 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001172 close(new_fd);
1173}
1174
Bill XIEfa5f9942017-09-12 11:22:29 +08001175static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001176 enum spi_frequency freq)
1177{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001178 struct fcba *fcba = find_fcba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001179 if (!fcba)
1180 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001181
1182 /* clear bits 21-29 */
1183 fcba->flcomp &= ~0x3fe00000;
1184 /* Read ID and Read Status Clock Frequency */
1185 fcba->flcomp |= freq << 27;
1186 /* Write and Erase Clock Frequency */
1187 fcba->flcomp |= freq << 24;
1188 /* Fast Read Clock Frequency */
1189 fcba->flcomp |= freq << 21;
1190
1191 write_image(filename, image, size);
1192}
1193
Bill XIEfa5f9942017-09-12 11:22:29 +08001194static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001195{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001196 struct fcba *fcba = find_fcba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001197 if (!fcba)
1198 exit(EXIT_FAILURE);
1199
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001200 int freq;
1201
1202 switch (ifd_version) {
1203 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +02001204 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001205 freq = SPI_FREQUENCY_20MHZ;
1206 break;
1207 case IFD_VERSION_2:
1208 freq = SPI_FREQUENCY_17MHZ;
1209 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001210 default:
1211 freq = SPI_FREQUENCY_17MHZ;
1212 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001213 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001214
1215 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001216 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001217}
1218
Bill XIEfa5f9942017-09-12 11:22:29 +08001219static void set_chipdensity(const char *filename, char *image, int size,
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001220 unsigned int density)
Jan Tatjefa317512016-03-11 00:52:07 +01001221{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001222 struct fcba *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001223 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001224 if (!fcba)
1225 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001226
1227 printf("Setting chip density to ");
1228 decode_component_density(density);
1229 printf("\n");
1230
1231 switch (ifd_version) {
1232 case IFD_VERSION_1:
1233 /* fail if selected density is not supported by this version */
1234 if ( (density == COMPONENT_DENSITY_32MB) ||
1235 (density == COMPONENT_DENSITY_64MB) ||
1236 (density == COMPONENT_DENSITY_UNUSED) ) {
1237 printf("error: Selected density not supported in IFD version 1.\n");
1238 exit(EXIT_FAILURE);
1239 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001240 mask = 0x7;
1241 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001242 break;
Patrick Rudolph16598742022-10-21 15:13:43 +02001243 case IFD_VERSION_1_5:
Jan Tatjefa317512016-03-11 00:52:07 +01001244 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001245 mask = 0xf;
1246 chip2_offset = 4;
1247 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001248 default:
1249 printf("error: Unknown IFD version\n");
1250 exit(EXIT_FAILURE);
1251 break;
1252 }
1253
1254 /* clear chip density for corresponding chip */
1255 switch (selected_chip) {
1256 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001257 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001258 break;
1259 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001260 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001261 break;
1262 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001263 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001264 break;
1265 }
1266
1267 /* set the new density */
1268 if (selected_chip == 1 || selected_chip == 0)
1269 fcba->flcomp |= (density); /* first chip */
1270 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001271 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001272
1273 write_image(filename, image, size);
1274}
1275
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001276static int check_region(const struct frba *frba, unsigned int region_type)
Duncan Laurie7775d672019-06-06 13:39:26 -07001277{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001278 struct region region;
Duncan Laurie7775d672019-06-06 13:39:26 -07001279
1280 if (!frba)
1281 return 0;
1282
1283 region = get_region(frba, region_type);
1284 return !!((region.base < region.limit) && (region.size > 0));
1285}
1286
Bill XIEfa5f9942017-09-12 11:22:29 +08001287static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001288{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001289 int wr_shift, rd_shift;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001290 struct fmba *fmba = find_fmba(image, size);
1291 const struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001292 if (!fmba)
1293 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001294
1295 if (ifd_version >= IFD_VERSION_2) {
1296 wr_shift = FLMSTR_WR_SHIFT_V2;
1297 rd_shift = FLMSTR_RD_SHIFT_V2;
1298
1299 /* Clear non-reserved bits */
1300 fmba->flmstr1 &= 0xff;
1301 fmba->flmstr2 &= 0xff;
1302 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001303 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001304 } else {
1305 wr_shift = FLMSTR_WR_SHIFT_V1;
1306 rd_shift = FLMSTR_RD_SHIFT_V1;
1307
1308 fmba->flmstr1 = 0;
1309 fmba->flmstr2 = 0;
1310 /* Requestor ID */
1311 fmba->flmstr3 = 0x118;
1312 }
1313
Andrey Petrov96ecb772016-10-31 19:31:54 -07001314 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001315 case PLATFORM_APL:
1316 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001317 /* CPU/BIOS can read descriptor and BIOS */
1318 fmba->flmstr1 |= 0x3 << rd_shift;
1319 /* CPU/BIOS can write BIOS */
1320 fmba->flmstr1 |= 0x2 << wr_shift;
1321 /* TXE can read descriptor, BIOS and Device Expansion */
1322 fmba->flmstr2 |= 0x23 << rd_shift;
1323 /* TXE can only write Device Expansion */
1324 fmba->flmstr2 |= 0x20 << wr_shift;
1325 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001326 case PLATFORM_CNL:
1327 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001328 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001329 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301330 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001331 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301332 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001333 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +05301334 case PLATFORM_MTL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001335 /* CPU/BIOS can read descriptor and BIOS. */
1336 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1337 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1338 /* CPU/BIOS can write BIOS. */
1339 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1340 /* ME can read descriptor and ME. */
1341 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1342 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001343 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001344 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1345 if (check_region(frba, REGION_GBE)) {
1346 /* BIOS can read/write GbE. */
1347 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1348 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1349 /* ME can read GbE. */
1350 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1351 /* GbE can read descriptor and read/write GbE.. */
1352 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1353 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1354 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1355 }
1356 if (check_region(frba, REGION_PDR)) {
1357 /* BIOS can read/write PDR. */
1358 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1359 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1360 }
1361 if (check_region(frba, REGION_EC)) {
1362 /* BIOS can read EC. */
1363 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1364 /* EC can read descriptor and read/write EC. */
1365 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1366 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1367 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1368 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001369 break;
Jeff Dalyabd4b962022-01-06 00:52:30 -05001370 case PLATFORM_DNV:
Patrick Rudolph16598742022-10-21 15:13:43 +02001371 case PLATFORM_WBG:
Jeff Dalyabd4b962022-01-06 00:52:30 -05001372 /* CPU/BIOS can read descriptor and BIOS. */
1373 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1374 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1375 /* CPU/BIOS can write BIOS. */
1376 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1377 /* ME can read descriptor and ME. */
1378 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1379 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1380 /* ME can write ME. */
1381 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1382 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001383 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001384 /* CPU/BIOS can read descriptor and BIOS. */
1385 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1386 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1387 /* CPU/BIOS can write BIOS. */
1388 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1389 /* ME can read descriptor and ME. */
1390 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1391 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1392 /* ME can write ME. */
1393 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1394 if (check_region(frba, REGION_GBE)) {
1395 /* BIOS can read GbE. */
1396 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1397 /* BIOS can write GbE. */
1398 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1399 /* ME can read GbE. */
1400 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1401 /* ME can write GbE. */
1402 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1403 /* GbE can write GbE. */
1404 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1405 /* GbE can read GbE. */
1406 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1407 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001408 break;
1409 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001410
1411 write_image(filename, image, size);
1412}
1413
Usha P412679d2020-10-15 11:25:08 +05301414static void enable_cpu_read_me(const char *filename, char *image, int size)
1415{
1416 int rd_shift;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001417 struct fmba *fmba = find_fmba(image, size);
Usha P412679d2020-10-15 11:25:08 +05301418
1419 if (!fmba)
1420 exit(EXIT_FAILURE);
1421
1422 if (ifd_version >= IFD_VERSION_2)
1423 rd_shift = FLMSTR_RD_SHIFT_V2;
1424 else
1425 rd_shift = FLMSTR_RD_SHIFT_V1;
1426
1427 /* CPU/BIOS can read ME. */
1428 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1429
1430 write_image(filename, image, size);
1431}
1432
Bill XIEfa5f9942017-09-12 11:22:29 +08001433static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001434{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001435 struct fmba *fmba = find_fmba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001436 if (!fmba)
1437 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001438
1439 if (ifd_version >= IFD_VERSION_2) {
1440 /* Access bits for each region are read: 19:8 write: 31:20 */
1441 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1442 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1443 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001444 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001445 } else {
1446 fmba->flmstr1 = 0xffff0000;
1447 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001448 /* Keep chipset specific Requester ID */
1449 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001450 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001451
1452 write_image(filename, image, size);
1453}
1454
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001455static void set_pchstrap(struct fpsba *fpsba, const struct fdbar *fdb, const int strap,
1456 const unsigned int value)
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001457{
1458 if (!fpsba || !fdb) {
1459 fprintf(stderr, "Internal error\n");
1460 exit(EXIT_FAILURE);
1461 }
1462
Arthur Heymans0424a2c2021-06-22 11:14:24 +02001463 /* SoC Strap, aka PSL, aka ISL */
1464 int SS = (fdb->flmap1 >> 24) & 0xff;
1465 if (strap >= SS) {
1466 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SS);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001467 exit(EXIT_FAILURE);
1468 }
1469 fpsba->pchstrp[strap] = value;
1470}
1471
Bill XIEb3e15a22017-09-07 18:34:50 +08001472/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001473static void fpsba_set_altmedisable(struct fpsba *fpsba, struct fmsba *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001474{
1475 if (ifd_version >= IFD_VERSION_2) {
1476 printf("%sting the HAP bit to %s Intel ME...\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001477 altmedisable?"Set":"Unset",
1478 altmedisable?"disable":"enable");
Bill XIEb3e15a22017-09-07 18:34:50 +08001479 if (altmedisable)
1480 fpsba->pchstrp[0] |= (1 << 16);
1481 else
1482 fpsba->pchstrp[0] &= ~(1 << 16);
1483 } else {
1484 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1485 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1486 "and MCH_AltMeDisable to %s Intel ME...\n",
1487 altmedisable?"Set":"Unset",
1488 altmedisable?"disable":"enable");
1489 if (altmedisable) {
1490 /* MCH_MeDisable */
1491 fmsba->data[0] |= 1;
1492 /* MCH_AltMeDisable */
1493 fmsba->data[0] |= (1 << 7);
1494 /* ICH_MeDisable */
1495 fpsba->pchstrp[0] |= 1;
1496 } else {
1497 fmsba->data[0] &= ~1;
1498 fmsba->data[0] &= ~(1 << 7);
1499 fpsba->pchstrp[0] &= ~1;
1500 }
1501 } else {
1502 printf("%sting the AltMeDisable to %s Intel ME...\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001503 altmedisable?"Set":"Unset",
1504 altmedisable?"disable":"enable");
Bill XIEb3e15a22017-09-07 18:34:50 +08001505 if (altmedisable)
1506 fpsba->pchstrp[10] |= (1 << 7);
1507 else
1508 fpsba->pchstrp[10] &= ~(1 << 7);
1509 }
1510 }
1511}
1512
Jacob Garber595d9262019-06-27 17:33:10 -06001513static void inject_region(const char *filename, char *image, int size,
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001514 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001515{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001516 struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001517 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001518 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001519
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001520 struct region region = get_region(frba, region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001521 if (region.size <= 0xfff) {
1522 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1523 region_name(region_type));
1524 exit(EXIT_FAILURE);
1525 }
1526
Scott Duplichanf2c98372014-12-12 21:03:06 -06001527 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001528 if (region_fd == -1) {
1529 perror("Could not open file");
1530 exit(EXIT_FAILURE);
1531 }
1532 struct stat buf;
1533 if (fstat(region_fd, &buf) == -1) {
1534 perror("Could not stat file");
1535 exit(EXIT_FAILURE);
1536 }
1537 int region_size = buf.st_size;
1538
1539 printf("File %s is %d bytes\n", region_fname, region_size);
1540
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001541 if (region_size > region.size) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001542 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1543 " bytes. Not injecting.\n",
1544 region_name(region_type), region.size,
1545 region.size, region_size, region_size);
1546 exit(EXIT_FAILURE);
1547 }
1548
1549 int offset = 0;
1550 if ((region_type == 1) && (region_size < region.size)) {
1551 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1552 " bytes. Padding before injecting.\n",
1553 region_name(region_type), region.size,
1554 region.size, region_size, region_size);
1555 offset = region.size - region_size;
1556 memset(image + region.base, 0xff, offset);
1557 }
1558
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001559 if (size < region.base + offset + region_size) {
1560 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1561 size, region.base + offset + region_size);
1562 exit(EXIT_FAILURE);
1563 }
1564
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001565 if (read(region_fd, image + region.base + offset, region_size) != region_size) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001566 perror("Could not read file");
1567 exit(EXIT_FAILURE);
1568 }
1569
1570 close(region_fd);
1571
1572 printf("Adding %s as the %s section of %s\n",
1573 region_fname, region_name(region_type), filename);
1574 write_image(filename, image, size);
1575}
1576
Jacob Garber595d9262019-06-27 17:33:10 -06001577static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001578{
1579 unsigned int y = 1;
1580 if (x == 0)
1581 return 0;
1582 while (y <= x)
1583 y = y << 1;
1584
1585 return y;
1586}
1587
1588/**
1589 * Determine if two memory regions overlap.
1590 *
1591 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001592 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001593 * @return 1 if the two regions overlap
1594 */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001595static int regions_collide(const struct region *r1, const struct region *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001596{
Bill XIEfa5f9942017-09-12 11:22:29 +08001597 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001598 return 0;
1599
Nico Huber844eda02019-01-05 00:06:19 +01001600 /* r1 should be either completely below or completely above r2 */
1601 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001602}
1603
Jacob Garber595d9262019-06-27 17:33:10 -06001604static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001605 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001606{
1607 FILE *romlayout;
1608 char tempstr[256];
1609 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001610 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001611 int region_number;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001612 struct region current_regions[MAX_REGIONS];
1613 struct region new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001614 int new_extent = 0;
1615 char *new_image;
1616
1617 /* load current descriptor map and regions */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001618 struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001619 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001620 exit(EXIT_FAILURE);
1621
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001622 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001623 current_regions[i] = get_region(frba, i);
1624 new_regions[i] = get_region(frba, i);
1625 }
1626
1627 /* read new layout */
1628 romlayout = fopen(layout_fname, "r");
1629
1630 if (!romlayout) {
1631 perror("Could not read layout file.\n");
1632 exit(EXIT_FAILURE);
1633 }
1634
1635 while (!feof(romlayout)) {
1636 char *tstr1, *tstr2;
1637
Patrick Georgi802ad522014-08-09 17:12:23 +02001638 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001639 layout_region_name))
1640 continue;
1641
1642 region_number = region_num(layout_region_name);
1643 if (region_number < 0)
1644 continue;
1645
1646 tstr1 = strtok(tempstr, ":");
1647 tstr2 = strtok(NULL, ":");
1648 if (!tstr1 || !tstr2) {
1649 fprintf(stderr, "Could not parse layout file.\n");
1650 exit(EXIT_FAILURE);
1651 }
1652 new_regions[region_number].base = strtol(tstr1,
1653 (char **)NULL, 16);
1654 new_regions[region_number].limit = strtol(tstr2,
1655 (char **)NULL, 16);
1656 new_regions[region_number].size =
1657 new_regions[region_number].limit -
1658 new_regions[region_number].base + 1;
1659
1660 if (new_regions[region_number].size < 0)
1661 new_regions[region_number].size = 0;
1662 }
1663 fclose(romlayout);
1664
1665 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001666 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001667 if (new_regions[i].size == 0)
1668 continue;
1669
1670 if (new_regions[i].size < current_regions[i].size) {
1671 printf("DANGER: Region %s is shrinking.\n",
1672 region_name(i));
1673 printf(" The region will be truncated to fit.\n");
1674 printf(" This may result in an unusable image.\n");
1675 }
1676
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001677 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001678 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001679 fprintf(stderr, "Regions would overlap.\n");
1680 exit(EXIT_FAILURE);
1681 }
1682 }
1683
1684 /* detect if the image size should grow */
1685 if (new_extent < new_regions[i].limit)
1686 new_extent = new_regions[i].limit;
1687 }
1688
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001689 /* check if the image is actually a Flash Descriptor region */
1690 if (size == new_regions[0].size) {
1691 printf("The image is a single Flash Descriptor:\n");
1692 printf(" Only the descriptor will be modified\n");
1693 new_extent = size;
1694 } else {
1695 new_extent = next_pow2(new_extent - 1);
1696 if (new_extent != size) {
1697 printf("The image has changed in size.\n");
1698 printf("The old image is %d bytes.\n", size);
1699 printf("The new image is %d bytes.\n", new_extent);
1700 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001701 }
1702
1703 /* copy regions to a new image */
1704 new_image = malloc(new_extent);
1705 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001706 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001707 int copy_size = new_regions[i].size;
1708 int offset_current = 0, offset_new = 0;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001709 const struct region *current = &current_regions[i];
1710 const struct region *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001711
Bill XIEfa5f9942017-09-12 11:22:29 +08001712 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001713 continue;
1714
Bill XIEfa5f9942017-09-12 11:22:29 +08001715 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001716 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001717 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001718 if (i == REGION_BIOS)
1719 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001720 }
1721
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001722 if ((i == REGION_BIOS) && (new->size < current->size)) {
1723 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001724 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001725 }
1726
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001727 if (size < current->base + offset_current + copy_size) {
1728 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1729 region_name(i));
1730 continue;
1731 };
1732
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001733 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1734 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001735 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1736 offset_current, current->limit, current->size);
1737 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1738 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001739
Bill XIEfa5f9942017-09-12 11:22:29 +08001740 memcpy(new_image + new->base + offset_new,
1741 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001742 copy_size);
1743 }
1744
1745 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001746 frba = find_frba(new_image, new_extent);
1747 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001748 exit(EXIT_FAILURE);
1749
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001750 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001751 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001752 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001753
1754 write_image(filename, new_image, new_extent);
1755 free(new_image);
1756}
1757
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001758static void print_version(void)
1759{
1760 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1761 printf("Copyright (C) 2011 Google Inc.\n\n");
1762 printf
1763 ("This program is free software: you can redistribute it and/or modify\n"
1764 "it under the terms of the GNU General Public License as published by\n"
1765 "the Free Software Foundation, version 2 of the License.\n\n"
1766 "This program is distributed in the hope that it will be useful,\n"
1767 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1768 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001769 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001770}
1771
1772static void print_usage(const char *name)
1773{
1774 printf("usage: %s [-vhdix?] <filename>\n", name);
1775 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001776 " -d | --dump: dump intel firmware descriptor\n"
1777 " -f | --layout <filename> dump regions into a flashrom layout file\n"
Maximilian Brune347596a2023-03-05 20:55:32 +01001778 " -F | --fmap-layout <filename> dump IFD regions into a fmap layout template (.fmd) file\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001779 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1780 " -x | --extract: extract intel fd modules\n"
1781 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1782 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001783 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001784 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1785 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1786 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1787 " can only be used once per run:\n"
1788 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1789 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1790 " Dual Output Fast Read Support\n"
1791 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301792 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001793 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001794 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1795 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001796 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301797 " adl - Alder Lake\n"
1798 " aplk - Apollo Lake\n"
1799 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08001800 " lbg - Lewisburg PCH\n"
Jeff Dalyabd4b962022-01-06 00:52:30 -05001801 " dnv - Denverton\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001802 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301803 " glk - Gemini Lake\n"
1804 " icl - Ice Lake\n"
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001805 " ifd2 - IFDv2 Platform\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301806 " jsl - Jasper Lake\n"
1807 " sklkbl - Sky Lake/Kaby Lake\n"
1808 " tgl - Tiger Lake\n"
Patrick Rudolph16598742022-10-21 15:13:43 +02001809 " wbg - Wellsburg\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001810 " -S | --setpchstrap Write a PCH strap\n"
1811 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001812 " -v | --version: print the version\n"
1813 " -h | --help: print this help\n\n"
Jeff Daly3623eca2022-01-05 23:51:40 -05001814 "<region> is one of Descriptor, BIOS, ME, GbE, Platform Data, Secondary BIOS, "
1815 "Device Exp1, EC, Device Exp2, IE, 10GbE_0, 10GbE_1, PTT\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001816 "\n");
1817}
1818
1819int main(int argc, char *argv[])
1820{
1821 int opt, option_index = 0;
1822 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001823 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001824 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Maximilian Brune347596a2023-03-05 20:55:32 +01001825 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0, mode_fmap_template = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001826 char *region_type_string = NULL, *region_fname = NULL;
1827 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001828 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001829 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001830 unsigned int value = 0;
1831 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001832 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001833 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1834
Bill XIEfa5f9942017-09-12 11:22:29 +08001835 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001836 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001837 {"layout", 1, NULL, 'f'},
Maximilian Brune347596a2023-03-05 20:55:32 +01001838 {"fmap-template", 1, NULL, 'F'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001839 {"extract", 0, NULL, 'x'},
1840 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001841 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001842 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001843 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001844 {"density", 1, NULL, 'D'},
1845 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001846 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001847 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001848 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301849 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001850 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001851 {"version", 0, NULL, 'v'},
1852 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001853 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001854 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001855 {"setpchstrap", 1, NULL, 'S'},
1856 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001857 {0, 0, 0, 0}
1858 };
1859
Maximilian Brune347596a2023-03-05 20:55:32 +01001860 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 +01001861 long_options, &option_index)) != EOF) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001862 switch (opt) {
1863 case 'd':
1864 mode_dump = 1;
1865 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001866 case 'S':
1867 mode_setstrap = 1;
1868 pchstrap = strtoul(optarg, NULL, 0);
1869 break;
1870 case 'V':
1871 value = strtoul(optarg, NULL, 0);
1872 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001873 case 'f':
1874 mode_layout = 1;
1875 layout_fname = strdup(optarg);
1876 if (!layout_fname) {
1877 fprintf(stderr, "No layout file specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001878 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Chris Douglass03ce0142014-02-26 13:30:13 -05001879 exit(EXIT_FAILURE);
1880 }
1881 break;
Maximilian Brune347596a2023-03-05 20:55:32 +01001882 case 'F':
1883 mode_fmap_template = 1;
1884 layout_fname = strdup(optarg);
1885 if (!layout_fname) {
1886 fprintf(stderr, "No layout file specified\n");
1887 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
1888 exit(EXIT_FAILURE);
1889 }
1890 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001891 case 'x':
1892 mode_extract = 1;
1893 break;
1894 case 'i':
1895 // separate type and file name
1896 region_type_string = strdup(optarg);
1897 region_fname = strchr(region_type_string, ':');
1898 if (!region_fname) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001899 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001900 exit(EXIT_FAILURE);
1901 }
1902 region_fname[0] = '\0';
1903 region_fname++;
1904 // Descriptor, BIOS, ME, GbE, Platform
1905 // valid type?
1906 if (!strcasecmp("Descriptor", region_type_string))
1907 region_type = 0;
1908 else if (!strcasecmp("BIOS", region_type_string))
1909 region_type = 1;
1910 else if (!strcasecmp("ME", region_type_string))
1911 region_type = 2;
1912 else if (!strcasecmp("GbE", region_type_string))
1913 region_type = 3;
Jeff Daly3623eca2022-01-05 23:51:40 -05001914 else if (!strcasecmp("Platform Data", region_type_string))
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001915 region_type = 4;
Jeff Daly3623eca2022-01-05 23:51:40 -05001916 else if (!strcasecmp("Device Exp1", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001917 region_type = 5;
Jeff Daly3623eca2022-01-05 23:51:40 -05001918 else if (!strcasecmp("Secondary BIOS", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001919 region_type = 6;
Jeff Daly3623eca2022-01-05 23:51:40 -05001920 else if (!strcasecmp("Reserved", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001921 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001922 else if (!strcasecmp("EC", region_type_string))
1923 region_type = 8;
Jeff Daly3623eca2022-01-05 23:51:40 -05001924 else if (!strcasecmp("Device Exp2", region_type_string))
1925 region_type = 9;
1926 else if (!strcasecmp("IE", region_type_string))
1927 region_type = 10;
1928 else if (!strcasecmp("10GbE_0", region_type_string))
1929 region_type = 11;
1930 else if (!strcasecmp("10GbE_1", region_type_string))
1931 region_type = 12;
1932 else if (!strcasecmp("PTT", region_type_string))
1933 region_type = 15;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001934 if (region_type == -1) {
1935 fprintf(stderr, "No such region type: '%s'\n\n",
1936 region_type_string);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001937 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001938 exit(EXIT_FAILURE);
1939 }
1940 mode_inject = 1;
1941 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001942 case 'n':
1943 mode_newlayout = 1;
1944 layout_fname = strdup(optarg);
1945 if (!layout_fname) {
1946 fprintf(stderr, "No layout file specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001947 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001948 exit(EXIT_FAILURE);
1949 }
1950 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001951 case 'O':
1952 new_filename = strdup(optarg);
1953 if (!new_filename) {
1954 fprintf(stderr, "No output filename specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001955 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001956 exit(EXIT_FAILURE);
1957 }
1958 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001959 case 'D':
1960 mode_density = 1;
1961 new_density = strtoul(optarg, NULL, 0);
1962 switch (new_density) {
1963 case 512:
1964 new_density = COMPONENT_DENSITY_512KB;
1965 break;
1966 case 1:
1967 new_density = COMPONENT_DENSITY_1MB;
1968 break;
1969 case 2:
1970 new_density = COMPONENT_DENSITY_2MB;
1971 break;
1972 case 4:
1973 new_density = COMPONENT_DENSITY_4MB;
1974 break;
1975 case 8:
1976 new_density = COMPONENT_DENSITY_8MB;
1977 break;
1978 case 16:
1979 new_density = COMPONENT_DENSITY_16MB;
1980 break;
1981 case 32:
1982 new_density = COMPONENT_DENSITY_32MB;
1983 break;
1984 case 64:
1985 new_density = COMPONENT_DENSITY_64MB;
1986 break;
1987 case 0:
1988 new_density = COMPONENT_DENSITY_UNUSED;
1989 break;
1990 default:
1991 printf("error: Unknown density\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001992 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Jan Tatjefa317512016-03-11 00:52:07 +01001993 exit(EXIT_FAILURE);
1994 }
1995 break;
1996 case 'C':
1997 selected_chip = strtol(optarg, NULL, 0);
1998 if (selected_chip > 2) {
1999 fprintf(stderr, "error: Invalid chip selection\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002000 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Jan Tatjefa317512016-03-11 00:52:07 +01002001 exit(EXIT_FAILURE);
2002 }
2003 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08002004 case 'M':
2005 mode_altmedisable = 1;
2006 altmedisable = strtol(optarg, NULL, 0);
2007 if (altmedisable > 1) {
2008 fprintf(stderr, "error: Illegal value\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002009 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Bill XIEb3e15a22017-09-07 18:34:50 +08002010 exit(EXIT_FAILURE);
2011 }
2012 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002013 case 's':
2014 // Parse the requested SPI frequency
2015 inputfreq = strtol(optarg, NULL, 0);
2016 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002017 case 17:
2018 spifreq = SPI_FREQUENCY_17MHZ;
2019 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002020 case 20:
2021 spifreq = SPI_FREQUENCY_20MHZ;
2022 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002023 case 30:
2024 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
2025 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002026 case 33:
2027 spifreq = SPI_FREQUENCY_33MHZ;
2028 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002029 case 48:
2030 spifreq = SPI_FREQUENCY_48MHZ;
2031 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002032 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002033 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002034 break;
2035 default:
2036 fprintf(stderr, "Invalid SPI Frequency: %d\n",
2037 inputfreq);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002038 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002039 exit(EXIT_FAILURE);
2040 }
2041 mode_spifreq = 1;
2042 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002043 case 'e':
2044 mode_em100 = 1;
2045 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002046 case 'l':
2047 mode_locked = 1;
2048 if (mode_unlocked == 1) {
2049 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
2050 exit(EXIT_FAILURE);
2051 }
2052 break;
Usha P412679d2020-10-15 11:25:08 +05302053 case 'r':
2054 mode_read = 1;
2055 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002056 case 'u':
2057 mode_unlocked = 1;
2058 if (mode_locked == 1) {
2059 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
2060 exit(EXIT_FAILURE);
2061 }
2062 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002063 case 'p':
2064 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002065 platform = PLATFORM_APL;
2066 } else if (!strcmp(optarg, "cnl")) {
2067 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08002068 } else if (!strcmp(optarg, "lbg")) {
2069 platform = PLATFORM_LBG;
Jeff Dalyabd4b962022-01-06 00:52:30 -05002070 } else if (!strcmp(optarg, "dnv")) {
2071 platform = PLATFORM_DNV;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002072 } else if (!strcmp(optarg, "ehl")) {
2073 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002074 } else if (!strcmp(optarg, "glk")) {
2075 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05302076 } else if (!strcmp(optarg, "icl")) {
2077 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05302078 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002079 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07002080 } else if (!strcmp(optarg, "sklkbl")) {
2081 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07002082 } else if (!strcmp(optarg, "tgl")) {
2083 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05302084 } else if (!strcmp(optarg, "adl")) {
2085 platform = PLATFORM_ADL;
Wonkyu Kim3922aa52022-02-02 15:19:05 -08002086 } else if (!strcmp(optarg, "ifd2")) {
2087 platform = PLATFORM_IFD2;
Subrata Banikca82e612022-01-20 18:51:21 +05302088 } else if (!strcmp(optarg, "mtl")) {
2089 platform = PLATFORM_MTL;
Patrick Rudolph16598742022-10-21 15:13:43 +02002090 } else if (!strcmp(optarg, "wbg")) {
2091 platform = PLATFORM_WBG;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002092 } else {
2093 fprintf(stderr, "Unknown platform: %s\n", optarg);
2094 exit(EXIT_FAILURE);
2095 }
2096 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06002097 case 't':
2098 mode_validate = 1;
2099 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002100 case 'v':
2101 print_version();
2102 exit(EXIT_SUCCESS);
2103 break;
2104 case 'h':
2105 case '?':
2106 default:
2107 print_usage(argv[0]);
2108 exit(EXIT_SUCCESS);
2109 break;
2110 }
2111 }
2112
Maximilian Brune347596a2023-03-05 20:55:32 +01002113 if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject +
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002114 mode_setstrap + mode_newlayout + (mode_spifreq | mode_em100 |
2115 mode_unlocked | mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002116 fprintf(stderr, "You may not specify more than one mode.\n\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002117 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002118 exit(EXIT_FAILURE);
2119 }
2120
Maximilian Brune347596a2023-03-05 20:55:32 +01002121 if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject +
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002122 mode_setstrap + mode_newlayout + mode_spifreq + mode_em100 +
2123 mode_locked + mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002124 fprintf(stderr, "You need to specify a mode.\n\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002125 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002126 exit(EXIT_FAILURE);
2127 }
2128
2129 if (optind + 1 != argc) {
2130 fprintf(stderr, "You need to specify a file.\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
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002135 if (platform == -1)
2136 fprintf(stderr, "Warning: No platform specified. Output may be incomplete\n");
2137
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002138 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06002139 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002140 if (bios_fd == -1) {
2141 perror("Could not open file");
2142 exit(EXIT_FAILURE);
2143 }
2144 struct stat buf;
2145 if (fstat(bios_fd, &buf) == -1) {
2146 perror("Could not stat file");
2147 exit(EXIT_FAILURE);
2148 }
2149 int size = buf.st_size;
2150
2151 printf("File %s is %d bytes\n", filename, size);
2152
2153 char *image = malloc(size);
2154 if (!image) {
2155 printf("Out of memory.\n");
2156 exit(EXIT_FAILURE);
2157 }
2158
2159 if (read(bios_fd, image, size) != size) {
2160 perror("Could not read file");
2161 exit(EXIT_FAILURE);
2162 }
2163
2164 close(bios_fd);
2165
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002166 // generate new filename
2167 if (new_filename == NULL) {
2168 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
2169 if (!new_filename) {
2170 printf("Out of memory.\n");
2171 exit(EXIT_FAILURE);
2172 }
2173 // - 5: leave room for ".new\0"
2174 strcpy(new_filename, filename);
2175 strcat(new_filename, ".new");
2176 }
2177
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002178 check_ifd_version(image, size);
2179
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002180 if (mode_dump)
2181 dump_fd(image, size);
2182
Chris Douglass03ce0142014-02-26 13:30:13 -05002183 if (mode_layout)
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002184 dump_flashrom_layout(image, size, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -05002185
Maximilian Brune347596a2023-03-05 20:55:32 +01002186 if (mode_fmap_template)
2187 create_fmap_template(image, size, layout_fname);
2188
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002189 if (mode_extract)
2190 write_regions(image, size);
2191
Mathew Kingc7ddc992019-08-08 14:59:25 -06002192 if (mode_validate)
2193 validate_layout(image, size);
2194
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002195 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002196 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002197 region_fname);
2198
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002199 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002200 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002201
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002202 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002203 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002204
Jan Tatjefa317512016-03-11 00:52:07 +01002205 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002206 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002207
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002208 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002209 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002210
Alexander Couzensd12ea112016-09-10 13:33:05 +02002211 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002212 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002213
Usha P412679d2020-10-15 11:25:08 +05302214 if (mode_read)
2215 enable_cpu_read_me(new_filename, image, size);
2216
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002217 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002218 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002219
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002220 if (mode_setstrap) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002221 struct fpsba *fpsba = find_fpsba(image, size);
2222 const struct fdbar *fdb = find_fd(image, size);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002223 set_pchstrap(fpsba, fdb, pchstrap, value);
2224 write_image(new_filename, image, size);
2225 }
2226
Bill XIEb3e15a22017-09-07 18:34:50 +08002227 if (mode_altmedisable) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002228 struct fpsba *fpsba = find_fpsba(image, size);
2229 struct fmsba *fmsba = find_fmsba(image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002230 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002231 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002232 }
2233
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002234 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002235 free(image);
2236
2237 return 0;
2238}