blob: 516570e0a3a95587655ead81ae03d12eb880f3c0 [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
Subrata Banik5fe22972024-01-30 00:31:08 +053047union gprd {
48 struct bit_field {
49 /*
50 * Start Address: bit 0-14 of the GPRD represents the
51 * protected region start address, where bit 0-11 of
52 * the start address are assumed to be zero.
53 */
54 uint32_t start:15;
55
56 /* Specifies read protection is enabled */
57 uint32_t read_protect_en:1;
58
59 /*
60 * End Address: bit 16-30 of the GPRD represents the
61 * protected region end address, where bit 0-11 of
62 * the end address are assumed to be 0xfff.
63 */
64 uint32_t end:15;
65
66 /* Specifies write protection is enabled */
67 uint32_t write_protect_en:1;
68 } __packed data;
69
70 uint32_t value;
71};
72
Maximilian Bruneab0e6802023-03-05 04:34:40 +010073static int max_regions_from_fdbar(const struct fdbar *fdb);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +020074
Duncan Laurie1f7fd722015-06-22 11:14:48 -070075static int ifd_version;
Bill XIEb3e15a22017-09-07 18:34:50 +080076static int chipset;
Bill XIEfa5f9942017-09-12 11:22:29 +080077static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010078static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070079static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050080
Duncan Laurie1f7fd722015-06-22 11:14:48 -070081static const struct region_name region_names[MAX_REGIONS] = {
Mathew Kingc7ddc992019-08-08 14:59:25 -060082 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin", "SI_DESC" },
83 { "BIOS", "bios", "flashregion_1_bios.bin", "SI_BIOS" },
84 { "Intel ME", "me", "flashregion_2_intel_me.bin", "SI_ME" },
85 { "GbE", "gbe", "flashregion_3_gbe.bin", "SI_GBE" },
86 { "Platform Data", "pd", "flashregion_4_platform_data.bin", "SI_PDR" },
Jeff Daly3623eca2022-01-05 23:51:40 -050087 { "Device Exp1", "devexp", "flashregion_5_device_exp.bin", "SI_DEVICEEXT" },
88 { "Secondary BIOS", "bios2", "flashregion_6_bios2.bin", "SI_BIOS2" },
89 { "Reserved", "res7", "flashregion_7_reserved.bin", NULL },
Mathew Kingc7ddc992019-08-08 14:59:25 -060090 { "EC", "ec", "flashregion_8_ec.bin", "SI_EC" },
Jeff Daly3623eca2022-01-05 23:51:40 -050091 { "Device Exp2", "devexp2", "flashregion_9_device_exp.bin", "SI_DEVICEEXT2" },
92 { "IE", "ie", "flashregion_10_ie.bin", "SI_IE" },
93 { "10GbE_0", "10gbe_0", "flashregion_11_10gbe0.bin", "SI_10GBE0" },
94 { "10GbE_1", "10gbe_1", "flashregion_12_10gbe1.bin", "SI_10GBE1" },
95 { "Reserved", "res13", "flashregion_13_reserved.bin", NULL },
96 { "Reserved", "res14", "flashregion_14_reserved.bin", NULL },
97 { "PTT", "ptt", "flashregion_15_ptt.bin", "SI_PTT" },
Chris Douglass03ce0142014-02-26 13:30:13 -050098};
99
Bill XIEb3e15a22017-09-07 18:34:50 +0800100/* port from flashrom */
101static const char *const ich_chipset_names[] = {
102 "Unknown ICH",
Bill XIEb3e15a22017-09-07 18:34:50 +0800103 "ICH8",
104 "ICH9",
105 "ICH10",
Subrata Banik89db2252020-08-26 14:49:17 +0530106 "Unknown PCH",
Bill XIEb3e15a22017-09-07 18:34:50 +0800107 "5 series Ibex Peak",
108 "6 series Cougar Point",
109 "7 series Panther Point",
110 "8 series Lynx Point",
111 "Baytrail",
112 "8 series Lynx Point LP",
113 "8 series Wellsburg",
114 "9 series Wildcat Point",
115 "9 series Wildcat Point LP",
Subrata Banik8c082e52021-06-10 23:02:29 +0530116 "Apollo Lake: N3xxx, J3xxx",
Subrata Banik89db2252020-08-26 14:49:17 +0530117 "Gemini Lake: N5xxx, J5xxx, N4xxx, J4xxx",
Subrata Banik8c082e52021-06-10 23:02:29 +0530118 "Jasper Lake: N6xxx, N51xx, N45xx",
119 "Elkhart Lake: x6000 series Atom",
Subrata Banik89db2252020-08-26 14:49:17 +0530120 "100/200 series Sunrise Point",
Subrata Banik8c082e52021-06-10 23:02:29 +0530121 "300 series Cannon Point",
122 "400 series Ice Point",
Subrata Banika5f47812020-09-29 11:43:01 +0530123 "500 series Tiger Point/ 600 series Alder Point",
Subrata Banik9cd85d02023-05-24 23:18:49 +0530124 "800 series Meteor Lake",
Bill XIEb3e15a22017-09-07 18:34:50 +0800125 "C620 series Lewisburg",
Patrick Rudolph19209002022-10-22 10:34:05 +0200126 "Denverton: C39xx",
Bill XIEb3e15a22017-09-07 18:34:50 +0800127 NULL
128};
129
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100130static struct fdbar *find_fd(char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700131{
132 int i, found = 0;
133
134 /* Scan for FD signature */
135 for (i = 0; i < (size - 4); i += 4) {
136 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
137 found = 1;
138 break; // signature found.
139 }
140 }
141
142 if (!found) {
143 printf("No Flash Descriptor found in this image\n");
144 return NULL;
145 }
146
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100147 struct fdbar *fdb = (struct fdbar *) (image + i);
Bill XIE612ec0e2017-08-30 16:10:27 +0800148 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
149}
150
Stefan Tauner0d226142018-08-05 18:56:53 +0200151static char *find_flumap(char *image, int size)
152{
153 /* The upper map is located in the word before the 256B-long OEM section
154 * at the end of the 4kB-long flash descriptor. In the official
155 * documentation this is defined as FDBAR + 0xEFC. However, starting
156 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
157 * has moved 16 bytes back to offset 0x10 of the image. Although
158 * official documentation still maintains the offset relative to FDBAR
159 * this is wrong and a simple fixed offset from the start of the image
160 * works.
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100161 */
Stefan Tauner0d226142018-08-05 18:56:53 +0200162 char *flumap = image + 4096 - 256 - 4;
163 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
164}
165
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100166static struct fcba *find_fcba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800167{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100168 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800169 if (!fdb)
170 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100171 struct fcba *fcba = (struct fcba *) (image + ((fdb->flmap0 & 0xff) << 4));
Bill XIE612ec0e2017-08-30 16:10:27 +0800172 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
173
174}
175
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100176static struct fmba *find_fmba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800177{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100178 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800179 if (!fdb)
180 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100181 struct fmba *fmba = (struct fmba *) (image + ((fdb->flmap1 & 0xff) << 4));
Bill XIE612ec0e2017-08-30 16:10:27 +0800182 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
183}
184
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100185static struct frba *find_frba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800186{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100187 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800188 if (!fdb)
189 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100190 struct frba *frba =
191 (struct frba *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
Bill XIE612ec0e2017-08-30 16:10:27 +0800192 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
193}
194
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100195static struct fpsba *find_fpsba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800196{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100197 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800198 if (!fdb)
199 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100200 struct fpsba *fpsba =
201 (struct fpsba *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200202
203 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
204 if ((((char *)fpsba) + SSL) >= (image + size))
205 return NULL;
206 return fpsba;
Bill XIE612ec0e2017-08-30 16:10:27 +0800207}
208
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100209static struct fmsba *find_fmsba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800210{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100211 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800212 if (!fdb)
213 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100214 struct fmsba *fmsba = (struct fmsba *) (image + ((fdb->flmap2 & 0xff) << 4));
Bill XIE612ec0e2017-08-30 16:10:27 +0800215 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700216}
217
Bill XIEb3e15a22017-09-07 18:34:50 +0800218/* port from flashrom */
Subrata Banik8c082e52021-06-10 23:02:29 +0530219static enum ich_chipset ifd1_guess_chipset(char *image, int size)
Bill XIEb3e15a22017-09-07 18:34:50 +0800220{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100221 const struct fdbar *fdb = find_fd(image, size);
Subrata Banik8c082e52021-06-10 23:02:29 +0530222 if (!fdb)
223 exit(EXIT_FAILURE);
Bill XIEb3e15a22017-09-07 18:34:50 +0800224 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
225 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
226 uint32_t isl = (fdb->flmap1 >> 24);
Subrata Banik89db2252020-08-26 14:49:17 +0530227
228 /* Rest for IFD1 chipset type */
Bill XIEb3e15a22017-09-07 18:34:50 +0800229 if (iccriba == 0x00) {
230 if (msl == 0 && isl <= 2)
231 return CHIPSET_ICH8;
232 else if (isl <= 2)
233 return CHIPSET_ICH9;
234 else if (isl <= 10)
235 return CHIPSET_ICH10;
236 else if (isl <= 16)
237 return CHIPSET_5_SERIES_IBEX_PEAK;
238 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
239 return CHIPSET_5_SERIES_IBEX_PEAK;
240 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
241 if (msl == 0 && isl <= 17)
242 return CHIPSET_BAYTRAIL;
243 else if (msl <= 1 && isl <= 18)
244 return CHIPSET_6_SERIES_COUGAR_POINT;
245 else if (msl <= 1 && isl <= 21)
246 return CHIPSET_8_SERIES_LYNX_POINT;
247 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
248 return CHIPSET_9_SERIES_WILDCAT_POINT;
Bill XIEb3e15a22017-09-07 18:34:50 +0800249 }
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200250 return CHIPSET_PCH_UNKNOWN;
Bill XIEb3e15a22017-09-07 18:34:50 +0800251}
252
Subrata Banik8c082e52021-06-10 23:02:29 +0530253static enum ich_chipset ifd2_platform_to_chipset(const int pindex)
254{
255 switch (pindex) {
Subrata Banik6da003c2021-07-14 13:52:03 +0530256 case PLATFORM_APL:
257 return CHIPSET_N_J_SERIES_APOLLO_LAKE;
Subrata Banik8c082e52021-06-10 23:02:29 +0530258 case PLATFORM_GLK:
259 return CHIPSET_N_J_SERIES_GEMINI_LAKE;
260 case PLATFORM_JSL:
261 return CHIPSET_N_SERIES_JASPER_LAKE;
262 case PLATFORM_EHL:
263 return CHIPSET_x6000_SERIES_ELKHART_LAKE;
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200264 case PLATFORM_SKLKBL:
265 return CHIPSET_100_200_SERIES_SUNRISE_POINT;
Subrata Banik8c082e52021-06-10 23:02:29 +0530266 case PLATFORM_CNL:
267 return CHIPSET_300_SERIES_CANNON_POINT;
268 case PLATFORM_TGL:
269 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800270 case PLATFORM_IFD2:
Subrata Banik8c082e52021-06-10 23:02:29 +0530271 return CHIPSET_500_600_SERIES_TIGER_ALDER_POINT;
Subrata Banik9cd85d02023-05-24 23:18:49 +0530272 case PLATFORM_MTL:
273 return CHIPSET_800_SERIES_METEOR_LAKE;
Subrata Banik8c082e52021-06-10 23:02:29 +0530274 case PLATFORM_ICL:
275 return CHIPSET_400_SERIES_ICE_POINT;
Johnny Line273a022021-06-22 11:26:46 +0800276 case PLATFORM_LBG:
277 return CHIPSET_C620_SERIES_LEWISBURG;
Jeff Dalyabd4b962022-01-06 00:52:30 -0500278 case PLATFORM_DNV:
279 return CHIPSET_DENVERTON;
Patrick Rudolph16598742022-10-21 15:13:43 +0200280 case PLATFORM_WBG:
281 return CHIPSET_8_SERIES_WELLSBURG;
Subrata Banik8c082e52021-06-10 23:02:29 +0530282 default:
283 return CHIPSET_PCH_UNKNOWN;
284 }
285}
286
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700287/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700288 * Some newer platforms have re-defined the FCBA field that was used to
289 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
290 * have the required FCBA field, but are IFD v2 and return true if current
291 * platform is one of them.
292 */
293static int is_platform_ifd_2(void)
294{
295 static const int ifd_2_platforms[] = {
Subrata Banik6da003c2021-07-14 13:52:03 +0530296 PLATFORM_APL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700297 PLATFORM_GLK,
298 PLATFORM_CNL,
Johnny Line273a022021-06-22 11:26:46 +0800299 PLATFORM_LBG,
Jeff Dalyabd4b962022-01-06 00:52:30 -0500300 PLATFORM_DNV,
Aamir Bohra1018be22018-06-29 15:08:50 +0530301 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700302 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530303 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700304 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530305 PLATFORM_ADL,
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200306 PLATFORM_SKLKBL,
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800307 PLATFORM_IFD2,
Subrata Banikca82e612022-01-20 18:51:21 +0530308 PLATFORM_MTL,
Patrick Rudolph16598742022-10-21 15:13:43 +0200309 PLATFORM_WBG,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700310 };
311 unsigned int i;
312
313 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
314 if (platform == ifd_2_platforms[i])
315 return 1;
316 }
317
318 return 0;
319}
320
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700321static void check_ifd_version(char *image, int size)
322{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100323 const struct fdbar *fdb = find_fd(image, size);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200324
Subrata Banik8c082e52021-06-10 23:02:29 +0530325 if (is_platform_ifd_2()) {
Subrata Banik8c082e52021-06-10 23:02:29 +0530326 chipset = ifd2_platform_to_chipset(platform);
Patrick Rudolph16598742022-10-21 15:13:43 +0200327 if (chipset == CHIPSET_8_SERIES_WELLSBURG)
328 ifd_version = IFD_VERSION_1_5;
329 else
330 ifd_version = IFD_VERSION_2;
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200331 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS);
Subrata Banik8c082e52021-06-10 23:02:29 +0530332 } else {
333 ifd_version = IFD_VERSION_1;
334 chipset = ifd1_guess_chipset(image, size);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200335 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS_OLD);
Subrata Banik8c082e52021-06-10 23:02:29 +0530336 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700337}
338
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100339static struct region get_region(const struct frba *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700340{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500341 int base_mask;
342 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700343 uint32_t flreg;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100344 struct region region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500345
346 if (ifd_version >= IFD_VERSION_2)
347 base_mask = 0x7fff;
348 else
349 base_mask = 0xfff;
350
351 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700352
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400353 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800354 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700355 exit (EXIT_FAILURE);
356 }
357
Bill XIE4651d452017-09-12 11:54:48 +0800358 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700359 region.base = (flreg & base_mask) << 12;
360 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700361 region.size = region.limit - region.base + 1;
Maximilian Brune347596a2023-03-05 20:55:32 +0100362 region.type = region_type;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500363
Chris Douglass03ce0142014-02-26 13:30:13 -0500364 if (region.size < 0)
365 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700366
367 return region;
368}
369
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100370static void set_region(struct frba *frba, unsigned int region_type,
371 const struct region *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500372{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400373 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800374 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500375 exit (EXIT_FAILURE);
376 }
Bill XIE4651d452017-09-12 11:54:48 +0800377
378 frba->flreg[region_type] =
379 (((region->limit >> 12) & 0x7fff) << 16) |
380 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500381}
382
Bill XIEfa5f9942017-09-12 11:22:29 +0800383static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700384{
Bill XIEfa5f9942017-09-12 11:22:29 +0800385 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700386 fprintf(stderr, "Invalid region type.\n");
387 exit (EXIT_FAILURE);
388 }
389
Chris Douglass03ce0142014-02-26 13:30:13 -0500390 return region_names[region_type].pretty;
391}
392
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500393static int region_num(const char *name)
394{
Bill XIEfa5f9942017-09-12 11:22:29 +0800395 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500396
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200397 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500398 if (strcasecmp(name, region_names[i].pretty) == 0)
399 return i;
400 if (strcasecmp(name, region_names[i].terse) == 0)
401 return i;
402 }
403
404 return -1;
405}
406
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100407static void dump_region(unsigned int num, const struct frba *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700408{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100409 struct region region = get_region(frba, num);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700410 printf(" Flash Region %d (%s): %08x - %08x %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100411 num, region_name(num), region.base, region.limit,
412 region.size < 1 ? "(unused)" : "");
Chris Douglass03ce0142014-02-26 13:30:13 -0500413}
414
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200415static int sort_compare(const void *a, const void *b)
416{
417 return *(size_t *)a - *(size_t *)b;
418}
419
420/*
421 * IFDv1 always has 8 regions, while IFDv2 always has 16 regions.
422 *
423 * It's platform specific which regions are used or are reserved.
424 * The 'SPI programming guide' as the name says is a guide only,
425 * not a specification what the hardware actually does.
426 * The best to do is not to rely on the guide, but detect how many
427 * regions are present in the IFD and expose them all.
428 *
429 * Very early IFDv2 chipsets, sometimes unofficially referred to as
430 * IFDv1.5 platforms, only have 8 regions. To not corrupt the IFD when
431 * operating on an IFDv1.5 detect how much space is actually present
432 * in the IFD.
433 */
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100434static int max_regions_from_fdbar(const struct fdbar *fdb)
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200435{
436 const size_t fcba = (fdb->flmap0 & 0xff) << 4;
437 const size_t fmba = (fdb->flmap1 & 0xff) << 4;
438 const size_t frba = ((fdb->flmap0 >> 16) & 0xff) << 4;
439 const size_t fpsba = ((fdb->flmap1 >> 16) & 0xff) << 4;
440 const size_t flumap = 4096 - 256 - 4;
441 size_t sorted[5] = {fcba, fmba, frba, fpsba, flumap};
442
443 qsort(sorted, ARRAY_SIZE(sorted), sizeof(size_t), sort_compare);
444
445 for (size_t i = 0; i < 4; i++) {
446 /*
447 * Find FRBA in the sorted array and determine the size of the
448 * region by the start of the next region. Every region requires
449 * 4 bytes of space.
450 */
451 if (sorted[i] == frba)
452 return MIN((sorted[i+1] - sorted[i])/4, MAX_REGIONS);
453 }
454 /* Never reaches this point */
455 return 0;
456}
457
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100458static void dump_frba(const struct frba *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700459{
Bill XIE4651d452017-09-12 11:54:48 +0800460 unsigned int i;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100461 struct region region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700462 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800463 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530464 region = get_region(frba, i);
465 /* Skip unused & reserved Flash Region */
466 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
467 continue;
468
Bill XIE4651d452017-09-12 11:54:48 +0800469 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
470 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700471 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700472}
473
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100474static void dump_flashrom_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500475{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100476 const struct frba *frba = find_frba(image, size);
477 if (!frba)
478 exit(EXIT_FAILURE);
Chris Douglass03ce0142014-02-26 13:30:13 -0500479
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100480 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
Chris Douglass03ce0142014-02-26 13:30:13 -0500481 if (layout_fd == -1) {
482 perror("Could not open file");
483 exit(EXIT_FAILURE);
484 }
485
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100486 for (unsigned int i = 0; i < max_regions; i++) {
487 struct region region = get_region(frba, i);
Maximilian Brune2c895aa2023-04-24 19:28:21 +0200488
489 /* A region limit of 0 is an indicator of an unused region
490 * A region base of 7FFFh is an indicator of a reserved region
491 */
492 if (region.limit == 0 || region.base == 0x07FFF000)
Alexander Couzenseff596b2016-10-08 00:53:09 +0200493 continue;
494
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100495 char buf[LAYOUT_LINELEN];
496 snprintf(buf, LAYOUT_LINELEN, "%08x:%08x %s\n", region.base, region.limit, region_names[i].terse);
Chris Douglass03ce0142014-02-26 13:30:13 -0500497 if (write(layout_fd, buf, strlen(buf)) < 0) {
498 perror("Could not write to file");
499 exit(EXIT_FAILURE);
500 }
501 }
502 close(layout_fd);
503 printf("Wrote layout to %s\n", layout_fname);
504}
505
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530506static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700507{
508 switch (freq) {
509 case SPI_FREQUENCY_20MHZ:
510 printf("20MHz");
511 break;
512 case SPI_FREQUENCY_33MHZ:
513 printf("33MHz");
514 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700515 case SPI_FREQUENCY_48MHZ:
516 printf("48MHz");
517 break;
518 case SPI_FREQUENCY_50MHZ_30MHZ:
519 switch (ifd_version) {
520 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +0200521 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700522 printf("50MHz");
523 break;
524 case IFD_VERSION_2:
525 printf("30MHz");
526 break;
527 }
528 break;
529 case SPI_FREQUENCY_17MHZ:
530 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700531 break;
532 default:
533 printf("unknown<%x>MHz", freq);
534 }
535}
536
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530537static void _decode_spi_frequency_500_series(unsigned int freq)
538{
539 switch (freq) {
540 case SPI_FREQUENCY_100MHZ:
541 printf("100MHz");
542 break;
543 case SPI_FREQUENCY_50MHZ:
544 printf("50MHz");
545 break;
546 case SPI_FREQUENCY_500SERIES_33MHZ:
547 printf("33MHz");
548 break;
549 case SPI_FREQUENCY_25MHZ:
550 printf("25MHz");
551 break;
552 case SPI_FREQUENCY_14MHZ:
553 printf("14MHz");
554 break;
555 default:
556 printf("unknown<%x>MHz", freq);
557 }
558}
559
560static void decode_spi_frequency(unsigned int freq)
561{
Subrata Banik9cd85d02023-05-24 23:18:49 +0530562 switch (chipset) {
563 case CHIPSET_500_600_SERIES_TIGER_ALDER_POINT:
564 case CHIPSET_800_SERIES_METEOR_LAKE:
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530565 _decode_spi_frequency_500_series(freq);
Subrata Banik9cd85d02023-05-24 23:18:49 +0530566 break;
567 default:
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530568 _decode_spi_frequency(freq);
Subrata Banik9cd85d02023-05-24 23:18:49 +0530569 }
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530570}
571
Subrata Banike5d39922020-08-26 16:01:42 +0530572static void _decode_espi_frequency(unsigned int freq)
573{
574 switch (freq) {
575 case ESPI_FREQUENCY_20MHZ:
576 printf("20MHz");
577 break;
578 case ESPI_FREQUENCY_24MHZ:
579 printf("24MHz");
580 break;
581 case ESPI_FREQUENCY_30MHZ:
582 printf("30MHz");
583 break;
584 case ESPI_FREQUENCY_48MHZ:
585 printf("48MHz");
586 break;
587 case ESPI_FREQUENCY_60MHZ:
588 printf("60MHz");
589 break;
590 case ESPI_FREQUENCY_17MHZ:
591 printf("17MHz");
592 break;
593 default:
594 printf("unknown<%x>MHz", freq);
595 }
596}
597
598static void _decode_espi_frequency_500_series(unsigned int freq)
599{
600 switch (freq) {
601 case ESPI_FREQUENCY_500SERIES_20MHZ:
602 printf("20MHz");
603 break;
604 case ESPI_FREQUENCY_500SERIES_24MHZ:
605 printf("24MHz");
606 break;
607 case ESPI_FREQUENCY_500SERIES_25MHZ:
608 printf("25MHz");
609 break;
610 case ESPI_FREQUENCY_500SERIES_48MHZ:
611 printf("48MHz");
612 break;
613 case ESPI_FREQUENCY_500SERIES_60MHZ:
614 printf("60MHz");
615 break;
616 default:
617 printf("unknown<%x>MHz", freq);
618 }
619}
620
Subrata Banik9cd85d02023-05-24 23:18:49 +0530621static void _decode_espi_frequency_800_series(unsigned int freq)
622{
623 switch (freq) {
624 case ESPI_FREQUENCY_800SERIES_20MHZ:
625 printf("20MHz");
626 break;
627 case ESPI_FREQUENCY_800SERIES_25MHZ:
628 printf("25MHz");
629 break;
630 case ESPI_FREQUENCY_800SERIES_33MHZ:
631 printf("33MHz");
632 break;
633 case ESPI_FREQUENCY_800SERIES_50MHZ:
634 printf("50MHz");
635 break;
636 default:
637 printf("unknown<%x>MHz", freq);
638 }
639}
640
Subrata Banike5d39922020-08-26 16:01:42 +0530641static void decode_espi_frequency(unsigned int freq)
642{
Subrata Banika5f47812020-09-29 11:43:01 +0530643 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530644 _decode_espi_frequency_500_series(freq);
Subrata Banik9cd85d02023-05-24 23:18:49 +0530645 else if (chipset == CHIPSET_800_SERIES_METEOR_LAKE)
646 _decode_espi_frequency_800_series(freq);
Subrata Banike5d39922020-08-26 16:01:42 +0530647 else
648 _decode_espi_frequency(freq);
649}
650
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700651static void decode_component_density(unsigned int density)
652{
653 switch (density) {
654 case COMPONENT_DENSITY_512KB:
655 printf("512KB");
656 break;
657 case COMPONENT_DENSITY_1MB:
658 printf("1MB");
659 break;
660 case COMPONENT_DENSITY_2MB:
661 printf("2MB");
662 break;
663 case COMPONENT_DENSITY_4MB:
664 printf("4MB");
665 break;
666 case COMPONENT_DENSITY_8MB:
667 printf("8MB");
668 break;
669 case COMPONENT_DENSITY_16MB:
670 printf("16MB");
671 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700672 case COMPONENT_DENSITY_32MB:
673 printf("32MB");
674 break;
675 case COMPONENT_DENSITY_64MB:
676 printf("64MB");
677 break;
678 case COMPONENT_DENSITY_UNUSED:
679 printf("UNUSED");
680 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700681 default:
682 printf("unknown<%x>MB", density);
683 }
684}
685
Subrata Banik26058dc2020-08-26 15:12:16 +0530686static int is_platform_with_pch(void)
687{
688 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
689 return 1;
690
691 return 0;
692}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530693
694/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
695static int is_platform_with_100x_series_pch(void)
696{
697 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banik9cd85d02023-05-24 23:18:49 +0530698 chipset <= CHIPSET_800_SERIES_METEOR_LAKE)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530699 return 1;
700
701 return 0;
702}
703
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100704static void dump_fcba(const struct fcba *fcba, const struct fpsba *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700705{
Subrata Banike5d39922020-08-26 16:01:42 +0530706 unsigned int freq;
707
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700708 printf("\nFound Component Section\n");
709 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700710 printf(" Dual Output Fast Read Support: %ssupported\n",
711 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700712 printf(" Read ID/Read Status Clock Frequency: ");
713 decode_spi_frequency((fcba->flcomp >> 27) & 7);
714 printf("\n Write/Erase Clock Frequency: ");
715 decode_spi_frequency((fcba->flcomp >> 24) & 7);
716 printf("\n Fast Read Clock Frequency: ");
717 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700718 printf("\n Fast Read Support: %ssupported",
719 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530720 if (is_platform_with_100x_series_pch() &&
721 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
722 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530723 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530724 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
Subrata Banik9cd85d02023-05-24 23:18:49 +0530725 else if (chipset == CHIPSET_800_SERIES_METEOR_LAKE)
726 freq = (fpsba->pchstrp[65] & 0x38) >> 3;
Subrata Banike5d39922020-08-26 16:01:42 +0530727 else
728 freq = (fcba->flcomp >> 17) & 7;
729 decode_espi_frequency(freq);
730 } else {
731 printf("\n Read Clock Frequency: ");
732 decode_spi_frequency((fcba->flcomp >> 17) & 7);
733 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700734
735 switch (ifd_version) {
736 case IFD_VERSION_1:
737 printf("\n Component 2 Density: ");
738 decode_component_density((fcba->flcomp >> 3) & 7);
739 printf("\n Component 1 Density: ");
740 decode_component_density(fcba->flcomp & 7);
741 break;
Patrick Rudolph16598742022-10-21 15:13:43 +0200742 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700743 case IFD_VERSION_2:
744 printf("\n Component 2 Density: ");
745 decode_component_density((fcba->flcomp >> 4) & 0xf);
746 printf("\n Component 1 Density: ");
747 decode_component_density(fcba->flcomp & 0xf);
748 break;
749 }
750
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700751 printf("\n");
752 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700753 printf(" Invalid Instruction 3: 0x%02x\n",
754 (fcba->flill >> 24) & 0xff);
755 printf(" Invalid Instruction 2: 0x%02x\n",
756 (fcba->flill >> 16) & 0xff);
757 printf(" Invalid Instruction 1: 0x%02x\n",
758 (fcba->flill >> 8) & 0xff);
759 printf(" Invalid Instruction 0: 0x%02x\n",
760 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530761 if (is_platform_with_100x_series_pch()) {
762 printf("FLILL1 0x%08x\n", fcba->flpb);
763 printf(" Invalid Instruction 7: 0x%02x\n",
764 (fcba->flpb >> 24) & 0xff);
765 printf(" Invalid Instruction 6: 0x%02x\n",
766 (fcba->flpb >> 16) & 0xff);
767 printf(" Invalid Instruction 5: 0x%02x\n",
768 (fcba->flpb >> 8) & 0xff);
769 printf(" Invalid Instruction 4: 0x%02x\n",
770 fcba->flpb & 0xff);
771 } else {
772 printf("FLPB 0x%08x\n", fcba->flpb);
773 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
774 (fcba->flpb & 0xfff) << 12);
775 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700776}
777
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100778static void dump_fpsba(const struct fdbar *fdb, const struct fpsba *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700779{
Bill XIE4651d452017-09-12 11:54:48 +0800780 unsigned int i;
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200781 /* SoC Straps, aka PSL, aka ISL */
782 unsigned int SS = (fdb->flmap1 >> 24) & 0xff;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200783
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700784 printf("Found PCH Strap Section\n");
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200785 for (i = 0; i < SS; i++)
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200786 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800787
788 if (ifd_version >= IFD_VERSION_2) {
789 printf("HAP bit is %sset\n",
790 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100791 } else if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
Bill XIEb3e15a22017-09-07 18:34:50 +0800792 printf("ICH_MeDisable bit is %sset\n",
793 fpsba->pchstrp[0] & 1 ? "" : "not ");
794 } else {
795 printf("AltMeDisable bit is %sset\n",
796 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
797 }
798
Bill XIE4651d452017-09-12 11:54:48 +0800799 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700800}
801
802static void decode_flmstr(uint32_t flmstr)
803{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700804 int wr_shift, rd_shift;
805 if (ifd_version >= IFD_VERSION_2) {
806 wr_shift = FLMSTR_WR_SHIFT_V2;
807 rd_shift = FLMSTR_RD_SHIFT_V2;
808 } else {
809 wr_shift = FLMSTR_WR_SHIFT_V1;
810 rd_shift = FLMSTR_RD_SHIFT_V1;
811 }
812
813 /* EC region access only available on v2+ */
Jeff Dalyabd4b962022-01-06 00:52:30 -0500814 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700815 printf(" EC Region Write Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100816 (flmstr & (1 << (wr_shift + 8))) ?
817 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700818 printf(" Platform Data Region Write Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100819 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500820 if (PLATFORM_HAS_GBE_REGION) {
821 printf(" GbE Region Write Access: %s\n",
822 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
823 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700824 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700825 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700826 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700827 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700828 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700829 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500830 if (PLATFORM_HAS_10GBE_0_REGION) {
831 printf(" 10GbE_0 Write Access: %s\n",
832 (flmstr & (1 << (wr_shift + 11))) ? "enabled" : "disabled");
833 }
834 if (PLATFORM_HAS_10GBE_1_REGION) {
835 printf(" 10GbE_1 Write Access: %s\n",
836 (flmstr & (1 << 4)) ? "enabled" : "disabled");
837 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700838
Jeff Dalyabd4b962022-01-06 00:52:30 -0500839 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700840 printf(" EC Region Read Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100841 (flmstr & (1 << (rd_shift + 8))) ?
842 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700843 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700844 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500845 if (PLATFORM_HAS_GBE_REGION) {
846 printf(" GbE Region Read Access: %s\n",
847 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
848 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700849 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700850 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700851 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700852 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700853 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700854 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500855 if (PLATFORM_HAS_10GBE_0_REGION) {
856 printf(" 10GbE_0 Read Access: %s\n",
857 (flmstr & (1 << (rd_shift + 11))) ? "enabled" : "disabled");
858 }
859 if (PLATFORM_HAS_10GBE_1_REGION) {
860 printf(" 10GbE_1 Read Access: %s\n",
861 (flmstr & (1 << 0)) ? "enabled" : "disabled");
862 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700863
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700864 /* Requestor ID doesn't exist for ifd 2 */
865 if (ifd_version < IFD_VERSION_2)
866 printf(" Requester ID: 0x%04x\n\n",
867 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700868}
869
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100870static void dump_fmba(const struct fmba *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700871{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700872 printf("Found Master Section\n");
873 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
874 decode_flmstr(fmba->flmstr1);
875 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
876 decode_flmstr(fmba->flmstr2);
Jeff Dalyabd4b962022-01-06 00:52:30 -0500877 if (PLATFORM_HAS_GBE_REGION) {
878 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
879 decode_flmstr(fmba->flmstr3);
880 if (ifd_version >= IFD_VERSION_2) {
881 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
882 decode_flmstr(fmba->flmstr5);
883 }
884 } else {
885 printf("FLMSTR6: 0x%08x (IE)\n", fmba->flmstr6);
886 decode_flmstr(fmba->flmstr6);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700887 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700888}
889
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100890static void dump_fmsba(const struct fmsba *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700891{
Bill XIE612ec0e2017-08-30 16:10:27 +0800892 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700893 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800894 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
895 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800896
897 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
898 printf("MCH_MeDisable bit is %sset\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100899 fmsba->data[0] & 1 ? "" : "not ");
Bill XIEb3e15a22017-09-07 18:34:50 +0800900 printf("MCH_AltMeDisable bit is %sset\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100901 fmsba->data[0] & (1 << 7) ? "" : "not ");
Bill XIEb3e15a22017-09-07 18:34:50 +0800902 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700903}
904
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700905static void dump_jid(uint32_t jid)
906{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100907 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700908 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100909 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200910 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100911 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200912 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700913}
914
915static void dump_vscc(uint32_t vscc)
916{
917 printf(" Lower Erase Opcode: 0x%02x\n",
918 vscc >> 24);
919 printf(" Lower Write Enable on Write Status: 0x%02x\n",
920 vscc & (1 << 20) ? 0x06 : 0x50);
921 printf(" Lower Write Status Required: %s\n",
922 vscc & (1 << 19) ? "Yes" : "No");
923 printf(" Lower Write Granularity: %d bytes\n",
924 vscc & (1 << 18) ? 64 : 1);
925 printf(" Lower Block / Sector Erase Size: ");
926 switch ((vscc >> 16) & 0x3) {
927 case 0:
928 printf("256 Byte\n");
929 break;
930 case 1:
931 printf("4KB\n");
932 break;
933 case 2:
934 printf("8KB\n");
935 break;
936 case 3:
937 printf("64KB\n");
938 break;
939 }
940
941 printf(" Upper Erase Opcode: 0x%02x\n",
942 (vscc >> 8) & 0xff);
943 printf(" Upper Write Enable on Write Status: 0x%02x\n",
944 vscc & (1 << 4) ? 0x06 : 0x50);
945 printf(" Upper Write Status Required: %s\n",
946 vscc & (1 << 3) ? "Yes" : "No");
947 printf(" Upper Write Granularity: %d bytes\n",
948 vscc & (1 << 2) ? 64 : 1);
949 printf(" Upper Block / Sector Erase Size: ");
950 switch (vscc & 0x3) {
951 case 0:
952 printf("256 Byte\n");
953 break;
954 case 1:
955 printf("4KB\n");
956 break;
957 case 2:
958 printf("8KB\n");
959 break;
960 case 3:
961 printf("64KB\n");
962 break;
963 }
964}
965
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100966static void dump_vtba(const struct vtba *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700967{
968 int i;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100969 int max_len = sizeof(struct vtba)/sizeof(struct vscc);
Stefan Tauner0d226142018-08-05 18:56:53 +0200970 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700971
972 printf("ME VSCC table:\n");
973 for (i = 0; i < num; i++) {
974 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
975 dump_jid(vtba->entry[i].jid);
976 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
977 dump_vscc(vtba->entry[i].vscc);
978 }
979 printf("\n");
980}
981
Bill XIEfa5f9942017-09-12 11:22:29 +0800982static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700983{
984 int i, j;
985 printf("OEM Section:\n");
986 for (i = 0; i < 4; i++) {
987 printf("%02x:", i << 4);
988 for (j = 0; j < 16; j++)
989 printf(" %02x", oem[(i<<4)+j]);
990 printf ("\n");
991 }
992 printf ("\n");
993}
994
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700995static void dump_fd(char *image, int size)
996{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100997 const struct fdbar *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700998 if (!fdb)
999 exit(EXIT_FAILURE);
1000
Subrata Banik26058dc2020-08-26 15:12:16 +05301001 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
1002 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001003 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +05301004 if (!is_platform_with_100x_series_pch())
1005 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001006 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
1007 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
1008 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
1009
1010 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +05301011 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
1012 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001013 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
1014 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
1015 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
1016
Subrata Banikac1b1dd2020-08-26 15:29:58 +05301017 if (!is_platform_with_100x_series_pch()) {
1018 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
1019 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
1020 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
1021 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001022
Subrata Banik9cd85d02023-05-24 23:18:49 +05301023 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT ||
1024 chipset == CHIPSET_800_SERIES_METEOR_LAKE) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +05301025 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
1026 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
1027 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
1028 }
1029
Stefan Tauner0d226142018-08-05 18:56:53 +02001030 char *flumap = find_flumap(image, size);
1031 uint32_t flumap1 = *(uint32_t *)flumap;
1032 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001033 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +02001034 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001035 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +02001036 (flumap1 & 0xff) << 4);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001037 dump_vtba((struct vtba *)
Stefan Tauner0d226142018-08-05 18:56:53 +02001038 (image + ((flumap1 & 0xff) << 4)),
1039 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +08001040 dump_oem((const uint8_t *)image + 0xf00);
1041
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001042 const struct frba *frba = find_frba(image, size);
1043 const struct fcba *fcba = find_fcba(image, size);
1044 const struct fpsba *fpsba = find_fpsba(image, size);
1045 const struct fmba *fmba = find_fmba(image, size);
1046 const struct fmsba *fmsba = find_fmsba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001047
1048 if (frba && fcba && fpsba && fmba && fmsba) {
1049 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +05301050 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001051 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +08001052 dump_fmba(fmba);
1053 dump_fmsba(fmsba);
1054 } else {
1055 printf("FD is corrupted!\n");
1056 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001057}
1058
Maximilian Brune347596a2023-03-05 20:55:32 +01001059/* Takes an image containing an IFD and creates a Flashmap .fmd file template.
1060 * This flashmap will contain all IFD regions except the BIOS region.
1061 * The BIOS region is created by coreboot itself and 'should' match the IFD region
1062 * anyway (CONFIG_VALIDATE_INTEL_DESCRIPTOR should make sure). coreboot built system will use
1063 * this template to generate the final Flashmap file.
1064 */
1065static void create_fmap_template(char *image, int size, const char *layout_fname)
1066{
1067 const struct frba *frba = find_frba(image, size);
1068 if (!frba)
1069 exit(EXIT_FAILURE);
1070
1071 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1072 if (layout_fd == -1) {
1073 perror("Could not open file");
1074 exit(EXIT_FAILURE);
1075 }
1076
1077 char *bbuf = "FLASH@##ROM_BASE## ##ROM_SIZE## {\n";
1078 if (write(layout_fd, bbuf, strlen(bbuf)) < 0) {
1079 perror("Could not write to file");
1080 exit(EXIT_FAILURE);
1081 }
1082
1083 /* fmaptool requires regions in .fmd to be sorted.
1084 * => We need to sort the regions by base address before writing them in .fmd File
1085 */
1086 int count_regions = 0;
1087 struct region sorted_regions[MAX_REGIONS] = { 0 };
1088 for (unsigned int i = 0; i < max_regions; i++) {
1089 struct region region = get_region(frba, i);
Maximilian Brune2c895aa2023-04-24 19:28:21 +02001090
1091 /* A region limit of 0 is an indicator of an unused region
1092 * A region base of 7FFFh is an indicator of a reserved region
1093 */
1094 if (region.limit == 0 || region.base == 0x07FFF000)
Maximilian Brune347596a2023-03-05 20:55:32 +01001095 continue;
1096
Maximilian Brune794d1d72023-11-13 02:07:01 +01001097 /* Is there an FMAP equivalent? IFD reserved regions are usually thrown out
1098 * of the FMAP here
1099 */
1100 if (!region_names[region.type].fmapname) {
1101 printf("Skip IFD region: %s\n", region_names[region.type].pretty);
1102 continue;
1103 }
1104
Maximilian Brune347596a2023-03-05 20:55:32 +01001105 /* Here we decide to use the coreboot generated FMAP BIOS region, instead of
1106 * the one specified in the IFD. The case when IFD and FMAP BIOS region do not
1107 * match cannot be caught here, therefore one should still validate IFD and
1108 * FMAP via CONFIG_VALIDATE_INTEL_DESCRIPTOR
1109 */
1110 if (i == REGION_BIOS)
1111 continue;
1112
1113 sorted_regions[count_regions] = region;
1114 // basically insertion sort
1115 for (int i = count_regions-1; i >= 0 ; i--) {
1116 if (sorted_regions[i].base > sorted_regions[i+1].base) {
1117 struct region tmp = sorted_regions[i];
1118 sorted_regions[i] = sorted_regions[i+1];
1119 sorted_regions[i+1] = tmp;
1120 }
1121 }
1122 count_regions++;
1123 }
1124
1125 // Now write regions sorted by base address in the fmap file
1126 for (int i = 0; i < count_regions; i++) {
1127 struct region region = sorted_regions[i];
1128 char buf[LAYOUT_LINELEN];
1129 snprintf(buf, LAYOUT_LINELEN, "\t%s@0x%X 0x%X\n", region_names[region.type].fmapname, region.base, region.size);
1130 if (write(layout_fd, buf, strlen(buf)) < 0) {
1131 perror("Could not write to file");
1132 exit(EXIT_FAILURE);
1133 }
1134 }
1135
1136 char *ebuf = "\tSI_BIOS@##BIOS_BASE## ##BIOS_SIZE## {\n"
1137 "\t\t##CONSOLE_ENTRY##\n"
1138 "\t\t##MRC_CACHE_ENTRY##\n"
1139 "\t\t##SMMSTORE_ENTRY##\n"
1140 "\t\t##SPD_CACHE_ENTRY##\n"
1141 "\t\t##VPD_ENTRY##\n"
1142 "\t\tFMAP@##FMAP_BASE## ##FMAP_SIZE##\n"
1143 "\t\tCOREBOOT(CBFS)@##CBFS_BASE## ##CBFS_SIZE##\n"
1144 "\t}\n"
1145 "}\n";
1146 if (write(layout_fd, ebuf, strlen(ebuf)) < 0) {
1147 perror("Could not write to file");
1148 exit(EXIT_FAILURE);
1149 }
1150
1151 close(layout_fd);
1152 printf("Wrote layout to %s\n", layout_fname);
1153}
1154
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001155static void write_regions(char *image, int size)
1156{
Bill XIEfa5f9942017-09-12 11:22:29 +08001157 unsigned int i;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001158 const struct frba *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001159
Bill XIE612ec0e2017-08-30 16:10:27 +08001160 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001161 exit(EXIT_FAILURE);
1162
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001163 for (i = 0; i < max_regions; i++) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001164 struct region region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001165 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001166 if (region.size > 0) {
1167 int region_fd;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001168 region_fd = open(region_names[i].filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001169 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001170 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001171 if (region_fd < 0) {
1172 perror("Error while trying to open file");
1173 exit(EXIT_FAILURE);
1174 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001175 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001176 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001177 close(region_fd);
1178 }
1179 }
1180}
1181
Mathew Kingc7ddc992019-08-08 14:59:25 -06001182static void validate_layout(char *image, int size)
1183{
1184 uint i, errors = 0;
1185 struct fmap *fmap;
1186 long int fmap_loc = fmap_find((uint8_t *)image, size);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001187 const struct frba *frba = find_frba(image, size);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001188
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001189 if (fmap_loc < 0 || !frba) {
1190 printf("Could not find FMAP (%p) or Intel Flash Descriptor (%p)\n",
1191 (void *)fmap_loc, frba);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001192 exit(EXIT_FAILURE);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001193 }
Mathew Kingc7ddc992019-08-08 14:59:25 -06001194
1195 fmap = (struct fmap *)(image + fmap_loc);
1196
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001197 int matches = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001198 for (i = 0; i < max_regions; i++) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001199 struct region region = get_region(frba, i);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001200 if (region.size == 0)
1201 continue;
1202
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001203 const struct fmap_area *area = fmap_find_area(fmap, region_names[i].fmapname);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001204 if (!area)
1205 continue;
1206
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001207 matches++; // found a match between FMAP and IFD region
1208
1209 if ((uint)region.base != area->offset || (uint)region.size != area->size) {
1210 printf("Region mismatch between %s and %s\n", region_names[i].terse, area->name);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001211 printf(" Descriptor region %s:\n", region_names[i].terse);
1212 printf(" offset: 0x%08x\n", region.base);
1213 printf(" length: 0x%08x\n", region.size);
1214 printf(" FMAP area %s:\n", area->name);
1215 printf(" offset: 0x%08x\n", area->offset);
1216 printf(" length: 0x%08x\n", area->size);
1217 errors++;
1218 }
1219 }
1220
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001221 if (!matches) {
1222 // At least a BIOS region should be present in both IFD and FMAP
1223 fprintf(stderr, "Warning: Not a single IFD region found in FMAP\n");
1224 }
1225
Mathew Kingc7ddc992019-08-08 14:59:25 -06001226 if (errors > 0)
1227 exit(EXIT_FAILURE);
1228}
1229
Bill XIEfa5f9942017-09-12 11:22:29 +08001230static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001231{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001232 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001233 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001234
1235 // Now write out new image
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001236 new_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001237 if (new_fd < 0) {
1238 perror("Error while trying to open file");
1239 exit(EXIT_FAILURE);
1240 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001241 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001242 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001243 close(new_fd);
1244}
1245
Bill XIEfa5f9942017-09-12 11:22:29 +08001246static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001247 enum spi_frequency freq)
1248{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001249 struct fcba *fcba = find_fcba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001250 if (!fcba)
1251 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001252
1253 /* clear bits 21-29 */
1254 fcba->flcomp &= ~0x3fe00000;
1255 /* Read ID and Read Status Clock Frequency */
1256 fcba->flcomp |= freq << 27;
1257 /* Write and Erase Clock Frequency */
1258 fcba->flcomp |= freq << 24;
1259 /* Fast Read Clock Frequency */
1260 fcba->flcomp |= freq << 21;
1261
1262 write_image(filename, image, size);
1263}
1264
Bill XIEfa5f9942017-09-12 11:22:29 +08001265static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001266{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001267 struct fcba *fcba = find_fcba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001268 if (!fcba)
1269 exit(EXIT_FAILURE);
1270
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001271 int freq;
1272
1273 switch (ifd_version) {
1274 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +02001275 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001276 freq = SPI_FREQUENCY_20MHZ;
1277 break;
1278 case IFD_VERSION_2:
1279 freq = SPI_FREQUENCY_17MHZ;
1280 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001281 default:
1282 freq = SPI_FREQUENCY_17MHZ;
1283 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001284 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001285
1286 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001287 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001288}
1289
Bill XIEfa5f9942017-09-12 11:22:29 +08001290static void set_chipdensity(const char *filename, char *image, int size,
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001291 unsigned int density)
Jan Tatjefa317512016-03-11 00:52:07 +01001292{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001293 struct fcba *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001294 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001295 if (!fcba)
1296 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001297
1298 printf("Setting chip density to ");
1299 decode_component_density(density);
1300 printf("\n");
1301
1302 switch (ifd_version) {
1303 case IFD_VERSION_1:
1304 /* fail if selected density is not supported by this version */
1305 if ( (density == COMPONENT_DENSITY_32MB) ||
1306 (density == COMPONENT_DENSITY_64MB) ||
1307 (density == COMPONENT_DENSITY_UNUSED) ) {
1308 printf("error: Selected density not supported in IFD version 1.\n");
1309 exit(EXIT_FAILURE);
1310 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001311 mask = 0x7;
1312 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001313 break;
Patrick Rudolph16598742022-10-21 15:13:43 +02001314 case IFD_VERSION_1_5:
Jan Tatjefa317512016-03-11 00:52:07 +01001315 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001316 mask = 0xf;
1317 chip2_offset = 4;
1318 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001319 default:
1320 printf("error: Unknown IFD version\n");
1321 exit(EXIT_FAILURE);
1322 break;
1323 }
1324
1325 /* clear chip density for corresponding chip */
1326 switch (selected_chip) {
1327 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001328 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001329 break;
1330 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001331 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001332 break;
1333 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001334 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001335 break;
1336 }
1337
1338 /* set the new density */
1339 if (selected_chip == 1 || selected_chip == 0)
1340 fcba->flcomp |= (density); /* first chip */
1341 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001342 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001343
1344 write_image(filename, image, size);
1345}
1346
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001347static int check_region(const struct frba *frba, unsigned int region_type)
Duncan Laurie7775d672019-06-06 13:39:26 -07001348{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001349 struct region region;
Duncan Laurie7775d672019-06-06 13:39:26 -07001350
1351 if (!frba)
1352 return 0;
1353
1354 region = get_region(frba, region_type);
1355 return !!((region.base < region.limit) && (region.size > 0));
1356}
1357
Reka Normanafed45d2024-01-05 12:54:44 +11001358/*
1359 * Platforms from CNL onwards support up to 16 flash regions, not 12. The
1360 * permissions for regions [15:12] are stored in extended region read/write
1361 * access fields in the FLMSTR registers.
1362 *
1363 * FLMSTR with extended regions:
1364 * 31:20 Region Write Access
1365 * 19:8 Region Read Access
1366 * 7:4 Extended Region Write Access
1367 * 3:0 Extended Region Read Access
1368 *
1369 * FLMSTR without extended regions:
1370 * 31:20 Region Write Access
1371 * 19:8 Region Read Access
1372 * 7:0 Reserved
1373 */
1374static bool platform_has_extended_regions(void)
1375{
1376 switch (platform) {
1377 case PLATFORM_CNL:
1378 case PLATFORM_JSL:
1379 case PLATFORM_TGL:
1380 case PLATFORM_ADL:
1381 case PLATFORM_MTL:
1382 return true;
1383 default:
1384 return false;
1385 }
1386}
1387
Bill XIEfa5f9942017-09-12 11:22:29 +08001388static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001389{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001390 int wr_shift, rd_shift;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001391 struct fmba *fmba = find_fmba(image, size);
1392 const struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001393 if (!fmba)
1394 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001395
1396 if (ifd_version >= IFD_VERSION_2) {
1397 wr_shift = FLMSTR_WR_SHIFT_V2;
1398 rd_shift = FLMSTR_RD_SHIFT_V2;
1399
Reka Normanafed45d2024-01-05 12:54:44 +11001400 /*
1401 * Clear all read/write access bits. See comment on
1402 * platform_has_extended_regions() for bitfields.
1403 */
1404 if (platform_has_extended_regions()) {
1405 fmba->flmstr1 = 0;
1406 fmba->flmstr2 = 0;
1407 fmba->flmstr3 = 0;
1408 fmba->flmstr5 = 0;
1409 } else {
1410 fmba->flmstr1 &= 0xff;
1411 fmba->flmstr2 &= 0xff;
1412 fmba->flmstr3 &= 0xff;
1413 fmba->flmstr5 &= 0xff;
1414 }
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001415 } else {
1416 wr_shift = FLMSTR_WR_SHIFT_V1;
1417 rd_shift = FLMSTR_RD_SHIFT_V1;
1418
1419 fmba->flmstr1 = 0;
1420 fmba->flmstr2 = 0;
1421 /* Requestor ID */
1422 fmba->flmstr3 = 0x118;
1423 }
1424
Andrey Petrov96ecb772016-10-31 19:31:54 -07001425 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001426 case PLATFORM_APL:
1427 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001428 /* CPU/BIOS can read descriptor and BIOS */
1429 fmba->flmstr1 |= 0x3 << rd_shift;
1430 /* CPU/BIOS can write BIOS */
1431 fmba->flmstr1 |= 0x2 << wr_shift;
1432 /* TXE can read descriptor, BIOS and Device Expansion */
1433 fmba->flmstr2 |= 0x23 << rd_shift;
1434 /* TXE can only write Device Expansion */
1435 fmba->flmstr2 |= 0x20 << wr_shift;
1436 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001437 case PLATFORM_CNL:
1438 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001439 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001440 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301441 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001442 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301443 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001444 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +05301445 case PLATFORM_MTL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001446 /* CPU/BIOS can read descriptor and BIOS. */
1447 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1448 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1449 /* CPU/BIOS can write BIOS. */
1450 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1451 /* ME can read descriptor and ME. */
1452 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1453 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001454 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001455 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1456 if (check_region(frba, REGION_GBE)) {
1457 /* BIOS can read/write GbE. */
1458 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1459 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1460 /* ME can read GbE. */
1461 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1462 /* GbE can read descriptor and read/write GbE.. */
1463 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1464 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1465 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1466 }
1467 if (check_region(frba, REGION_PDR)) {
1468 /* BIOS can read/write PDR. */
1469 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1470 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1471 }
1472 if (check_region(frba, REGION_EC)) {
1473 /* BIOS can read EC. */
1474 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1475 /* EC can read descriptor and read/write EC. */
1476 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1477 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1478 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1479 }
Subrata Banike8cfb882024-01-12 01:30:13 +05301480 if (check_region(frba, REGION_DEV_EXP2)) {
1481 /* BIOS can read SPI device expansion 2 region. */
1482 fmba->flmstr1 |= (1 << REGION_DEV_EXP2) << rd_shift;
1483 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001484 break;
Jeff Dalyabd4b962022-01-06 00:52:30 -05001485 case PLATFORM_DNV:
Patrick Rudolph16598742022-10-21 15:13:43 +02001486 case PLATFORM_WBG:
Jeff Dalyabd4b962022-01-06 00:52:30 -05001487 /* CPU/BIOS can read descriptor and BIOS. */
1488 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1489 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1490 /* CPU/BIOS can write BIOS. */
1491 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1492 /* ME can read descriptor and ME. */
1493 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1494 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1495 /* ME can write ME. */
1496 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1497 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001498 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001499 /* CPU/BIOS can read descriptor and BIOS. */
1500 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1501 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1502 /* CPU/BIOS can write BIOS. */
1503 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1504 /* ME can read descriptor and ME. */
1505 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1506 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1507 /* ME can write ME. */
1508 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1509 if (check_region(frba, REGION_GBE)) {
1510 /* BIOS can read GbE. */
1511 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1512 /* BIOS can write GbE. */
1513 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1514 /* ME can read GbE. */
1515 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1516 /* ME can write GbE. */
1517 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1518 /* GbE can write GbE. */
1519 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1520 /* GbE can read GbE. */
1521 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1522 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001523 break;
1524 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001525
1526 write_image(filename, image, size);
1527}
1528
Usha P412679d2020-10-15 11:25:08 +05301529static void enable_cpu_read_me(const char *filename, char *image, int size)
1530{
1531 int rd_shift;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001532 struct fmba *fmba = find_fmba(image, size);
Usha P412679d2020-10-15 11:25:08 +05301533
1534 if (!fmba)
1535 exit(EXIT_FAILURE);
1536
1537 if (ifd_version >= IFD_VERSION_2)
1538 rd_shift = FLMSTR_RD_SHIFT_V2;
1539 else
1540 rd_shift = FLMSTR_RD_SHIFT_V1;
1541
1542 /* CPU/BIOS can read ME. */
1543 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1544
1545 write_image(filename, image, size);
1546}
1547
Bill XIEfa5f9942017-09-12 11:22:29 +08001548static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001549{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001550 struct fmba *fmba = find_fmba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001551 if (!fmba)
1552 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001553
1554 if (ifd_version >= IFD_VERSION_2) {
Reka Normanafed45d2024-01-05 12:54:44 +11001555 /*
1556 * Set all read/write access bits. See comment on
1557 * platform_has_extended_regions() for bitfields.
1558 */
1559 if (platform_has_extended_regions()) {
1560 fmba->flmstr1 = 0xffffffff;
1561 fmba->flmstr2 = 0xffffffff;
1562 fmba->flmstr3 = 0xffffffff;
1563 fmba->flmstr5 = 0xffffffff;
1564 } else {
1565 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1566 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1567 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
1568 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
1569 }
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001570 } else {
1571 fmba->flmstr1 = 0xffff0000;
1572 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001573 /* Keep chipset specific Requester ID */
1574 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001575 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001576
1577 write_image(filename, image, size);
1578}
1579
Subrata Banik5fe22972024-01-30 00:31:08 +05301580static void print_gpr0_range(union gprd reg)
Reka Normanc64be922023-10-03 09:47:01 +11001581{
Subrata Banik5fe22972024-01-30 00:31:08 +05301582 printf("--------- GPR0 Protected Range --------------\n");
1583 printf("Start address = 0x%08x\n", reg.data.start << 12);
1584 printf("End address = 0x%08x\n", (reg.data.end << 12) | 0xfff);
1585}
Reka Normanc64be922023-10-03 09:47:01 +11001586
Subrata Banik5fe22972024-01-30 00:31:08 +05301587static uint8_t get_cse_data_partition_offset(void)
1588{
1589 uint8_t data_offset = 0xff;
1590
1591 switch (platform) {
1592 case PLATFORM_CNL:
1593 case PLATFORM_JSL:
1594 data_offset = 0x10;
1595 break;
1596 case PLATFORM_TGL:
1597 case PLATFORM_ADL:
1598 case PLATFORM_MTL:
1599 data_offset = 0x18;
1600 break;
1601 default:
1602 break;
1603 }
1604
1605 return data_offset;
1606}
1607
1608static uint32_t get_gpr0_offset(void)
1609{
Reka Normanc64be922023-10-03 09:47:01 +11001610 /* Offset expressed as number of 32-bit fields from FPSBA */
Subrata Banik5fe22972024-01-30 00:31:08 +05301611 uint32_t gpr0_offset = 0xffffffff;
1612
Reka Normanc64be922023-10-03 09:47:01 +11001613 switch (platform) {
1614 case PLATFORM_CNL:
1615 gpr0_offset = 0x10;
1616 break;
1617 case PLATFORM_JSL:
1618 gpr0_offset = 0x12;
1619 break;
1620 case PLATFORM_TGL:
1621 case PLATFORM_ADL:
1622 gpr0_offset = 0x15;
1623 break;
1624 case PLATFORM_MTL:
1625 gpr0_offset = 0x40;
1626 break;
1627 default:
Subrata Banik5fe22972024-01-30 00:31:08 +05301628 break;
1629 }
1630
1631 return gpr0_offset;
1632}
1633
1634static void disable_gpr0(const char *filename, char *image, int size)
1635{
1636 struct fpsba *fpsba = find_fpsba(image, size);
1637 if (!fpsba)
1638 exit(EXIT_FAILURE);
1639
1640 uint32_t gpr0_offset = get_gpr0_offset();
1641 if (gpr0_offset == 0xffffffff) {
Reka Normanc64be922023-10-03 09:47:01 +11001642 fprintf(stderr, "Disabling GPR0 not supported on this platform\n");
1643 exit(EXIT_FAILURE);
1644 }
Subrata Banik5fe22972024-01-30 00:31:08 +05301645
1646 union gprd reg;
Subrata Banik2820d2a2024-01-26 19:09:15 +05301647 /* If bit 31 is set then GPR0 protection is enable */
Subrata Banik5fe22972024-01-30 00:31:08 +05301648 reg.value = fpsba->pchstrp[gpr0_offset];
1649 if (!reg.data.write_protect_en) {
Subrata Banik2820d2a2024-01-26 19:09:15 +05301650 printf("GPR0 protection is already disabled\n");
1651 return;
1652 }
Reka Normanc64be922023-10-03 09:47:01 +11001653
Subrata Banik5fe22972024-01-30 00:31:08 +05301654 printf("Value at GPRD offset (%d) is 0x%08x\n", gpr0_offset, reg.value);
1655 print_gpr0_range(reg);
Reka Normanc64be922023-10-03 09:47:01 +11001656 /* 0 means GPR0 protection is disabled */
1657 fpsba->pchstrp[gpr0_offset] = 0;
Reka Normanc64be922023-10-03 09:47:01 +11001658 write_image(filename, image, size);
Subrata Banik5fe22972024-01-30 00:31:08 +05301659 printf("GPR0 protection is now disabled\n");
1660}
1661
1662/*
1663 * Helper function to parse the FPT to retrieve the FITC start offset and size.
1664 * FITC is a sub-partition table inside CSE data partition known as FPT.
1665 *
1666 * CSE Region
1667 * |-----> CSE Data Partition Offset
1668 * | |-------> FPT Entry
1669 * | | |-> Sub Partition 1
1670 * | | |-> Sub Partition 2
1671 * | | |-> FITC
1672 * | | | | -> FITC Offset
1673 * | | | | -> FITC Length
1674 */
1675static int parse_fitc_table(struct cse_fpt *fpt, uint32_t *offset,
1676 size_t *size)
1677{
1678 size_t num_part_header = fpt->count;
1679 /* Move to the next structure which is FPT sub-partition entries */
1680 struct cse_fpt_sub_part *fpt_sub_part = (struct cse_fpt_sub_part *)(fpt + 1);
1681 for (size_t index = 0; index < num_part_header; index++) {
1682 if (!strncmp(fpt_sub_part->signature, "FITC", 4)) {
1683 *offset = fpt_sub_part->offset;
1684 *size = fpt_sub_part->length;
1685 return 0;
1686 }
1687 fpt_sub_part++;
1688 }
1689
1690 return -1;
1691}
1692
1693/*
1694 * Formula to calculate the GPR0 protection range as below:
1695 * Start: CSE Region Base Offset
1696 * End: Till the end of FITC sub-partition
1697 */
1698static int calculate_gpr0_range(char *image, int size,
1699 uint32_t *gpr0_start, uint32_t *gpr0_end)
1700{
1701 struct frba *frba = find_frba(image, size);
1702 if (!frba)
1703 return -1;
1704
1705 struct region region = get_region(frba, REGION_ME);
1706 if (region.size <= 0) {
1707 fprintf(stderr, "Region %s is disabled in target\n",
1708 region_name(REGION_ME));
1709 return -1;
1710 }
1711
1712 /* CSE Region Start */
1713 uint32_t cse_region_start = region.base;
1714 /* Get CSE Data Partition Offset */
1715 uint8_t cse_data_offset = get_cse_data_partition_offset();
1716 if (cse_data_offset == 0xff) {
1717 fprintf(stderr, "Unsupported platform\n");
1718 exit(EXIT_FAILURE);
1719 }
1720 uint32_t data_part_offset = *((uint32_t *)(image + cse_region_start + cse_data_offset));
1721 /* Start reading the CSE Data Partition Table, also known as FPT */
1722 uint32_t data_part_start = data_part_offset + cse_region_start;
1723
1724 uint32_t fitc_region_start = 0;
1725 size_t fitc_region_size = 0;
1726 /*
1727 * FPT holds entry for own FPT data structure also bunch of sub-partitions.
1728 * `FITC` is one of such sub-partition entry.
1729 */
1730 if (parse_fitc_table(((struct cse_fpt *)(image + data_part_start)),
1731 &fitc_region_start, &fitc_region_size) < 0) {
1732 fprintf(stderr, "Unable to find FITC entry\n");
1733 return -1;
1734 }
1735
1736 /*
1737 * GPR0 protection is configured to the following range:
1738 * start: CSE region base offset
1739 * end: Till the end of FITC sub-partition (i.e. CSE region + data partition offset +
1740 * FITC sub partition offset + FITC sub partition size)
1741 */
1742 *gpr0_start = cse_region_start;
1743 *gpr0_end = (cse_region_start + data_part_offset +
1744 fitc_region_start + fitc_region_size) - 1;
1745
1746 return 0;
1747}
1748
1749static void enable_gpr0(const char *filename, char *image, int size)
1750{
1751 struct fpsba *fpsba = find_fpsba(image, size);
1752 if (!fpsba)
1753 exit(EXIT_FAILURE);
1754
1755 uint32_t gpr0_offset = get_gpr0_offset();
1756 if (gpr0_offset == 0xffffffff) {
1757 fprintf(stderr, "Enabling GPR0 not supported on this platform\n");
1758 exit(EXIT_FAILURE);
1759 }
1760
1761 union gprd reg;
1762 /* If bit 31 is set then GPR0 protection is enable */
1763 reg.value = fpsba->pchstrp[gpr0_offset];
1764 if (reg.data.write_protect_en) {
1765 printf("GPR0 protection is already enabled\n");
1766 print_gpr0_range(reg);
1767 return;
1768 }
1769
1770 uint32_t gpr0_range_start, gpr0_range_end;
1771
1772 if (calculate_gpr0_range(image, size, &gpr0_range_start, &gpr0_range_end))
1773 exit(EXIT_FAILURE);
1774
1775 reg.data.start = (gpr0_range_start >> 12) & 0x7fff;
1776 reg.data.end = (gpr0_range_end >> 12) & 0x7fff;
1777 reg.data.read_protect_en = 0;
1778 reg.data.write_protect_en = 1;
1779
1780 fpsba->pchstrp[gpr0_offset] = reg.value;
1781 printf("Value at GPRD offset (%d) is 0x%08x\n", gpr0_offset, reg.value);
1782 print_gpr0_range(reg);
1783 write_image(filename, image, size);
1784 printf("GPR0 protection is now enabled\n");
Reka Normanc64be922023-10-03 09:47:01 +11001785}
1786
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001787static void set_pchstrap(struct fpsba *fpsba, const struct fdbar *fdb, const int strap,
1788 const unsigned int value)
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001789{
1790 if (!fpsba || !fdb) {
1791 fprintf(stderr, "Internal error\n");
1792 exit(EXIT_FAILURE);
1793 }
1794
Arthur Heymans0424a2c2021-06-22 11:14:24 +02001795 /* SoC Strap, aka PSL, aka ISL */
1796 int SS = (fdb->flmap1 >> 24) & 0xff;
1797 if (strap >= SS) {
1798 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SS);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001799 exit(EXIT_FAILURE);
1800 }
1801 fpsba->pchstrp[strap] = value;
1802}
1803
Bill XIEb3e15a22017-09-07 18:34:50 +08001804/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001805static void fpsba_set_altmedisable(struct fpsba *fpsba, struct fmsba *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001806{
1807 if (ifd_version >= IFD_VERSION_2) {
1808 printf("%sting the HAP bit to %s Intel ME...\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001809 altmedisable?"Set":"Unset",
1810 altmedisable?"disable":"enable");
Bill XIEb3e15a22017-09-07 18:34:50 +08001811 if (altmedisable)
1812 fpsba->pchstrp[0] |= (1 << 16);
1813 else
1814 fpsba->pchstrp[0] &= ~(1 << 16);
1815 } else {
1816 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1817 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1818 "and MCH_AltMeDisable to %s Intel ME...\n",
1819 altmedisable?"Set":"Unset",
1820 altmedisable?"disable":"enable");
1821 if (altmedisable) {
1822 /* MCH_MeDisable */
1823 fmsba->data[0] |= 1;
1824 /* MCH_AltMeDisable */
1825 fmsba->data[0] |= (1 << 7);
1826 /* ICH_MeDisable */
1827 fpsba->pchstrp[0] |= 1;
1828 } else {
1829 fmsba->data[0] &= ~1;
1830 fmsba->data[0] &= ~(1 << 7);
1831 fpsba->pchstrp[0] &= ~1;
1832 }
1833 } else {
1834 printf("%sting the AltMeDisable to %s Intel ME...\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001835 altmedisable?"Set":"Unset",
1836 altmedisable?"disable":"enable");
Bill XIEb3e15a22017-09-07 18:34:50 +08001837 if (altmedisable)
1838 fpsba->pchstrp[10] |= (1 << 7);
1839 else
1840 fpsba->pchstrp[10] &= ~(1 << 7);
1841 }
1842 }
1843}
1844
Jacob Garber595d9262019-06-27 17:33:10 -06001845static void inject_region(const char *filename, char *image, int size,
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001846 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001847{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001848 struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001849 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001850 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001851
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001852 struct region region = get_region(frba, region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001853 if (region.size <= 0xfff) {
1854 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1855 region_name(region_type));
1856 exit(EXIT_FAILURE);
1857 }
1858
Scott Duplichanf2c98372014-12-12 21:03:06 -06001859 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001860 if (region_fd == -1) {
1861 perror("Could not open file");
1862 exit(EXIT_FAILURE);
1863 }
1864 struct stat buf;
1865 if (fstat(region_fd, &buf) == -1) {
1866 perror("Could not stat file");
1867 exit(EXIT_FAILURE);
1868 }
1869 int region_size = buf.st_size;
1870
1871 printf("File %s is %d bytes\n", region_fname, region_size);
1872
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001873 if (region_size > region.size) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001874 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1875 " bytes. Not injecting.\n",
1876 region_name(region_type), region.size,
1877 region.size, region_size, region_size);
1878 exit(EXIT_FAILURE);
1879 }
1880
1881 int offset = 0;
1882 if ((region_type == 1) && (region_size < region.size)) {
1883 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1884 " bytes. Padding before injecting.\n",
1885 region_name(region_type), region.size,
1886 region.size, region_size, region_size);
1887 offset = region.size - region_size;
1888 memset(image + region.base, 0xff, offset);
1889 }
1890
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001891 if (size < region.base + offset + region_size) {
1892 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1893 size, region.base + offset + region_size);
1894 exit(EXIT_FAILURE);
1895 }
1896
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001897 if (read(region_fd, image + region.base + offset, region_size) != region_size) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001898 perror("Could not read file");
1899 exit(EXIT_FAILURE);
1900 }
1901
1902 close(region_fd);
1903
1904 printf("Adding %s as the %s section of %s\n",
1905 region_fname, region_name(region_type), filename);
1906 write_image(filename, image, size);
1907}
1908
Jacob Garber595d9262019-06-27 17:33:10 -06001909static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001910{
1911 unsigned int y = 1;
1912 if (x == 0)
1913 return 0;
1914 while (y <= x)
1915 y = y << 1;
1916
1917 return y;
1918}
1919
1920/**
1921 * Determine if two memory regions overlap.
1922 *
1923 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001924 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001925 * @return 1 if the two regions overlap
1926 */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001927static int regions_collide(const struct region *r1, const struct region *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001928{
Bill XIEfa5f9942017-09-12 11:22:29 +08001929 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001930 return 0;
1931
Nico Huber844eda02019-01-05 00:06:19 +01001932 /* r1 should be either completely below or completely above r2 */
1933 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001934}
1935
Jacob Garber595d9262019-06-27 17:33:10 -06001936static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001937 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001938{
1939 FILE *romlayout;
1940 char tempstr[256];
1941 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001942 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001943 int region_number;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001944 struct region current_regions[MAX_REGIONS];
1945 struct region new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001946 int new_extent = 0;
1947 char *new_image;
1948
1949 /* load current descriptor map and regions */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001950 struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001951 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001952 exit(EXIT_FAILURE);
1953
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001954 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001955 current_regions[i] = get_region(frba, i);
1956 new_regions[i] = get_region(frba, i);
1957 }
1958
1959 /* read new layout */
1960 romlayout = fopen(layout_fname, "r");
1961
1962 if (!romlayout) {
1963 perror("Could not read layout file.\n");
1964 exit(EXIT_FAILURE);
1965 }
1966
1967 while (!feof(romlayout)) {
1968 char *tstr1, *tstr2;
1969
Patrick Georgi802ad522014-08-09 17:12:23 +02001970 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001971 layout_region_name))
1972 continue;
1973
1974 region_number = region_num(layout_region_name);
1975 if (region_number < 0)
1976 continue;
1977
1978 tstr1 = strtok(tempstr, ":");
1979 tstr2 = strtok(NULL, ":");
1980 if (!tstr1 || !tstr2) {
1981 fprintf(stderr, "Could not parse layout file.\n");
1982 exit(EXIT_FAILURE);
1983 }
1984 new_regions[region_number].base = strtol(tstr1,
1985 (char **)NULL, 16);
1986 new_regions[region_number].limit = strtol(tstr2,
1987 (char **)NULL, 16);
1988 new_regions[region_number].size =
1989 new_regions[region_number].limit -
1990 new_regions[region_number].base + 1;
1991
1992 if (new_regions[region_number].size < 0)
1993 new_regions[region_number].size = 0;
1994 }
1995 fclose(romlayout);
1996
1997 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001998 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001999 if (new_regions[i].size == 0)
2000 continue;
2001
2002 if (new_regions[i].size < current_regions[i].size) {
2003 printf("DANGER: Region %s is shrinking.\n",
2004 region_name(i));
2005 printf(" The region will be truncated to fit.\n");
2006 printf(" This may result in an unusable image.\n");
2007 }
2008
Alexander Couzensfd5c6582016-10-08 00:37:24 +02002009 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08002010 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002011 fprintf(stderr, "Regions would overlap.\n");
2012 exit(EXIT_FAILURE);
2013 }
2014 }
2015
2016 /* detect if the image size should grow */
2017 if (new_extent < new_regions[i].limit)
2018 new_extent = new_regions[i].limit;
2019 }
2020
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01002021 /* check if the image is actually a Flash Descriptor region */
2022 if (size == new_regions[0].size) {
2023 printf("The image is a single Flash Descriptor:\n");
2024 printf(" Only the descriptor will be modified\n");
2025 new_extent = size;
2026 } else {
2027 new_extent = next_pow2(new_extent - 1);
2028 if (new_extent != size) {
2029 printf("The image has changed in size.\n");
2030 printf("The old image is %d bytes.\n", size);
2031 printf("The new image is %d bytes.\n", new_extent);
2032 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002033 }
2034
2035 /* copy regions to a new image */
2036 new_image = malloc(new_extent);
2037 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02002038 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002039 int copy_size = new_regions[i].size;
2040 int offset_current = 0, offset_new = 0;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002041 const struct region *current = &current_regions[i];
2042 const struct region *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002043
Bill XIEfa5f9942017-09-12 11:22:29 +08002044 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002045 continue;
2046
Bill XIEfa5f9942017-09-12 11:22:29 +08002047 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002048 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08002049 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01002050 if (i == REGION_BIOS)
2051 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002052 }
2053
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01002054 if ((i == REGION_BIOS) && (new->size < current->size)) {
2055 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08002056 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002057 }
2058
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01002059 if (size < current->base + offset_current + copy_size) {
2060 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
2061 region_name(i));
2062 continue;
2063 };
2064
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002065 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
2066 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08002067 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
2068 offset_current, current->limit, current->size);
2069 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
2070 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002071
Bill XIEfa5f9942017-09-12 11:22:29 +08002072 memcpy(new_image + new->base + offset_new,
2073 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002074 copy_size);
2075 }
2076
2077 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08002078 frba = find_frba(new_image, new_extent);
2079 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002080 exit(EXIT_FAILURE);
2081
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01002082 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08002083 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08002084 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002085
2086 write_image(filename, new_image, new_extent);
2087 free(new_image);
2088}
2089
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002090static void print_version(void)
2091{
2092 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
2093 printf("Copyright (C) 2011 Google Inc.\n\n");
2094 printf
2095 ("This program is free software: you can redistribute it and/or modify\n"
2096 "it under the terms of the GNU General Public License as published by\n"
2097 "the Free Software Foundation, version 2 of the License.\n\n"
2098 "This program is distributed in the hope that it will be useful,\n"
2099 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2100 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07002101 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002102}
2103
2104static void print_usage(const char *name)
2105{
2106 printf("usage: %s [-vhdix?] <filename>\n", name);
2107 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02002108 " -d | --dump: dump intel firmware descriptor\n"
2109 " -f | --layout <filename> dump regions into a flashrom layout file\n"
Maximilian Brune347596a2023-03-05 20:55:32 +01002110 " -F | --fmap-layout <filename> dump IFD regions into a fmap layout template (.fmd) file\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02002111 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
2112 " -x | --extract: extract intel fd modules\n"
2113 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
2114 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002115 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02002116 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
2117 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
2118 " -C | --chip <0|1|2> select spi chip on which to operate\n"
2119 " can only be used once per run:\n"
2120 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
2121 " -e | --em100 set SPI frequency to 20MHz and disable\n"
2122 " Dual Output Fast Read Support\n"
2123 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05302124 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02002125 " -u | --unlock Unlock firmware descriptor and ME region\n"
Reka Normanc64be922023-10-03 09:47:01 +11002126 " -g | --gpr0-disable Disable GPR0 (Global Protected Range) register\n"
Subrata Banik5fe22972024-01-30 00:31:08 +05302127 " -E | --gpr0-enable Enable GPR0 (Global Protected Range) register\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03002128 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
2129 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02002130 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05302131 " adl - Alder Lake\n"
2132 " aplk - Apollo Lake\n"
2133 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08002134 " lbg - Lewisburg PCH\n"
Jeff Dalyabd4b962022-01-06 00:52:30 -05002135 " dnv - Denverton\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002136 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05302137 " glk - Gemini Lake\n"
2138 " icl - Ice Lake\n"
Wonkyu Kim3922aa52022-02-02 15:19:05 -08002139 " ifd2 - IFDv2 Platform\n"
Subrata Banik15da1742020-08-26 13:27:21 +05302140 " jsl - Jasper Lake\n"
Subrata Banik9cd85d02023-05-24 23:18:49 +05302141 " mtl - Meteor Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05302142 " sklkbl - Sky Lake/Kaby Lake\n"
2143 " tgl - Tiger Lake\n"
Patrick Rudolph16598742022-10-21 15:13:43 +02002144 " wbg - Wellsburg\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002145 " -S | --setpchstrap Write a PCH strap\n"
2146 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02002147 " -v | --version: print the version\n"
2148 " -h | --help: print this help\n\n"
Jeff Daly3623eca2022-01-05 23:51:40 -05002149 "<region> is one of Descriptor, BIOS, ME, GbE, Platform Data, Secondary BIOS, "
2150 "Device Exp1, EC, Device Exp2, IE, 10GbE_0, 10GbE_1, PTT\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002151 "\n");
2152}
2153
2154int main(int argc, char *argv[])
2155{
2156 int opt, option_index = 0;
2157 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06002158 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002159 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Maximilian Brune347596a2023-03-05 20:55:32 +01002160 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0, mode_fmap_template = 0;
Subrata Banik5fe22972024-01-30 00:31:08 +05302161 int mode_gpr0_disable = 0, mode_gpr0_enable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08002162 char *region_type_string = NULL, *region_fname = NULL;
2163 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002164 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002165 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002166 unsigned int value = 0;
2167 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01002168 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002169 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
2170
Bill XIEfa5f9942017-09-12 11:22:29 +08002171 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002172 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05002173 {"layout", 1, NULL, 'f'},
Maximilian Brune347596a2023-03-05 20:55:32 +01002174 {"fmap-template", 1, NULL, 'F'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002175 {"extract", 0, NULL, 'x'},
2176 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002177 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002178 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002179 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01002180 {"density", 1, NULL, 'D'},
2181 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08002182 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002183 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002184 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05302185 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002186 {"unlock", 0, NULL, 'u'},
Reka Normanc64be922023-10-03 09:47:01 +11002187 {"gpr0-disable", 0, NULL, 'g'},
Subrata Banik5fe22972024-01-30 00:31:08 +05302188 {"gpr0-enable", 0, NULL, 'E'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002189 {"version", 0, NULL, 'v'},
2190 {"help", 0, NULL, 'h'},
Vojtech Vesely21af2112024-02-08 18:17:46 +01002191 {"platform", 1, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06002192 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002193 {"setpchstrap", 1, NULL, 'S'},
2194 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002195 {0, 0, 0, 0}
2196 };
2197
Subrata Banik5fe22972024-01-30 00:31:08 +05302198 while ((opt = getopt_long(argc, argv, "S:V:df:F:D:C:M:xi:n:O:s:p:elrugEvth?",
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002199 long_options, &option_index)) != EOF) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002200 switch (opt) {
2201 case 'd':
2202 mode_dump = 1;
2203 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002204 case 'S':
2205 mode_setstrap = 1;
2206 pchstrap = strtoul(optarg, NULL, 0);
2207 break;
2208 case 'V':
2209 value = strtoul(optarg, NULL, 0);
2210 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05002211 case 'f':
2212 mode_layout = 1;
2213 layout_fname = strdup(optarg);
2214 if (!layout_fname) {
2215 fprintf(stderr, "No layout file specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002216 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Chris Douglass03ce0142014-02-26 13:30:13 -05002217 exit(EXIT_FAILURE);
2218 }
2219 break;
Maximilian Brune347596a2023-03-05 20:55:32 +01002220 case 'F':
2221 mode_fmap_template = 1;
2222 layout_fname = strdup(optarg);
2223 if (!layout_fname) {
2224 fprintf(stderr, "No layout file specified\n");
2225 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
2226 exit(EXIT_FAILURE);
2227 }
2228 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002229 case 'x':
2230 mode_extract = 1;
2231 break;
2232 case 'i':
2233 // separate type and file name
2234 region_type_string = strdup(optarg);
2235 region_fname = strchr(region_type_string, ':');
2236 if (!region_fname) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002237 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002238 exit(EXIT_FAILURE);
2239 }
2240 region_fname[0] = '\0';
2241 region_fname++;
2242 // Descriptor, BIOS, ME, GbE, Platform
2243 // valid type?
2244 if (!strcasecmp("Descriptor", region_type_string))
2245 region_type = 0;
2246 else if (!strcasecmp("BIOS", region_type_string))
2247 region_type = 1;
2248 else if (!strcasecmp("ME", region_type_string))
2249 region_type = 2;
2250 else if (!strcasecmp("GbE", region_type_string))
2251 region_type = 3;
Jeff Daly3623eca2022-01-05 23:51:40 -05002252 else if (!strcasecmp("Platform Data", region_type_string))
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002253 region_type = 4;
Jeff Daly3623eca2022-01-05 23:51:40 -05002254 else if (!strcasecmp("Device Exp1", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07002255 region_type = 5;
Jeff Daly3623eca2022-01-05 23:51:40 -05002256 else if (!strcasecmp("Secondary BIOS", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07002257 region_type = 6;
Jeff Daly3623eca2022-01-05 23:51:40 -05002258 else if (!strcasecmp("Reserved", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07002259 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002260 else if (!strcasecmp("EC", region_type_string))
2261 region_type = 8;
Jeff Daly3623eca2022-01-05 23:51:40 -05002262 else if (!strcasecmp("Device Exp2", region_type_string))
2263 region_type = 9;
2264 else if (!strcasecmp("IE", region_type_string))
2265 region_type = 10;
2266 else if (!strcasecmp("10GbE_0", region_type_string))
2267 region_type = 11;
2268 else if (!strcasecmp("10GbE_1", region_type_string))
2269 region_type = 12;
2270 else if (!strcasecmp("PTT", region_type_string))
2271 region_type = 15;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002272 if (region_type == -1) {
2273 fprintf(stderr, "No such region type: '%s'\n\n",
2274 region_type_string);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002275 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002276 exit(EXIT_FAILURE);
2277 }
2278 mode_inject = 1;
2279 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002280 case 'n':
2281 mode_newlayout = 1;
2282 layout_fname = strdup(optarg);
2283 if (!layout_fname) {
2284 fprintf(stderr, "No layout file specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002285 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002286 exit(EXIT_FAILURE);
2287 }
2288 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002289 case 'O':
2290 new_filename = strdup(optarg);
2291 if (!new_filename) {
2292 fprintf(stderr, "No output filename specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002293 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002294 exit(EXIT_FAILURE);
2295 }
2296 break;
Jan Tatjefa317512016-03-11 00:52:07 +01002297 case 'D':
2298 mode_density = 1;
2299 new_density = strtoul(optarg, NULL, 0);
2300 switch (new_density) {
2301 case 512:
2302 new_density = COMPONENT_DENSITY_512KB;
2303 break;
2304 case 1:
2305 new_density = COMPONENT_DENSITY_1MB;
2306 break;
2307 case 2:
2308 new_density = COMPONENT_DENSITY_2MB;
2309 break;
2310 case 4:
2311 new_density = COMPONENT_DENSITY_4MB;
2312 break;
2313 case 8:
2314 new_density = COMPONENT_DENSITY_8MB;
2315 break;
2316 case 16:
2317 new_density = COMPONENT_DENSITY_16MB;
2318 break;
2319 case 32:
2320 new_density = COMPONENT_DENSITY_32MB;
2321 break;
2322 case 64:
2323 new_density = COMPONENT_DENSITY_64MB;
2324 break;
2325 case 0:
2326 new_density = COMPONENT_DENSITY_UNUSED;
2327 break;
2328 default:
2329 printf("error: Unknown density\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002330 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Jan Tatjefa317512016-03-11 00:52:07 +01002331 exit(EXIT_FAILURE);
2332 }
2333 break;
2334 case 'C':
2335 selected_chip = strtol(optarg, NULL, 0);
2336 if (selected_chip > 2) {
2337 fprintf(stderr, "error: Invalid chip selection\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002338 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Jan Tatjefa317512016-03-11 00:52:07 +01002339 exit(EXIT_FAILURE);
2340 }
2341 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08002342 case 'M':
2343 mode_altmedisable = 1;
2344 altmedisable = strtol(optarg, NULL, 0);
2345 if (altmedisable > 1) {
2346 fprintf(stderr, "error: Illegal value\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002347 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Bill XIEb3e15a22017-09-07 18:34:50 +08002348 exit(EXIT_FAILURE);
2349 }
2350 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002351 case 's':
2352 // Parse the requested SPI frequency
2353 inputfreq = strtol(optarg, NULL, 0);
2354 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002355 case 17:
2356 spifreq = SPI_FREQUENCY_17MHZ;
2357 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002358 case 20:
2359 spifreq = SPI_FREQUENCY_20MHZ;
2360 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002361 case 30:
2362 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
2363 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002364 case 33:
2365 spifreq = SPI_FREQUENCY_33MHZ;
2366 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002367 case 48:
2368 spifreq = SPI_FREQUENCY_48MHZ;
2369 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002370 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002371 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002372 break;
2373 default:
2374 fprintf(stderr, "Invalid SPI Frequency: %d\n",
2375 inputfreq);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002376 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002377 exit(EXIT_FAILURE);
2378 }
2379 mode_spifreq = 1;
2380 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002381 case 'e':
2382 mode_em100 = 1;
2383 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002384 case 'l':
2385 mode_locked = 1;
2386 if (mode_unlocked == 1) {
2387 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
2388 exit(EXIT_FAILURE);
2389 }
2390 break;
Usha P412679d2020-10-15 11:25:08 +05302391 case 'r':
2392 mode_read = 1;
2393 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002394 case 'u':
2395 mode_unlocked = 1;
2396 if (mode_locked == 1) {
2397 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
2398 exit(EXIT_FAILURE);
2399 }
2400 break;
Reka Normanc64be922023-10-03 09:47:01 +11002401 case 'g':
2402 mode_gpr0_disable = 1;
2403 break;
Subrata Banik5fe22972024-01-30 00:31:08 +05302404 case 'E':
2405 mode_gpr0_enable = 1;
2406 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002407 case 'p':
2408 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002409 platform = PLATFORM_APL;
2410 } else if (!strcmp(optarg, "cnl")) {
2411 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08002412 } else if (!strcmp(optarg, "lbg")) {
2413 platform = PLATFORM_LBG;
Jeff Dalyabd4b962022-01-06 00:52:30 -05002414 } else if (!strcmp(optarg, "dnv")) {
2415 platform = PLATFORM_DNV;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002416 } else if (!strcmp(optarg, "ehl")) {
2417 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002418 } else if (!strcmp(optarg, "glk")) {
2419 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05302420 } else if (!strcmp(optarg, "icl")) {
2421 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05302422 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002423 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07002424 } else if (!strcmp(optarg, "sklkbl")) {
2425 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07002426 } else if (!strcmp(optarg, "tgl")) {
2427 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05302428 } else if (!strcmp(optarg, "adl")) {
2429 platform = PLATFORM_ADL;
Wonkyu Kim3922aa52022-02-02 15:19:05 -08002430 } else if (!strcmp(optarg, "ifd2")) {
2431 platform = PLATFORM_IFD2;
Subrata Banikca82e612022-01-20 18:51:21 +05302432 } else if (!strcmp(optarg, "mtl")) {
2433 platform = PLATFORM_MTL;
Patrick Rudolph16598742022-10-21 15:13:43 +02002434 } else if (!strcmp(optarg, "wbg")) {
2435 platform = PLATFORM_WBG;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002436 } else {
2437 fprintf(stderr, "Unknown platform: %s\n", optarg);
2438 exit(EXIT_FAILURE);
2439 }
2440 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06002441 case 't':
2442 mode_validate = 1;
2443 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002444 case 'v':
2445 print_version();
2446 exit(EXIT_SUCCESS);
2447 break;
2448 case 'h':
2449 case '?':
2450 default:
2451 print_usage(argv[0]);
2452 exit(EXIT_SUCCESS);
2453 break;
2454 }
2455 }
2456
Maximilian Brune347596a2023-03-05 20:55:32 +01002457 if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject +
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002458 mode_setstrap + mode_newlayout + (mode_spifreq | mode_em100 |
Reka Normanc64be922023-10-03 09:47:01 +11002459 mode_unlocked | mode_locked) + mode_altmedisable + mode_validate +
Subrata Banik5fe22972024-01-30 00:31:08 +05302460 (mode_gpr0_disable | mode_gpr0_enable)) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002461 fprintf(stderr, "You may not specify more than one mode.\n\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002462 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002463 exit(EXIT_FAILURE);
2464 }
2465
Maximilian Brune347596a2023-03-05 20:55:32 +01002466 if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject +
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002467 mode_setstrap + mode_newlayout + mode_spifreq + mode_em100 +
Reka Normanc64be922023-10-03 09:47:01 +11002468 mode_locked + mode_unlocked + mode_density + mode_altmedisable +
Subrata Banik5fe22972024-01-30 00:31:08 +05302469 mode_validate + (mode_gpr0_disable | mode_gpr0_enable)) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002470 fprintf(stderr, "You need to specify a mode.\n\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002471 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002472 exit(EXIT_FAILURE);
2473 }
2474
2475 if (optind + 1 != argc) {
2476 fprintf(stderr, "You need to specify a file.\n\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002477 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002478 exit(EXIT_FAILURE);
2479 }
2480
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002481 if (platform == -1)
2482 fprintf(stderr, "Warning: No platform specified. Output may be incomplete\n");
2483
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002484 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06002485 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002486 if (bios_fd == -1) {
2487 perror("Could not open file");
2488 exit(EXIT_FAILURE);
2489 }
2490 struct stat buf;
2491 if (fstat(bios_fd, &buf) == -1) {
2492 perror("Could not stat file");
2493 exit(EXIT_FAILURE);
2494 }
2495 int size = buf.st_size;
2496
2497 printf("File %s is %d bytes\n", filename, size);
2498
2499 char *image = malloc(size);
2500 if (!image) {
2501 printf("Out of memory.\n");
2502 exit(EXIT_FAILURE);
2503 }
2504
2505 if (read(bios_fd, image, size) != size) {
2506 perror("Could not read file");
2507 exit(EXIT_FAILURE);
2508 }
2509
2510 close(bios_fd);
2511
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002512 // generate new filename
2513 if (new_filename == NULL) {
2514 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
2515 if (!new_filename) {
2516 printf("Out of memory.\n");
2517 exit(EXIT_FAILURE);
2518 }
2519 // - 5: leave room for ".new\0"
2520 strcpy(new_filename, filename);
2521 strcat(new_filename, ".new");
2522 }
2523
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002524 check_ifd_version(image, size);
2525
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002526 if (mode_dump)
2527 dump_fd(image, size);
2528
Chris Douglass03ce0142014-02-26 13:30:13 -05002529 if (mode_layout)
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002530 dump_flashrom_layout(image, size, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -05002531
Maximilian Brune347596a2023-03-05 20:55:32 +01002532 if (mode_fmap_template)
2533 create_fmap_template(image, size, layout_fname);
2534
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002535 if (mode_extract)
2536 write_regions(image, size);
2537
Mathew Kingc7ddc992019-08-08 14:59:25 -06002538 if (mode_validate)
2539 validate_layout(image, size);
2540
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002541 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002542 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002543 region_fname);
2544
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002545 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002546 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002547
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002548 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002549 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002550
Jan Tatjefa317512016-03-11 00:52:07 +01002551 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002552 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002553
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002554 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002555 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002556
Alexander Couzensd12ea112016-09-10 13:33:05 +02002557 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002558 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002559
Usha P412679d2020-10-15 11:25:08 +05302560 if (mode_read)
2561 enable_cpu_read_me(new_filename, image, size);
2562
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002563 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002564 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002565
Reka Normanc64be922023-10-03 09:47:01 +11002566 if (mode_gpr0_disable)
2567 disable_gpr0(new_filename, image, size);
2568
Subrata Banik5fe22972024-01-30 00:31:08 +05302569 if (mode_gpr0_enable)
2570 enable_gpr0(new_filename, image, size);
2571
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002572 if (mode_setstrap) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002573 struct fpsba *fpsba = find_fpsba(image, size);
2574 const struct fdbar *fdb = find_fd(image, size);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002575 set_pchstrap(fpsba, fdb, pchstrap, value);
2576 write_image(new_filename, image, size);
2577 }
2578
Bill XIEb3e15a22017-09-07 18:34:50 +08002579 if (mode_altmedisable) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002580 struct fpsba *fpsba = find_fpsba(image, size);
2581 struct fmsba *fmsba = find_fmsba(image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002582 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002583 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002584 }
2585
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002586 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002587 free(image);
2588
2589 return 0;
2590}