blob: 1c3e810d1980ad9e3b1fe184d1c14767f7bc8828 [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 Banik6fc8bd92024-06-20 13:32:56 +0530274 case PLATFORM_PTL:
275 return CHIPSET_900_SERIES_PANTHER_LAKE;
Subrata Banik8c082e52021-06-10 23:02:29 +0530276 case PLATFORM_ICL:
277 return CHIPSET_400_SERIES_ICE_POINT;
Johnny Line273a022021-06-22 11:26:46 +0800278 case PLATFORM_LBG:
279 return CHIPSET_C620_SERIES_LEWISBURG;
Jeff Dalyabd4b962022-01-06 00:52:30 -0500280 case PLATFORM_DNV:
281 return CHIPSET_DENVERTON;
Patrick Rudolph16598742022-10-21 15:13:43 +0200282 case PLATFORM_WBG:
283 return CHIPSET_8_SERIES_WELLSBURG;
Subrata Banik8c082e52021-06-10 23:02:29 +0530284 default:
285 return CHIPSET_PCH_UNKNOWN;
286 }
287}
288
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700289/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700290 * Some newer platforms have re-defined the FCBA field that was used to
291 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
292 * have the required FCBA field, but are IFD v2 and return true if current
293 * platform is one of them.
294 */
295static int is_platform_ifd_2(void)
296{
297 static const int ifd_2_platforms[] = {
Subrata Banik6da003c2021-07-14 13:52:03 +0530298 PLATFORM_APL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700299 PLATFORM_GLK,
300 PLATFORM_CNL,
Johnny Line273a022021-06-22 11:26:46 +0800301 PLATFORM_LBG,
Jeff Dalyabd4b962022-01-06 00:52:30 -0500302 PLATFORM_DNV,
Aamir Bohra1018be22018-06-29 15:08:50 +0530303 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700304 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530305 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700306 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530307 PLATFORM_ADL,
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200308 PLATFORM_SKLKBL,
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800309 PLATFORM_IFD2,
Subrata Banikca82e612022-01-20 18:51:21 +0530310 PLATFORM_MTL,
Subrata Banik6fc8bd92024-06-20 13:32:56 +0530311 PLATFORM_PTL,
Patrick Rudolph16598742022-10-21 15:13:43 +0200312 PLATFORM_WBG,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700313 };
314 unsigned int i;
315
316 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
317 if (platform == ifd_2_platforms[i])
318 return 1;
319 }
320
321 return 0;
322}
323
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700324static void check_ifd_version(char *image, int size)
325{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100326 const struct fdbar *fdb = find_fd(image, size);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200327
Subrata Banik8c082e52021-06-10 23:02:29 +0530328 if (is_platform_ifd_2()) {
Subrata Banik8c082e52021-06-10 23:02:29 +0530329 chipset = ifd2_platform_to_chipset(platform);
Patrick Rudolph16598742022-10-21 15:13:43 +0200330 if (chipset == CHIPSET_8_SERIES_WELLSBURG)
331 ifd_version = IFD_VERSION_1_5;
332 else
333 ifd_version = IFD_VERSION_2;
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200334 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS);
Subrata Banik8c082e52021-06-10 23:02:29 +0530335 } else {
336 ifd_version = IFD_VERSION_1;
337 chipset = ifd1_guess_chipset(image, size);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200338 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS_OLD);
Subrata Banik8c082e52021-06-10 23:02:29 +0530339 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700340}
341
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100342static struct region get_region(const struct frba *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700343{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500344 int base_mask;
345 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700346 uint32_t flreg;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100347 struct region region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500348
349 if (ifd_version >= IFD_VERSION_2)
350 base_mask = 0x7fff;
351 else
352 base_mask = 0xfff;
353
354 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700355
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400356 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800357 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700358 exit (EXIT_FAILURE);
359 }
360
Bill XIE4651d452017-09-12 11:54:48 +0800361 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700362 region.base = (flreg & base_mask) << 12;
363 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700364 region.size = region.limit - region.base + 1;
Maximilian Brune347596a2023-03-05 20:55:32 +0100365 region.type = region_type;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500366
Chris Douglass03ce0142014-02-26 13:30:13 -0500367 if (region.size < 0)
368 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700369
370 return region;
371}
372
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100373static void set_region(struct frba *frba, unsigned int region_type,
374 const struct region *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500375{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400376 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800377 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500378 exit (EXIT_FAILURE);
379 }
Bill XIE4651d452017-09-12 11:54:48 +0800380
381 frba->flreg[region_type] =
382 (((region->limit >> 12) & 0x7fff) << 16) |
383 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500384}
385
Bill XIEfa5f9942017-09-12 11:22:29 +0800386static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700387{
Bill XIEfa5f9942017-09-12 11:22:29 +0800388 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700389 fprintf(stderr, "Invalid region type.\n");
390 exit (EXIT_FAILURE);
391 }
392
Chris Douglass03ce0142014-02-26 13:30:13 -0500393 return region_names[region_type].pretty;
394}
395
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500396static int region_num(const char *name)
397{
Bill XIEfa5f9942017-09-12 11:22:29 +0800398 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500399
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200400 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500401 if (strcasecmp(name, region_names[i].pretty) == 0)
402 return i;
403 if (strcasecmp(name, region_names[i].terse) == 0)
404 return i;
405 }
406
407 return -1;
408}
409
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100410static void dump_region(unsigned int num, const struct frba *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700411{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100412 struct region region = get_region(frba, num);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700413 printf(" Flash Region %d (%s): %08x - %08x %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100414 num, region_name(num), region.base, region.limit,
415 region.size < 1 ? "(unused)" : "");
Chris Douglass03ce0142014-02-26 13:30:13 -0500416}
417
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200418static int sort_compare(const void *a, const void *b)
419{
420 return *(size_t *)a - *(size_t *)b;
421}
422
423/*
424 * IFDv1 always has 8 regions, while IFDv2 always has 16 regions.
425 *
426 * It's platform specific which regions are used or are reserved.
427 * The 'SPI programming guide' as the name says is a guide only,
428 * not a specification what the hardware actually does.
429 * The best to do is not to rely on the guide, but detect how many
430 * regions are present in the IFD and expose them all.
431 *
432 * Very early IFDv2 chipsets, sometimes unofficially referred to as
433 * IFDv1.5 platforms, only have 8 regions. To not corrupt the IFD when
434 * operating on an IFDv1.5 detect how much space is actually present
435 * in the IFD.
436 */
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100437static int max_regions_from_fdbar(const struct fdbar *fdb)
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200438{
439 const size_t fcba = (fdb->flmap0 & 0xff) << 4;
440 const size_t fmba = (fdb->flmap1 & 0xff) << 4;
441 const size_t frba = ((fdb->flmap0 >> 16) & 0xff) << 4;
442 const size_t fpsba = ((fdb->flmap1 >> 16) & 0xff) << 4;
443 const size_t flumap = 4096 - 256 - 4;
444 size_t sorted[5] = {fcba, fmba, frba, fpsba, flumap};
445
446 qsort(sorted, ARRAY_SIZE(sorted), sizeof(size_t), sort_compare);
447
448 for (size_t i = 0; i < 4; i++) {
449 /*
450 * Find FRBA in the sorted array and determine the size of the
451 * region by the start of the next region. Every region requires
452 * 4 bytes of space.
453 */
454 if (sorted[i] == frba)
455 return MIN((sorted[i+1] - sorted[i])/4, MAX_REGIONS);
456 }
457 /* Never reaches this point */
458 return 0;
459}
460
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100461static void dump_frba(const struct frba *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700462{
Bill XIE4651d452017-09-12 11:54:48 +0800463 unsigned int i;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100464 struct region region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700465 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800466 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530467 region = get_region(frba, i);
468 /* Skip unused & reserved Flash Region */
469 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
470 continue;
471
Bill XIE4651d452017-09-12 11:54:48 +0800472 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
473 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700474 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700475}
476
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100477static void dump_flashrom_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500478{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100479 const struct frba *frba = find_frba(image, size);
480 if (!frba)
481 exit(EXIT_FAILURE);
Chris Douglass03ce0142014-02-26 13:30:13 -0500482
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100483 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
Chris Douglass03ce0142014-02-26 13:30:13 -0500484 if (layout_fd == -1) {
485 perror("Could not open file");
486 exit(EXIT_FAILURE);
487 }
488
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100489 for (unsigned int i = 0; i < max_regions; i++) {
490 struct region region = get_region(frba, i);
Maximilian Brune2c895aa2023-04-24 19:28:21 +0200491
492 /* A region limit of 0 is an indicator of an unused region
493 * A region base of 7FFFh is an indicator of a reserved region
494 */
495 if (region.limit == 0 || region.base == 0x07FFF000)
Alexander Couzenseff596b2016-10-08 00:53:09 +0200496 continue;
497
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100498 char buf[LAYOUT_LINELEN];
499 snprintf(buf, LAYOUT_LINELEN, "%08x:%08x %s\n", region.base, region.limit, region_names[i].terse);
Chris Douglass03ce0142014-02-26 13:30:13 -0500500 if (write(layout_fd, buf, strlen(buf)) < 0) {
501 perror("Could not write to file");
502 exit(EXIT_FAILURE);
503 }
504 }
505 close(layout_fd);
506 printf("Wrote layout to %s\n", layout_fname);
507}
508
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530509static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700510{
511 switch (freq) {
512 case SPI_FREQUENCY_20MHZ:
513 printf("20MHz");
514 break;
515 case SPI_FREQUENCY_33MHZ:
516 printf("33MHz");
517 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700518 case SPI_FREQUENCY_48MHZ:
519 printf("48MHz");
520 break;
521 case SPI_FREQUENCY_50MHZ_30MHZ:
522 switch (ifd_version) {
523 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +0200524 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700525 printf("50MHz");
526 break;
527 case IFD_VERSION_2:
528 printf("30MHz");
529 break;
530 }
531 break;
532 case SPI_FREQUENCY_17MHZ:
533 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700534 break;
535 default:
536 printf("unknown<%x>MHz", freq);
537 }
538}
539
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530540static void _decode_spi_frequency_500_series(unsigned int freq)
541{
542 switch (freq) {
543 case SPI_FREQUENCY_100MHZ:
544 printf("100MHz");
545 break;
546 case SPI_FREQUENCY_50MHZ:
547 printf("50MHz");
548 break;
549 case SPI_FREQUENCY_500SERIES_33MHZ:
550 printf("33MHz");
551 break;
552 case SPI_FREQUENCY_25MHZ:
553 printf("25MHz");
554 break;
555 case SPI_FREQUENCY_14MHZ:
556 printf("14MHz");
557 break;
558 default:
559 printf("unknown<%x>MHz", freq);
560 }
561}
562
563static void decode_spi_frequency(unsigned int freq)
564{
Subrata Banik9cd85d02023-05-24 23:18:49 +0530565 switch (chipset) {
566 case CHIPSET_500_600_SERIES_TIGER_ALDER_POINT:
567 case CHIPSET_800_SERIES_METEOR_LAKE:
Subrata Banik6fc8bd92024-06-20 13:32:56 +0530568 case CHIPSET_900_SERIES_PANTHER_LAKE:
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530569 _decode_spi_frequency_500_series(freq);
Subrata Banik9cd85d02023-05-24 23:18:49 +0530570 break;
571 default:
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530572 _decode_spi_frequency(freq);
Subrata Banik9cd85d02023-05-24 23:18:49 +0530573 }
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530574}
575
Subrata Banike5d39922020-08-26 16:01:42 +0530576static void _decode_espi_frequency(unsigned int freq)
577{
578 switch (freq) {
579 case ESPI_FREQUENCY_20MHZ:
580 printf("20MHz");
581 break;
582 case ESPI_FREQUENCY_24MHZ:
583 printf("24MHz");
584 break;
585 case ESPI_FREQUENCY_30MHZ:
586 printf("30MHz");
587 break;
588 case ESPI_FREQUENCY_48MHZ:
589 printf("48MHz");
590 break;
591 case ESPI_FREQUENCY_60MHZ:
592 printf("60MHz");
593 break;
594 case ESPI_FREQUENCY_17MHZ:
595 printf("17MHz");
596 break;
597 default:
598 printf("unknown<%x>MHz", freq);
599 }
600}
601
602static void _decode_espi_frequency_500_series(unsigned int freq)
603{
604 switch (freq) {
605 case ESPI_FREQUENCY_500SERIES_20MHZ:
606 printf("20MHz");
607 break;
608 case ESPI_FREQUENCY_500SERIES_24MHZ:
609 printf("24MHz");
610 break;
611 case ESPI_FREQUENCY_500SERIES_25MHZ:
612 printf("25MHz");
613 break;
614 case ESPI_FREQUENCY_500SERIES_48MHZ:
615 printf("48MHz");
616 break;
617 case ESPI_FREQUENCY_500SERIES_60MHZ:
618 printf("60MHz");
619 break;
620 default:
621 printf("unknown<%x>MHz", freq);
622 }
623}
624
Subrata Banik9cd85d02023-05-24 23:18:49 +0530625static void _decode_espi_frequency_800_series(unsigned int freq)
626{
627 switch (freq) {
628 case ESPI_FREQUENCY_800SERIES_20MHZ:
629 printf("20MHz");
630 break;
631 case ESPI_FREQUENCY_800SERIES_25MHZ:
632 printf("25MHz");
633 break;
634 case ESPI_FREQUENCY_800SERIES_33MHZ:
635 printf("33MHz");
636 break;
637 case ESPI_FREQUENCY_800SERIES_50MHZ:
638 printf("50MHz");
639 break;
640 default:
641 printf("unknown<%x>MHz", freq);
642 }
643}
644
Subrata Banike5d39922020-08-26 16:01:42 +0530645static void decode_espi_frequency(unsigned int freq)
646{
Subrata Banik6fc8bd92024-06-20 13:32:56 +0530647 switch (chipset) {
648 case CHIPSET_500_600_SERIES_TIGER_ALDER_POINT:
Subrata Banike5d39922020-08-26 16:01:42 +0530649 _decode_espi_frequency_500_series(freq);
Subrata Banik6fc8bd92024-06-20 13:32:56 +0530650 break;
651 case CHIPSET_800_SERIES_METEOR_LAKE:
652 case CHIPSET_900_SERIES_PANTHER_LAKE:
Subrata Banik9cd85d02023-05-24 23:18:49 +0530653 _decode_espi_frequency_800_series(freq);
Subrata Banik6fc8bd92024-06-20 13:32:56 +0530654 break;
655 default:
Subrata Banike5d39922020-08-26 16:01:42 +0530656 _decode_espi_frequency(freq);
Subrata Banik6fc8bd92024-06-20 13:32:56 +0530657 }
Subrata Banike5d39922020-08-26 16:01:42 +0530658}
659
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700660static void decode_component_density(unsigned int density)
661{
662 switch (density) {
663 case COMPONENT_DENSITY_512KB:
664 printf("512KB");
665 break;
666 case COMPONENT_DENSITY_1MB:
667 printf("1MB");
668 break;
669 case COMPONENT_DENSITY_2MB:
670 printf("2MB");
671 break;
672 case COMPONENT_DENSITY_4MB:
673 printf("4MB");
674 break;
675 case COMPONENT_DENSITY_8MB:
676 printf("8MB");
677 break;
678 case COMPONENT_DENSITY_16MB:
679 printf("16MB");
680 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700681 case COMPONENT_DENSITY_32MB:
682 printf("32MB");
683 break;
684 case COMPONENT_DENSITY_64MB:
685 printf("64MB");
686 break;
687 case COMPONENT_DENSITY_UNUSED:
688 printf("UNUSED");
689 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700690 default:
691 printf("unknown<%x>MB", density);
692 }
693}
694
Subrata Banik26058dc2020-08-26 15:12:16 +0530695static int is_platform_with_pch(void)
696{
697 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
698 return 1;
699
700 return 0;
701}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530702
703/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
704static int is_platform_with_100x_series_pch(void)
705{
706 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banik6fc8bd92024-06-20 13:32:56 +0530707 chipset <= CHIPSET_900_SERIES_PANTHER_LAKE)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530708 return 1;
709
710 return 0;
711}
712
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100713static void dump_fcba(const struct fcba *fcba, const struct fpsba *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700714{
Subrata Banike5d39922020-08-26 16:01:42 +0530715 unsigned int freq;
716
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700717 printf("\nFound Component Section\n");
718 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700719 printf(" Dual Output Fast Read Support: %ssupported\n",
720 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700721 printf(" Read ID/Read Status Clock Frequency: ");
722 decode_spi_frequency((fcba->flcomp >> 27) & 7);
723 printf("\n Write/Erase Clock Frequency: ");
724 decode_spi_frequency((fcba->flcomp >> 24) & 7);
725 printf("\n Fast Read Clock Frequency: ");
726 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700727 printf("\n Fast Read Support: %ssupported",
728 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530729 if (is_platform_with_100x_series_pch() &&
730 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
731 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530732 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530733 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
Subrata Banik9cd85d02023-05-24 23:18:49 +0530734 else if (chipset == CHIPSET_800_SERIES_METEOR_LAKE)
735 freq = (fpsba->pchstrp[65] & 0x38) >> 3;
Subrata Banik6fc8bd92024-06-20 13:32:56 +0530736 else if (chipset == CHIPSET_900_SERIES_PANTHER_LAKE)
737 freq = (fpsba->pchstrp[119] & 0x38) >> 3;
Subrata Banike5d39922020-08-26 16:01:42 +0530738 else
739 freq = (fcba->flcomp >> 17) & 7;
740 decode_espi_frequency(freq);
741 } else {
742 printf("\n Read Clock Frequency: ");
743 decode_spi_frequency((fcba->flcomp >> 17) & 7);
744 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700745
746 switch (ifd_version) {
747 case IFD_VERSION_1:
748 printf("\n Component 2 Density: ");
749 decode_component_density((fcba->flcomp >> 3) & 7);
750 printf("\n Component 1 Density: ");
751 decode_component_density(fcba->flcomp & 7);
752 break;
Patrick Rudolph16598742022-10-21 15:13:43 +0200753 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700754 case IFD_VERSION_2:
755 printf("\n Component 2 Density: ");
756 decode_component_density((fcba->flcomp >> 4) & 0xf);
757 printf("\n Component 1 Density: ");
758 decode_component_density(fcba->flcomp & 0xf);
759 break;
760 }
761
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700762 printf("\n");
763 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700764 printf(" Invalid Instruction 3: 0x%02x\n",
765 (fcba->flill >> 24) & 0xff);
766 printf(" Invalid Instruction 2: 0x%02x\n",
767 (fcba->flill >> 16) & 0xff);
768 printf(" Invalid Instruction 1: 0x%02x\n",
769 (fcba->flill >> 8) & 0xff);
770 printf(" Invalid Instruction 0: 0x%02x\n",
771 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530772 if (is_platform_with_100x_series_pch()) {
773 printf("FLILL1 0x%08x\n", fcba->flpb);
774 printf(" Invalid Instruction 7: 0x%02x\n",
775 (fcba->flpb >> 24) & 0xff);
776 printf(" Invalid Instruction 6: 0x%02x\n",
777 (fcba->flpb >> 16) & 0xff);
778 printf(" Invalid Instruction 5: 0x%02x\n",
779 (fcba->flpb >> 8) & 0xff);
780 printf(" Invalid Instruction 4: 0x%02x\n",
781 fcba->flpb & 0xff);
782 } else {
783 printf("FLPB 0x%08x\n", fcba->flpb);
784 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
785 (fcba->flpb & 0xfff) << 12);
786 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700787}
788
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100789static void dump_fpsba(const struct fdbar *fdb, const struct fpsba *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700790{
Bill XIE4651d452017-09-12 11:54:48 +0800791 unsigned int i;
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200792 /* SoC Straps, aka PSL, aka ISL */
793 unsigned int SS = (fdb->flmap1 >> 24) & 0xff;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200794
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700795 printf("Found PCH Strap Section\n");
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200796 for (i = 0; i < SS; i++)
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200797 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800798
799 if (ifd_version >= IFD_VERSION_2) {
800 printf("HAP bit is %sset\n",
801 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100802 } else if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
Bill XIEb3e15a22017-09-07 18:34:50 +0800803 printf("ICH_MeDisable bit is %sset\n",
804 fpsba->pchstrp[0] & 1 ? "" : "not ");
805 } else {
806 printf("AltMeDisable bit is %sset\n",
807 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
808 }
809
Bill XIE4651d452017-09-12 11:54:48 +0800810 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700811}
812
813static void decode_flmstr(uint32_t flmstr)
814{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700815 int wr_shift, rd_shift;
816 if (ifd_version >= IFD_VERSION_2) {
817 wr_shift = FLMSTR_WR_SHIFT_V2;
818 rd_shift = FLMSTR_RD_SHIFT_V2;
819 } else {
820 wr_shift = FLMSTR_WR_SHIFT_V1;
821 rd_shift = FLMSTR_RD_SHIFT_V1;
822 }
823
824 /* EC region access only available on v2+ */
Jeff Dalyabd4b962022-01-06 00:52:30 -0500825 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700826 printf(" EC Region Write Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100827 (flmstr & (1 << (wr_shift + 8))) ?
828 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700829 printf(" Platform Data Region Write Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100830 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500831 if (PLATFORM_HAS_GBE_REGION) {
832 printf(" GbE Region Write Access: %s\n",
833 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
834 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700835 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700836 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700837 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700838 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700839 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700840 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500841 if (PLATFORM_HAS_10GBE_0_REGION) {
842 printf(" 10GbE_0 Write Access: %s\n",
843 (flmstr & (1 << (wr_shift + 11))) ? "enabled" : "disabled");
844 }
845 if (PLATFORM_HAS_10GBE_1_REGION) {
846 printf(" 10GbE_1 Write Access: %s\n",
847 (flmstr & (1 << 4)) ? "enabled" : "disabled");
848 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700849
Jeff Dalyabd4b962022-01-06 00:52:30 -0500850 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700851 printf(" EC Region Read Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100852 (flmstr & (1 << (rd_shift + 8))) ?
853 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700854 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700855 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500856 if (PLATFORM_HAS_GBE_REGION) {
857 printf(" GbE Region Read Access: %s\n",
858 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
859 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700860 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700861 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700862 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700863 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700864 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700865 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500866 if (PLATFORM_HAS_10GBE_0_REGION) {
867 printf(" 10GbE_0 Read Access: %s\n",
868 (flmstr & (1 << (rd_shift + 11))) ? "enabled" : "disabled");
869 }
870 if (PLATFORM_HAS_10GBE_1_REGION) {
871 printf(" 10GbE_1 Read Access: %s\n",
872 (flmstr & (1 << 0)) ? "enabled" : "disabled");
873 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700874
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700875 /* Requestor ID doesn't exist for ifd 2 */
876 if (ifd_version < IFD_VERSION_2)
877 printf(" Requester ID: 0x%04x\n\n",
878 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700879}
880
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100881static void dump_fmba(const struct fmba *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700882{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700883 printf("Found Master Section\n");
884 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
885 decode_flmstr(fmba->flmstr1);
886 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
887 decode_flmstr(fmba->flmstr2);
Jeff Dalyabd4b962022-01-06 00:52:30 -0500888 if (PLATFORM_HAS_GBE_REGION) {
889 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
890 decode_flmstr(fmba->flmstr3);
891 if (ifd_version >= IFD_VERSION_2) {
892 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
893 decode_flmstr(fmba->flmstr5);
894 }
895 } else {
896 printf("FLMSTR6: 0x%08x (IE)\n", fmba->flmstr6);
897 decode_flmstr(fmba->flmstr6);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700898 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700899}
900
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100901static void dump_fmsba(const struct fmsba *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700902{
Bill XIE612ec0e2017-08-30 16:10:27 +0800903 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700904 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800905 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
906 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800907
908 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
909 printf("MCH_MeDisable bit is %sset\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100910 fmsba->data[0] & 1 ? "" : "not ");
Bill XIEb3e15a22017-09-07 18:34:50 +0800911 printf("MCH_AltMeDisable bit is %sset\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100912 fmsba->data[0] & (1 << 7) ? "" : "not ");
Bill XIEb3e15a22017-09-07 18:34:50 +0800913 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700914}
915
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700916static void dump_jid(uint32_t jid)
917{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100918 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700919 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100920 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200921 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100922 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200923 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700924}
925
926static void dump_vscc(uint32_t vscc)
927{
928 printf(" Lower Erase Opcode: 0x%02x\n",
929 vscc >> 24);
930 printf(" Lower Write Enable on Write Status: 0x%02x\n",
931 vscc & (1 << 20) ? 0x06 : 0x50);
932 printf(" Lower Write Status Required: %s\n",
933 vscc & (1 << 19) ? "Yes" : "No");
934 printf(" Lower Write Granularity: %d bytes\n",
935 vscc & (1 << 18) ? 64 : 1);
936 printf(" Lower Block / Sector Erase Size: ");
937 switch ((vscc >> 16) & 0x3) {
938 case 0:
939 printf("256 Byte\n");
940 break;
941 case 1:
942 printf("4KB\n");
943 break;
944 case 2:
945 printf("8KB\n");
946 break;
947 case 3:
948 printf("64KB\n");
949 break;
950 }
951
952 printf(" Upper Erase Opcode: 0x%02x\n",
953 (vscc >> 8) & 0xff);
954 printf(" Upper Write Enable on Write Status: 0x%02x\n",
955 vscc & (1 << 4) ? 0x06 : 0x50);
956 printf(" Upper Write Status Required: %s\n",
957 vscc & (1 << 3) ? "Yes" : "No");
958 printf(" Upper Write Granularity: %d bytes\n",
959 vscc & (1 << 2) ? 64 : 1);
960 printf(" Upper Block / Sector Erase Size: ");
961 switch (vscc & 0x3) {
962 case 0:
963 printf("256 Byte\n");
964 break;
965 case 1:
966 printf("4KB\n");
967 break;
968 case 2:
969 printf("8KB\n");
970 break;
971 case 3:
972 printf("64KB\n");
973 break;
974 }
975}
976
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100977static void dump_vtba(const struct vtba *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700978{
979 int i;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100980 int max_len = sizeof(struct vtba)/sizeof(struct vscc);
Stefan Tauner0d226142018-08-05 18:56:53 +0200981 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700982
983 printf("ME VSCC table:\n");
984 for (i = 0; i < num; i++) {
985 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
986 dump_jid(vtba->entry[i].jid);
987 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
988 dump_vscc(vtba->entry[i].vscc);
989 }
990 printf("\n");
991}
992
Bill XIEfa5f9942017-09-12 11:22:29 +0800993static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700994{
995 int i, j;
996 printf("OEM Section:\n");
997 for (i = 0; i < 4; i++) {
998 printf("%02x:", i << 4);
999 for (j = 0; j < 16; j++)
1000 printf(" %02x", oem[(i<<4)+j]);
1001 printf ("\n");
1002 }
1003 printf ("\n");
1004}
1005
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001006static void dump_fd(char *image, int size)
1007{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001008 const struct fdbar *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001009 if (!fdb)
1010 exit(EXIT_FAILURE);
1011
Subrata Banik26058dc2020-08-26 15:12:16 +05301012 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
1013 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001014 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +05301015 if (!is_platform_with_100x_series_pch())
1016 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001017 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
1018 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
1019 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
1020
1021 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +05301022 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
1023 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001024 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
1025 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
1026 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
1027
Subrata Banikac1b1dd2020-08-26 15:29:58 +05301028 if (!is_platform_with_100x_series_pch()) {
1029 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
1030 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
1031 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
1032 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001033
Subrata Banik9cd85d02023-05-24 23:18:49 +05301034 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT ||
Subrata Banik6fc8bd92024-06-20 13:32:56 +05301035 chipset == CHIPSET_800_SERIES_METEOR_LAKE ||
1036 chipset == CHIPSET_900_SERIES_PANTHER_LAKE) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +05301037 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
1038 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
1039 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
1040 }
1041
Stefan Tauner0d226142018-08-05 18:56:53 +02001042 char *flumap = find_flumap(image, size);
1043 uint32_t flumap1 = *(uint32_t *)flumap;
1044 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001045 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +02001046 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001047 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +02001048 (flumap1 & 0xff) << 4);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001049 dump_vtba((struct vtba *)
Stefan Tauner0d226142018-08-05 18:56:53 +02001050 (image + ((flumap1 & 0xff) << 4)),
1051 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +08001052 dump_oem((const uint8_t *)image + 0xf00);
1053
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001054 const struct frba *frba = find_frba(image, size);
1055 const struct fcba *fcba = find_fcba(image, size);
1056 const struct fpsba *fpsba = find_fpsba(image, size);
1057 const struct fmba *fmba = find_fmba(image, size);
1058 const struct fmsba *fmsba = find_fmsba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001059
1060 if (frba && fcba && fpsba && fmba && fmsba) {
1061 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +05301062 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001063 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +08001064 dump_fmba(fmba);
1065 dump_fmsba(fmsba);
1066 } else {
1067 printf("FD is corrupted!\n");
1068 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001069}
1070
Maximilian Brune347596a2023-03-05 20:55:32 +01001071/* Takes an image containing an IFD and creates a Flashmap .fmd file template.
1072 * This flashmap will contain all IFD regions except the BIOS region.
1073 * The BIOS region is created by coreboot itself and 'should' match the IFD region
1074 * anyway (CONFIG_VALIDATE_INTEL_DESCRIPTOR should make sure). coreboot built system will use
1075 * this template to generate the final Flashmap file.
1076 */
1077static void create_fmap_template(char *image, int size, const char *layout_fname)
1078{
1079 const struct frba *frba = find_frba(image, size);
1080 if (!frba)
1081 exit(EXIT_FAILURE);
1082
1083 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1084 if (layout_fd == -1) {
1085 perror("Could not open file");
1086 exit(EXIT_FAILURE);
1087 }
1088
1089 char *bbuf = "FLASH@##ROM_BASE## ##ROM_SIZE## {\n";
1090 if (write(layout_fd, bbuf, strlen(bbuf)) < 0) {
1091 perror("Could not write to file");
1092 exit(EXIT_FAILURE);
1093 }
1094
1095 /* fmaptool requires regions in .fmd to be sorted.
1096 * => We need to sort the regions by base address before writing them in .fmd File
1097 */
1098 int count_regions = 0;
1099 struct region sorted_regions[MAX_REGIONS] = { 0 };
1100 for (unsigned int i = 0; i < max_regions; i++) {
1101 struct region region = get_region(frba, i);
Maximilian Brune2c895aa2023-04-24 19:28:21 +02001102
1103 /* A region limit of 0 is an indicator of an unused region
1104 * A region base of 7FFFh is an indicator of a reserved region
1105 */
1106 if (region.limit == 0 || region.base == 0x07FFF000)
Maximilian Brune347596a2023-03-05 20:55:32 +01001107 continue;
1108
Maximilian Brune794d1d72023-11-13 02:07:01 +01001109 /* Is there an FMAP equivalent? IFD reserved regions are usually thrown out
1110 * of the FMAP here
1111 */
1112 if (!region_names[region.type].fmapname) {
1113 printf("Skip IFD region: %s\n", region_names[region.type].pretty);
1114 continue;
1115 }
1116
Maximilian Brune347596a2023-03-05 20:55:32 +01001117 /* Here we decide to use the coreboot generated FMAP BIOS region, instead of
1118 * the one specified in the IFD. The case when IFD and FMAP BIOS region do not
1119 * match cannot be caught here, therefore one should still validate IFD and
1120 * FMAP via CONFIG_VALIDATE_INTEL_DESCRIPTOR
1121 */
1122 if (i == REGION_BIOS)
1123 continue;
1124
1125 sorted_regions[count_regions] = region;
1126 // basically insertion sort
1127 for (int i = count_regions-1; i >= 0 ; i--) {
1128 if (sorted_regions[i].base > sorted_regions[i+1].base) {
1129 struct region tmp = sorted_regions[i];
1130 sorted_regions[i] = sorted_regions[i+1];
1131 sorted_regions[i+1] = tmp;
1132 }
1133 }
1134 count_regions++;
1135 }
1136
1137 // Now write regions sorted by base address in the fmap file
1138 for (int i = 0; i < count_regions; i++) {
1139 struct region region = sorted_regions[i];
1140 char buf[LAYOUT_LINELEN];
1141 snprintf(buf, LAYOUT_LINELEN, "\t%s@0x%X 0x%X\n", region_names[region.type].fmapname, region.base, region.size);
1142 if (write(layout_fd, buf, strlen(buf)) < 0) {
1143 perror("Could not write to file");
1144 exit(EXIT_FAILURE);
1145 }
1146 }
1147
1148 char *ebuf = "\tSI_BIOS@##BIOS_BASE## ##BIOS_SIZE## {\n"
1149 "\t\t##CONSOLE_ENTRY##\n"
1150 "\t\t##MRC_CACHE_ENTRY##\n"
1151 "\t\t##SMMSTORE_ENTRY##\n"
1152 "\t\t##SPD_CACHE_ENTRY##\n"
1153 "\t\t##VPD_ENTRY##\n"
1154 "\t\tFMAP@##FMAP_BASE## ##FMAP_SIZE##\n"
1155 "\t\tCOREBOOT(CBFS)@##CBFS_BASE## ##CBFS_SIZE##\n"
1156 "\t}\n"
1157 "}\n";
1158 if (write(layout_fd, ebuf, strlen(ebuf)) < 0) {
1159 perror("Could not write to file");
1160 exit(EXIT_FAILURE);
1161 }
1162
1163 close(layout_fd);
1164 printf("Wrote layout to %s\n", layout_fname);
1165}
1166
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001167static void write_regions(char *image, int size)
1168{
Bill XIEfa5f9942017-09-12 11:22:29 +08001169 unsigned int i;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001170 const struct frba *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001171
Bill XIE612ec0e2017-08-30 16:10:27 +08001172 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001173 exit(EXIT_FAILURE);
1174
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001175 for (i = 0; i < max_regions; i++) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001176 struct region region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001177 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001178 if (region.size > 0) {
1179 int region_fd;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001180 region_fd = open(region_names[i].filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001181 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001182 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001183 if (region_fd < 0) {
1184 perror("Error while trying to open file");
1185 exit(EXIT_FAILURE);
1186 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001187 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001188 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001189 close(region_fd);
1190 }
1191 }
1192}
1193
Mathew Kingc7ddc992019-08-08 14:59:25 -06001194static void validate_layout(char *image, int size)
1195{
1196 uint i, errors = 0;
1197 struct fmap *fmap;
1198 long int fmap_loc = fmap_find((uint8_t *)image, size);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001199 const struct frba *frba = find_frba(image, size);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001200
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001201 if (fmap_loc < 0 || !frba) {
1202 printf("Could not find FMAP (%p) or Intel Flash Descriptor (%p)\n",
1203 (void *)fmap_loc, frba);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001204 exit(EXIT_FAILURE);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001205 }
Mathew Kingc7ddc992019-08-08 14:59:25 -06001206
1207 fmap = (struct fmap *)(image + fmap_loc);
1208
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001209 int matches = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001210 for (i = 0; i < max_regions; i++) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001211 struct region region = get_region(frba, i);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001212 if (region.size == 0)
1213 continue;
1214
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001215 const struct fmap_area *area = fmap_find_area(fmap, region_names[i].fmapname);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001216 if (!area)
1217 continue;
1218
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001219 matches++; // found a match between FMAP and IFD region
1220
1221 if ((uint)region.base != area->offset || (uint)region.size != area->size) {
1222 printf("Region mismatch between %s and %s\n", region_names[i].terse, area->name);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001223 printf(" Descriptor region %s:\n", region_names[i].terse);
1224 printf(" offset: 0x%08x\n", region.base);
1225 printf(" length: 0x%08x\n", region.size);
1226 printf(" FMAP area %s:\n", area->name);
1227 printf(" offset: 0x%08x\n", area->offset);
1228 printf(" length: 0x%08x\n", area->size);
1229 errors++;
1230 }
1231 }
1232
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001233 if (!matches) {
1234 // At least a BIOS region should be present in both IFD and FMAP
1235 fprintf(stderr, "Warning: Not a single IFD region found in FMAP\n");
1236 }
1237
Mathew Kingc7ddc992019-08-08 14:59:25 -06001238 if (errors > 0)
1239 exit(EXIT_FAILURE);
1240}
1241
Bill XIEfa5f9942017-09-12 11:22:29 +08001242static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001243{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001244 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001245 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001246
1247 // Now write out new image
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001248 new_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001249 if (new_fd < 0) {
1250 perror("Error while trying to open file");
1251 exit(EXIT_FAILURE);
1252 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001253 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001254 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001255 close(new_fd);
1256}
1257
Bill XIEfa5f9942017-09-12 11:22:29 +08001258static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001259 enum spi_frequency freq)
1260{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001261 struct fcba *fcba = find_fcba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001262 if (!fcba)
1263 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001264
1265 /* clear bits 21-29 */
1266 fcba->flcomp &= ~0x3fe00000;
1267 /* Read ID and Read Status Clock Frequency */
1268 fcba->flcomp |= freq << 27;
1269 /* Write and Erase Clock Frequency */
1270 fcba->flcomp |= freq << 24;
1271 /* Fast Read Clock Frequency */
1272 fcba->flcomp |= freq << 21;
1273
1274 write_image(filename, image, size);
1275}
1276
Bill XIEfa5f9942017-09-12 11:22:29 +08001277static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001278{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001279 struct fcba *fcba = find_fcba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001280 if (!fcba)
1281 exit(EXIT_FAILURE);
1282
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001283 int freq;
1284
1285 switch (ifd_version) {
1286 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +02001287 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001288 freq = SPI_FREQUENCY_20MHZ;
1289 break;
1290 case IFD_VERSION_2:
1291 freq = SPI_FREQUENCY_17MHZ;
1292 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001293 default:
1294 freq = SPI_FREQUENCY_17MHZ;
1295 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001296 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001297
1298 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001299 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001300}
1301
Bill XIEfa5f9942017-09-12 11:22:29 +08001302static void set_chipdensity(const char *filename, char *image, int size,
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001303 unsigned int density)
Jan Tatjefa317512016-03-11 00:52:07 +01001304{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001305 struct fcba *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001306 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001307 if (!fcba)
1308 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001309
1310 printf("Setting chip density to ");
1311 decode_component_density(density);
1312 printf("\n");
1313
1314 switch (ifd_version) {
1315 case IFD_VERSION_1:
1316 /* fail if selected density is not supported by this version */
1317 if ( (density == COMPONENT_DENSITY_32MB) ||
1318 (density == COMPONENT_DENSITY_64MB) ||
1319 (density == COMPONENT_DENSITY_UNUSED) ) {
1320 printf("error: Selected density not supported in IFD version 1.\n");
1321 exit(EXIT_FAILURE);
1322 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001323 mask = 0x7;
1324 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001325 break;
Patrick Rudolph16598742022-10-21 15:13:43 +02001326 case IFD_VERSION_1_5:
Jan Tatjefa317512016-03-11 00:52:07 +01001327 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001328 mask = 0xf;
1329 chip2_offset = 4;
1330 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001331 default:
1332 printf("error: Unknown IFD version\n");
1333 exit(EXIT_FAILURE);
1334 break;
1335 }
1336
1337 /* clear chip density for corresponding chip */
1338 switch (selected_chip) {
1339 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001340 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001341 break;
1342 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001343 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001344 break;
1345 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001346 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001347 break;
1348 }
1349
1350 /* set the new density */
1351 if (selected_chip == 1 || selected_chip == 0)
1352 fcba->flcomp |= (density); /* first chip */
1353 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001354 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001355
1356 write_image(filename, image, size);
1357}
1358
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001359static int check_region(const struct frba *frba, unsigned int region_type)
Duncan Laurie7775d672019-06-06 13:39:26 -07001360{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001361 struct region region;
Duncan Laurie7775d672019-06-06 13:39:26 -07001362
1363 if (!frba)
1364 return 0;
1365
1366 region = get_region(frba, region_type);
1367 return !!((region.base < region.limit) && (region.size > 0));
1368}
1369
Reka Normanafed45d2024-01-05 12:54:44 +11001370/*
1371 * Platforms from CNL onwards support up to 16 flash regions, not 12. The
1372 * permissions for regions [15:12] are stored in extended region read/write
1373 * access fields in the FLMSTR registers.
1374 *
1375 * FLMSTR with extended regions:
1376 * 31:20 Region Write Access
1377 * 19:8 Region Read Access
1378 * 7:4 Extended Region Write Access
1379 * 3:0 Extended Region Read Access
1380 *
1381 * FLMSTR without extended regions:
1382 * 31:20 Region Write Access
1383 * 19:8 Region Read Access
1384 * 7:0 Reserved
1385 */
1386static bool platform_has_extended_regions(void)
1387{
1388 switch (platform) {
1389 case PLATFORM_CNL:
1390 case PLATFORM_JSL:
1391 case PLATFORM_TGL:
1392 case PLATFORM_ADL:
1393 case PLATFORM_MTL:
Subrata Banik6fc8bd92024-06-20 13:32:56 +05301394 case PLATFORM_PTL:
Reka Normanafed45d2024-01-05 12:54:44 +11001395 return true;
1396 default:
1397 return false;
1398 }
1399}
1400
Bill XIEfa5f9942017-09-12 11:22:29 +08001401static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001402{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001403 int wr_shift, rd_shift;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001404 struct fmba *fmba = find_fmba(image, size);
1405 const struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001406 if (!fmba)
1407 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001408
1409 if (ifd_version >= IFD_VERSION_2) {
1410 wr_shift = FLMSTR_WR_SHIFT_V2;
1411 rd_shift = FLMSTR_RD_SHIFT_V2;
1412
Reka Normanafed45d2024-01-05 12:54:44 +11001413 /*
1414 * Clear all read/write access bits. See comment on
1415 * platform_has_extended_regions() for bitfields.
1416 */
1417 if (platform_has_extended_regions()) {
1418 fmba->flmstr1 = 0;
1419 fmba->flmstr2 = 0;
1420 fmba->flmstr3 = 0;
1421 fmba->flmstr5 = 0;
1422 } else {
1423 fmba->flmstr1 &= 0xff;
1424 fmba->flmstr2 &= 0xff;
1425 fmba->flmstr3 &= 0xff;
1426 fmba->flmstr5 &= 0xff;
1427 }
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001428 } else {
1429 wr_shift = FLMSTR_WR_SHIFT_V1;
1430 rd_shift = FLMSTR_RD_SHIFT_V1;
1431
1432 fmba->flmstr1 = 0;
1433 fmba->flmstr2 = 0;
1434 /* Requestor ID */
1435 fmba->flmstr3 = 0x118;
1436 }
1437
Andrey Petrov96ecb772016-10-31 19:31:54 -07001438 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001439 case PLATFORM_APL:
1440 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001441 /* CPU/BIOS can read descriptor and BIOS */
1442 fmba->flmstr1 |= 0x3 << rd_shift;
1443 /* CPU/BIOS can write BIOS */
1444 fmba->flmstr1 |= 0x2 << wr_shift;
1445 /* TXE can read descriptor, BIOS and Device Expansion */
1446 fmba->flmstr2 |= 0x23 << rd_shift;
1447 /* TXE can only write Device Expansion */
1448 fmba->flmstr2 |= 0x20 << wr_shift;
1449 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001450 case PLATFORM_CNL:
1451 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001452 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001453 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301454 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001455 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301456 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001457 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +05301458 case PLATFORM_MTL:
Subrata Banik6fc8bd92024-06-20 13:32:56 +05301459 case PLATFORM_PTL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001460 /* CPU/BIOS can read descriptor and BIOS. */
1461 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1462 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1463 /* CPU/BIOS can write BIOS. */
1464 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1465 /* ME can read descriptor and ME. */
1466 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1467 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001468 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001469 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1470 if (check_region(frba, REGION_GBE)) {
1471 /* BIOS can read/write GbE. */
1472 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1473 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1474 /* ME can read GbE. */
1475 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1476 /* GbE can read descriptor and read/write GbE.. */
1477 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1478 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1479 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1480 }
1481 if (check_region(frba, REGION_PDR)) {
1482 /* BIOS can read/write PDR. */
1483 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1484 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1485 }
1486 if (check_region(frba, REGION_EC)) {
1487 /* BIOS can read EC. */
1488 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1489 /* EC can read descriptor and read/write EC. */
1490 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1491 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1492 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1493 }
Subrata Banike8cfb882024-01-12 01:30:13 +05301494 if (check_region(frba, REGION_DEV_EXP2)) {
1495 /* BIOS can read SPI device expansion 2 region. */
1496 fmba->flmstr1 |= (1 << REGION_DEV_EXP2) << rd_shift;
1497 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001498 break;
Jeff Dalyabd4b962022-01-06 00:52:30 -05001499 case PLATFORM_DNV:
Patrick Rudolph16598742022-10-21 15:13:43 +02001500 case PLATFORM_WBG:
Jeff Dalyabd4b962022-01-06 00:52:30 -05001501 /* CPU/BIOS can read descriptor and BIOS. */
1502 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1503 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1504 /* CPU/BIOS can write BIOS. */
1505 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1506 /* ME can read descriptor and ME. */
1507 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1508 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1509 /* ME can write ME. */
1510 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1511 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001512 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001513 /* CPU/BIOS can read descriptor and BIOS. */
1514 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1515 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1516 /* CPU/BIOS can write BIOS. */
1517 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1518 /* ME can read descriptor and ME. */
1519 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1520 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1521 /* ME can write ME. */
1522 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1523 if (check_region(frba, REGION_GBE)) {
1524 /* BIOS can read GbE. */
1525 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1526 /* BIOS can write GbE. */
1527 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1528 /* ME can read GbE. */
1529 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1530 /* ME can write GbE. */
1531 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1532 /* GbE can write GbE. */
1533 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1534 /* GbE can read GbE. */
1535 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1536 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001537 break;
1538 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001539
1540 write_image(filename, image, size);
1541}
1542
Usha P412679d2020-10-15 11:25:08 +05301543static void enable_cpu_read_me(const char *filename, char *image, int size)
1544{
1545 int rd_shift;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001546 struct fmba *fmba = find_fmba(image, size);
Usha P412679d2020-10-15 11:25:08 +05301547
1548 if (!fmba)
1549 exit(EXIT_FAILURE);
1550
1551 if (ifd_version >= IFD_VERSION_2)
1552 rd_shift = FLMSTR_RD_SHIFT_V2;
1553 else
1554 rd_shift = FLMSTR_RD_SHIFT_V1;
1555
1556 /* CPU/BIOS can read ME. */
1557 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1558
1559 write_image(filename, image, size);
1560}
1561
Bill XIEfa5f9942017-09-12 11:22:29 +08001562static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001563{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001564 struct fmba *fmba = find_fmba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001565 if (!fmba)
1566 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001567
1568 if (ifd_version >= IFD_VERSION_2) {
Reka Normanafed45d2024-01-05 12:54:44 +11001569 /*
1570 * Set all read/write access bits. See comment on
1571 * platform_has_extended_regions() for bitfields.
1572 */
1573 if (platform_has_extended_regions()) {
1574 fmba->flmstr1 = 0xffffffff;
1575 fmba->flmstr2 = 0xffffffff;
1576 fmba->flmstr3 = 0xffffffff;
1577 fmba->flmstr5 = 0xffffffff;
1578 } else {
1579 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1580 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1581 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
1582 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
1583 }
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001584 } else {
1585 fmba->flmstr1 = 0xffff0000;
1586 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001587 /* Keep chipset specific Requester ID */
1588 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001589 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001590
1591 write_image(filename, image, size);
1592}
1593
Subrata Banik5fe22972024-01-30 00:31:08 +05301594static void print_gpr0_range(union gprd reg)
Reka Normanc64be922023-10-03 09:47:01 +11001595{
Subrata Banik5fe22972024-01-30 00:31:08 +05301596 printf("--------- GPR0 Protected Range --------------\n");
1597 printf("Start address = 0x%08x\n", reg.data.start << 12);
1598 printf("End address = 0x%08x\n", (reg.data.end << 12) | 0xfff);
1599}
Reka Normanc64be922023-10-03 09:47:01 +11001600
Subrata Banik5fe22972024-01-30 00:31:08 +05301601static uint8_t get_cse_data_partition_offset(void)
1602{
1603 uint8_t data_offset = 0xff;
1604
1605 switch (platform) {
1606 case PLATFORM_CNL:
1607 case PLATFORM_JSL:
1608 data_offset = 0x10;
1609 break;
1610 case PLATFORM_TGL:
1611 case PLATFORM_ADL:
1612 case PLATFORM_MTL:
Subrata Banik6fc8bd92024-06-20 13:32:56 +05301613 case PLATFORM_PTL:
Subrata Banik5fe22972024-01-30 00:31:08 +05301614 data_offset = 0x18;
1615 break;
1616 default:
1617 break;
1618 }
1619
1620 return data_offset;
1621}
1622
1623static uint32_t get_gpr0_offset(void)
1624{
Reka Normanc64be922023-10-03 09:47:01 +11001625 /* Offset expressed as number of 32-bit fields from FPSBA */
Subrata Banik5fe22972024-01-30 00:31:08 +05301626 uint32_t gpr0_offset = 0xffffffff;
1627
Reka Normanc64be922023-10-03 09:47:01 +11001628 switch (platform) {
1629 case PLATFORM_CNL:
1630 gpr0_offset = 0x10;
1631 break;
1632 case PLATFORM_JSL:
1633 gpr0_offset = 0x12;
1634 break;
1635 case PLATFORM_TGL:
1636 case PLATFORM_ADL:
1637 gpr0_offset = 0x15;
1638 break;
1639 case PLATFORM_MTL:
1640 gpr0_offset = 0x40;
1641 break;
Subrata Banik6fc8bd92024-06-20 13:32:56 +05301642 case PLATFORM_PTL:
1643 gpr0_offset = 0x76;
1644 break;
Reka Normanc64be922023-10-03 09:47:01 +11001645 default:
Subrata Banik5fe22972024-01-30 00:31:08 +05301646 break;
1647 }
1648
1649 return gpr0_offset;
1650}
1651
1652static void disable_gpr0(const char *filename, char *image, int size)
1653{
1654 struct fpsba *fpsba = find_fpsba(image, size);
1655 if (!fpsba)
1656 exit(EXIT_FAILURE);
1657
1658 uint32_t gpr0_offset = get_gpr0_offset();
1659 if (gpr0_offset == 0xffffffff) {
Reka Normanc64be922023-10-03 09:47:01 +11001660 fprintf(stderr, "Disabling GPR0 not supported on this platform\n");
1661 exit(EXIT_FAILURE);
1662 }
Subrata Banik5fe22972024-01-30 00:31:08 +05301663
1664 union gprd reg;
Subrata Banik2820d2a2024-01-26 19:09:15 +05301665 /* If bit 31 is set then GPR0 protection is enable */
Subrata Banik5fe22972024-01-30 00:31:08 +05301666 reg.value = fpsba->pchstrp[gpr0_offset];
1667 if (!reg.data.write_protect_en) {
Subrata Banik2820d2a2024-01-26 19:09:15 +05301668 printf("GPR0 protection is already disabled\n");
1669 return;
1670 }
Reka Normanc64be922023-10-03 09:47:01 +11001671
Subrata Banik5fe22972024-01-30 00:31:08 +05301672 printf("Value at GPRD offset (%d) is 0x%08x\n", gpr0_offset, reg.value);
1673 print_gpr0_range(reg);
Reka Normanc64be922023-10-03 09:47:01 +11001674 /* 0 means GPR0 protection is disabled */
1675 fpsba->pchstrp[gpr0_offset] = 0;
Reka Normanc64be922023-10-03 09:47:01 +11001676 write_image(filename, image, size);
Subrata Banik5fe22972024-01-30 00:31:08 +05301677 printf("GPR0 protection is now disabled\n");
1678}
1679
1680/*
1681 * Helper function to parse the FPT to retrieve the FITC start offset and size.
1682 * FITC is a sub-partition table inside CSE data partition known as FPT.
1683 *
1684 * CSE Region
1685 * |-----> CSE Data Partition Offset
1686 * | |-------> FPT Entry
1687 * | | |-> Sub Partition 1
1688 * | | |-> Sub Partition 2
1689 * | | |-> FITC
1690 * | | | | -> FITC Offset
1691 * | | | | -> FITC Length
1692 */
1693static int parse_fitc_table(struct cse_fpt *fpt, uint32_t *offset,
1694 size_t *size)
1695{
1696 size_t num_part_header = fpt->count;
1697 /* Move to the next structure which is FPT sub-partition entries */
1698 struct cse_fpt_sub_part *fpt_sub_part = (struct cse_fpt_sub_part *)(fpt + 1);
1699 for (size_t index = 0; index < num_part_header; index++) {
1700 if (!strncmp(fpt_sub_part->signature, "FITC", 4)) {
1701 *offset = fpt_sub_part->offset;
1702 *size = fpt_sub_part->length;
1703 return 0;
1704 }
1705 fpt_sub_part++;
1706 }
1707
1708 return -1;
1709}
1710
1711/*
1712 * Formula to calculate the GPR0 protection range as below:
1713 * Start: CSE Region Base Offset
1714 * End: Till the end of FITC sub-partition
1715 */
1716static int calculate_gpr0_range(char *image, int size,
1717 uint32_t *gpr0_start, uint32_t *gpr0_end)
1718{
1719 struct frba *frba = find_frba(image, size);
1720 if (!frba)
1721 return -1;
1722
1723 struct region region = get_region(frba, REGION_ME);
1724 if (region.size <= 0) {
1725 fprintf(stderr, "Region %s is disabled in target\n",
1726 region_name(REGION_ME));
1727 return -1;
1728 }
1729
1730 /* CSE Region Start */
1731 uint32_t cse_region_start = region.base;
1732 /* Get CSE Data Partition Offset */
1733 uint8_t cse_data_offset = get_cse_data_partition_offset();
1734 if (cse_data_offset == 0xff) {
1735 fprintf(stderr, "Unsupported platform\n");
1736 exit(EXIT_FAILURE);
1737 }
1738 uint32_t data_part_offset = *((uint32_t *)(image + cse_region_start + cse_data_offset));
1739 /* Start reading the CSE Data Partition Table, also known as FPT */
1740 uint32_t data_part_start = data_part_offset + cse_region_start;
1741
1742 uint32_t fitc_region_start = 0;
1743 size_t fitc_region_size = 0;
1744 /*
1745 * FPT holds entry for own FPT data structure also bunch of sub-partitions.
1746 * `FITC` is one of such sub-partition entry.
1747 */
1748 if (parse_fitc_table(((struct cse_fpt *)(image + data_part_start)),
1749 &fitc_region_start, &fitc_region_size) < 0) {
1750 fprintf(stderr, "Unable to find FITC entry\n");
1751 return -1;
1752 }
1753
1754 /*
1755 * GPR0 protection is configured to the following range:
1756 * start: CSE region base offset
1757 * end: Till the end of FITC sub-partition (i.e. CSE region + data partition offset +
1758 * FITC sub partition offset + FITC sub partition size)
1759 */
1760 *gpr0_start = cse_region_start;
1761 *gpr0_end = (cse_region_start + data_part_offset +
1762 fitc_region_start + fitc_region_size) - 1;
1763
1764 return 0;
1765}
1766
Tyler Wang559ad552024-04-16 14:43:53 +08001767static union gprd get_enabled_gprd(char *image, int size)
1768{
1769 union gprd enabled_gprd_reg;
1770 uint32_t gpr0_range_start, gpr0_range_end;
1771 enabled_gprd_reg.value = 0;
1772 if (calculate_gpr0_range(image, size, &gpr0_range_start, &gpr0_range_end))
1773 exit(EXIT_FAILURE);
1774
1775 enabled_gprd_reg.data.start = (gpr0_range_start >> 12) & 0x7fff;
1776 enabled_gprd_reg.data.end = (gpr0_range_end >> 12) & 0x7fff;
1777 enabled_gprd_reg.data.read_protect_en = 0;
1778 enabled_gprd_reg.data.write_protect_en = 1;
1779
1780 return enabled_gprd_reg;
1781}
1782
Subrata Banik5fe22972024-01-30 00:31:08 +05301783static void enable_gpr0(const char *filename, char *image, int size)
1784{
1785 struct fpsba *fpsba = find_fpsba(image, size);
1786 if (!fpsba)
1787 exit(EXIT_FAILURE);
1788
1789 uint32_t gpr0_offset = get_gpr0_offset();
1790 if (gpr0_offset == 0xffffffff) {
1791 fprintf(stderr, "Enabling GPR0 not supported on this platform\n");
1792 exit(EXIT_FAILURE);
1793 }
1794
1795 union gprd reg;
1796 /* If bit 31 is set then GPR0 protection is enable */
1797 reg.value = fpsba->pchstrp[gpr0_offset];
1798 if (reg.data.write_protect_en) {
1799 printf("GPR0 protection is already enabled\n");
1800 print_gpr0_range(reg);
1801 return;
1802 }
1803
Tyler Wang559ad552024-04-16 14:43:53 +08001804 union gprd enabled_gprd = get_enabled_gprd(image, size);
Subrata Banik5fe22972024-01-30 00:31:08 +05301805
Tyler Wang559ad552024-04-16 14:43:53 +08001806 fpsba->pchstrp[gpr0_offset] = enabled_gprd.value;
1807 printf("Value at GPRD offset (%d) is 0x%08x\n", gpr0_offset, enabled_gprd.value);
1808 print_gpr0_range(enabled_gprd);
Subrata Banik5fe22972024-01-30 00:31:08 +05301809 write_image(filename, image, size);
1810 printf("GPR0 protection is now enabled\n");
Reka Normanc64be922023-10-03 09:47:01 +11001811}
1812
Tyler Wang559ad552024-04-16 14:43:53 +08001813static void is_gpr0_protected(char *image, int size)
1814{
1815 struct fpsba *fpsba = find_fpsba(image, size);
1816 if (!fpsba)
1817 exit(EXIT_FAILURE);
1818
1819 uint32_t gpr0_offset = get_gpr0_offset();
1820 if (gpr0_offset == 0xffffffff) {
1821 fprintf(stderr, "Checking GPR0 not supported on this platform\n");
1822 exit(EXIT_FAILURE);
1823 }
1824 union gprd reg;
1825 union gprd enabled_gprd = get_enabled_gprd(image, size);
1826 reg.value = fpsba->pchstrp[gpr0_offset];
1827
1828 if (fpsba->pchstrp[gpr0_offset] == enabled_gprd.value)
1829 printf("GPR0 status: Enabled\n\n");
1830 else if (fpsba->pchstrp[gpr0_offset] == 0)
1831 printf("GPR0 status: Disabled\n\n");
1832 else
1833 printf("ERROR: GPR0 setting is not expected\n\n");
1834
1835 printf("Value at GPRD offset (%d) is 0x%08x\n", gpr0_offset, fpsba->pchstrp[gpr0_offset]);
1836 print_gpr0_range(reg);
1837}
1838
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001839static void set_pchstrap(struct fpsba *fpsba, const struct fdbar *fdb, const int strap,
1840 const unsigned int value)
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001841{
1842 if (!fpsba || !fdb) {
1843 fprintf(stderr, "Internal error\n");
1844 exit(EXIT_FAILURE);
1845 }
1846
Arthur Heymans0424a2c2021-06-22 11:14:24 +02001847 /* SoC Strap, aka PSL, aka ISL */
1848 int SS = (fdb->flmap1 >> 24) & 0xff;
1849 if (strap >= SS) {
1850 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SS);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001851 exit(EXIT_FAILURE);
1852 }
1853 fpsba->pchstrp[strap] = value;
1854}
1855
Bill XIEb3e15a22017-09-07 18:34:50 +08001856/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001857static void fpsba_set_altmedisable(struct fpsba *fpsba, struct fmsba *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001858{
1859 if (ifd_version >= IFD_VERSION_2) {
1860 printf("%sting the HAP bit to %s Intel ME...\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001861 altmedisable?"Set":"Unset",
1862 altmedisable?"disable":"enable");
Bill XIEb3e15a22017-09-07 18:34:50 +08001863 if (altmedisable)
1864 fpsba->pchstrp[0] |= (1 << 16);
1865 else
1866 fpsba->pchstrp[0] &= ~(1 << 16);
1867 } else {
1868 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1869 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1870 "and MCH_AltMeDisable to %s Intel ME...\n",
1871 altmedisable?"Set":"Unset",
1872 altmedisable?"disable":"enable");
1873 if (altmedisable) {
1874 /* MCH_MeDisable */
1875 fmsba->data[0] |= 1;
1876 /* MCH_AltMeDisable */
1877 fmsba->data[0] |= (1 << 7);
1878 /* ICH_MeDisable */
1879 fpsba->pchstrp[0] |= 1;
1880 } else {
1881 fmsba->data[0] &= ~1;
1882 fmsba->data[0] &= ~(1 << 7);
1883 fpsba->pchstrp[0] &= ~1;
1884 }
1885 } else {
1886 printf("%sting the AltMeDisable to %s Intel ME...\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001887 altmedisable?"Set":"Unset",
1888 altmedisable?"disable":"enable");
Bill XIEb3e15a22017-09-07 18:34:50 +08001889 if (altmedisable)
1890 fpsba->pchstrp[10] |= (1 << 7);
1891 else
1892 fpsba->pchstrp[10] &= ~(1 << 7);
1893 }
1894 }
1895}
1896
Jacob Garber595d9262019-06-27 17:33:10 -06001897static void inject_region(const char *filename, char *image, int size,
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001898 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001899{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001900 struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001901 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001902 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001903
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001904 struct region region = get_region(frba, region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001905 if (region.size <= 0xfff) {
1906 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1907 region_name(region_type));
1908 exit(EXIT_FAILURE);
1909 }
1910
Scott Duplichanf2c98372014-12-12 21:03:06 -06001911 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001912 if (region_fd == -1) {
1913 perror("Could not open file");
1914 exit(EXIT_FAILURE);
1915 }
1916 struct stat buf;
1917 if (fstat(region_fd, &buf) == -1) {
1918 perror("Could not stat file");
1919 exit(EXIT_FAILURE);
1920 }
1921 int region_size = buf.st_size;
1922
1923 printf("File %s is %d bytes\n", region_fname, region_size);
1924
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001925 if (region_size > region.size) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001926 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1927 " bytes. Not injecting.\n",
1928 region_name(region_type), region.size,
1929 region.size, region_size, region_size);
1930 exit(EXIT_FAILURE);
1931 }
1932
1933 int offset = 0;
1934 if ((region_type == 1) && (region_size < region.size)) {
1935 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1936 " bytes. Padding before injecting.\n",
1937 region_name(region_type), region.size,
1938 region.size, region_size, region_size);
1939 offset = region.size - region_size;
1940 memset(image + region.base, 0xff, offset);
1941 }
1942
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001943 if (size < region.base + offset + region_size) {
1944 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1945 size, region.base + offset + region_size);
1946 exit(EXIT_FAILURE);
1947 }
1948
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001949 if (read(region_fd, image + region.base + offset, region_size) != region_size) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001950 perror("Could not read file");
1951 exit(EXIT_FAILURE);
1952 }
1953
1954 close(region_fd);
1955
1956 printf("Adding %s as the %s section of %s\n",
1957 region_fname, region_name(region_type), filename);
1958 write_image(filename, image, size);
1959}
1960
Jacob Garber595d9262019-06-27 17:33:10 -06001961static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001962{
1963 unsigned int y = 1;
1964 if (x == 0)
1965 return 0;
1966 while (y <= x)
1967 y = y << 1;
1968
1969 return y;
1970}
1971
1972/**
1973 * Determine if two memory regions overlap.
1974 *
1975 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001976 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001977 * @return 1 if the two regions overlap
1978 */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001979static int regions_collide(const struct region *r1, const struct region *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001980{
Bill XIEfa5f9942017-09-12 11:22:29 +08001981 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001982 return 0;
1983
Nico Huber844eda02019-01-05 00:06:19 +01001984 /* r1 should be either completely below or completely above r2 */
1985 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001986}
1987
Jacob Garber595d9262019-06-27 17:33:10 -06001988static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001989 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001990{
1991 FILE *romlayout;
1992 char tempstr[256];
1993 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001994 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001995 int region_number;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001996 struct region current_regions[MAX_REGIONS];
1997 struct region new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001998 int new_extent = 0;
1999 char *new_image;
2000
2001 /* load current descriptor map and regions */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002002 struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08002003 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002004 exit(EXIT_FAILURE);
2005
Alexander Couzensfd5c6582016-10-08 00:37:24 +02002006 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002007 current_regions[i] = get_region(frba, i);
2008 new_regions[i] = get_region(frba, i);
2009 }
2010
2011 /* read new layout */
2012 romlayout = fopen(layout_fname, "r");
2013
2014 if (!romlayout) {
2015 perror("Could not read layout file.\n");
2016 exit(EXIT_FAILURE);
2017 }
2018
2019 while (!feof(romlayout)) {
2020 char *tstr1, *tstr2;
2021
Patrick Georgi802ad522014-08-09 17:12:23 +02002022 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002023 layout_region_name))
2024 continue;
2025
2026 region_number = region_num(layout_region_name);
2027 if (region_number < 0)
2028 continue;
2029
2030 tstr1 = strtok(tempstr, ":");
2031 tstr2 = strtok(NULL, ":");
2032 if (!tstr1 || !tstr2) {
2033 fprintf(stderr, "Could not parse layout file.\n");
2034 exit(EXIT_FAILURE);
2035 }
2036 new_regions[region_number].base = strtol(tstr1,
2037 (char **)NULL, 16);
2038 new_regions[region_number].limit = strtol(tstr2,
2039 (char **)NULL, 16);
2040 new_regions[region_number].size =
2041 new_regions[region_number].limit -
2042 new_regions[region_number].base + 1;
2043
2044 if (new_regions[region_number].size < 0)
2045 new_regions[region_number].size = 0;
2046 }
2047 fclose(romlayout);
2048
2049 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02002050 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002051 if (new_regions[i].size == 0)
2052 continue;
2053
2054 if (new_regions[i].size < current_regions[i].size) {
2055 printf("DANGER: Region %s is shrinking.\n",
2056 region_name(i));
2057 printf(" The region will be truncated to fit.\n");
2058 printf(" This may result in an unusable image.\n");
2059 }
2060
Alexander Couzensfd5c6582016-10-08 00:37:24 +02002061 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08002062 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002063 fprintf(stderr, "Regions would overlap.\n");
2064 exit(EXIT_FAILURE);
2065 }
2066 }
2067
2068 /* detect if the image size should grow */
2069 if (new_extent < new_regions[i].limit)
2070 new_extent = new_regions[i].limit;
2071 }
2072
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01002073 /* check if the image is actually a Flash Descriptor region */
2074 if (size == new_regions[0].size) {
2075 printf("The image is a single Flash Descriptor:\n");
2076 printf(" Only the descriptor will be modified\n");
2077 new_extent = size;
2078 } else {
2079 new_extent = next_pow2(new_extent - 1);
2080 if (new_extent != size) {
2081 printf("The image has changed in size.\n");
2082 printf("The old image is %d bytes.\n", size);
2083 printf("The new image is %d bytes.\n", new_extent);
2084 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002085 }
2086
2087 /* copy regions to a new image */
2088 new_image = malloc(new_extent);
2089 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02002090 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002091 int copy_size = new_regions[i].size;
2092 int offset_current = 0, offset_new = 0;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002093 const struct region *current = &current_regions[i];
2094 const struct region *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002095
Bill XIEfa5f9942017-09-12 11:22:29 +08002096 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002097 continue;
2098
Bill XIEfa5f9942017-09-12 11:22:29 +08002099 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002100 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08002101 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01002102 if (i == REGION_BIOS)
2103 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002104 }
2105
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01002106 if ((i == REGION_BIOS) && (new->size < current->size)) {
2107 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08002108 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002109 }
2110
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01002111 if (size < current->base + offset_current + copy_size) {
2112 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
2113 region_name(i));
2114 continue;
2115 };
2116
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002117 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
2118 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08002119 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
2120 offset_current, current->limit, current->size);
2121 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
2122 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002123
Bill XIEfa5f9942017-09-12 11:22:29 +08002124 memcpy(new_image + new->base + offset_new,
2125 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002126 copy_size);
2127 }
2128
2129 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08002130 frba = find_frba(new_image, new_extent);
2131 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002132 exit(EXIT_FAILURE);
2133
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01002134 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08002135 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08002136 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002137
2138 write_image(filename, new_image, new_extent);
2139 free(new_image);
2140}
2141
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002142static void print_version(void)
2143{
2144 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
2145 printf("Copyright (C) 2011 Google Inc.\n\n");
2146 printf
2147 ("This program is free software: you can redistribute it and/or modify\n"
2148 "it under the terms of the GNU General Public License as published by\n"
2149 "the Free Software Foundation, version 2 of the License.\n\n"
2150 "This program is distributed in the hope that it will be useful,\n"
2151 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2152 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07002153 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002154}
2155
2156static void print_usage(const char *name)
2157{
2158 printf("usage: %s [-vhdix?] <filename>\n", name);
2159 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02002160 " -d | --dump: dump intel firmware descriptor\n"
2161 " -f | --layout <filename> dump regions into a flashrom layout file\n"
Maximilian Brune347596a2023-03-05 20:55:32 +01002162 " -F | --fmap-layout <filename> dump IFD regions into a fmap layout template (.fmd) file\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02002163 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
2164 " -x | --extract: extract intel fd modules\n"
2165 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
2166 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002167 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02002168 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
2169 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
2170 " -C | --chip <0|1|2> select spi chip on which to operate\n"
2171 " can only be used once per run:\n"
2172 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
2173 " -e | --em100 set SPI frequency to 20MHz and disable\n"
2174 " Dual Output Fast Read Support\n"
2175 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05302176 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02002177 " -u | --unlock Unlock firmware descriptor and ME region\n"
Reka Normanc64be922023-10-03 09:47:01 +11002178 " -g | --gpr0-disable Disable GPR0 (Global Protected Range) register\n"
Subrata Banik5fe22972024-01-30 00:31:08 +05302179 " -E | --gpr0-enable Enable GPR0 (Global Protected Range) register\n"
Tyler Wang559ad552024-04-16 14:43:53 +08002180 " -c | --gpr0-status Checking GPR0 (Global Protected Range) register status\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03002181 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
2182 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02002183 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05302184 " adl - Alder Lake\n"
2185 " aplk - Apollo Lake\n"
2186 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08002187 " lbg - Lewisburg PCH\n"
Jeff Dalyabd4b962022-01-06 00:52:30 -05002188 " dnv - Denverton\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002189 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05302190 " glk - Gemini Lake\n"
2191 " icl - Ice Lake\n"
Wonkyu Kim3922aa52022-02-02 15:19:05 -08002192 " ifd2 - IFDv2 Platform\n"
Subrata Banik15da1742020-08-26 13:27:21 +05302193 " jsl - Jasper Lake\n"
Subrata Banik9cd85d02023-05-24 23:18:49 +05302194 " mtl - Meteor Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05302195 " sklkbl - Sky Lake/Kaby Lake\n"
2196 " tgl - Tiger Lake\n"
Patrick Rudolph16598742022-10-21 15:13:43 +02002197 " wbg - Wellsburg\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002198 " -S | --setpchstrap Write a PCH strap\n"
2199 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02002200 " -v | --version: print the version\n"
2201 " -h | --help: print this help\n\n"
Jeff Daly3623eca2022-01-05 23:51:40 -05002202 "<region> is one of Descriptor, BIOS, ME, GbE, Platform Data, Secondary BIOS, "
2203 "Device Exp1, EC, Device Exp2, IE, 10GbE_0, 10GbE_1, PTT\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002204 "\n");
2205}
2206
2207int main(int argc, char *argv[])
2208{
2209 int opt, option_index = 0;
2210 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06002211 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002212 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Maximilian Brune347596a2023-03-05 20:55:32 +01002213 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0, mode_fmap_template = 0;
Tyler Wang559ad552024-04-16 14:43:53 +08002214 int mode_gpr0_disable = 0, mode_gpr0_enable = 0, mode_gpr0_status = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08002215 char *region_type_string = NULL, *region_fname = NULL;
2216 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002217 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002218 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002219 unsigned int value = 0;
2220 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01002221 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002222 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
2223
Bill XIEfa5f9942017-09-12 11:22:29 +08002224 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002225 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05002226 {"layout", 1, NULL, 'f'},
Maximilian Brune347596a2023-03-05 20:55:32 +01002227 {"fmap-template", 1, NULL, 'F'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002228 {"extract", 0, NULL, 'x'},
2229 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002230 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002231 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002232 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01002233 {"density", 1, NULL, 'D'},
2234 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08002235 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002236 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002237 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05302238 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002239 {"unlock", 0, NULL, 'u'},
Reka Normanc64be922023-10-03 09:47:01 +11002240 {"gpr0-disable", 0, NULL, 'g'},
Subrata Banik5fe22972024-01-30 00:31:08 +05302241 {"gpr0-enable", 0, NULL, 'E'},
Tyler Wang559ad552024-04-16 14:43:53 +08002242 {"gpr0-status", 0, NULL, 'c'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002243 {"version", 0, NULL, 'v'},
2244 {"help", 0, NULL, 'h'},
Vojtech Vesely21af2112024-02-08 18:17:46 +01002245 {"platform", 1, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06002246 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002247 {"setpchstrap", 1, NULL, 'S'},
2248 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002249 {0, 0, 0, 0}
2250 };
2251
Tyler Wang559ad552024-04-16 14:43:53 +08002252 while ((opt = getopt_long(argc, argv, "S:V:df:F:D:C:M:xi:n:O:s:p:elrugEcvth?",
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002253 long_options, &option_index)) != EOF) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002254 switch (opt) {
2255 case 'd':
2256 mode_dump = 1;
2257 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002258 case 'S':
2259 mode_setstrap = 1;
2260 pchstrap = strtoul(optarg, NULL, 0);
2261 break;
2262 case 'V':
2263 value = strtoul(optarg, NULL, 0);
2264 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05002265 case 'f':
2266 mode_layout = 1;
2267 layout_fname = strdup(optarg);
2268 if (!layout_fname) {
2269 fprintf(stderr, "No layout file specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002270 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Chris Douglass03ce0142014-02-26 13:30:13 -05002271 exit(EXIT_FAILURE);
2272 }
2273 break;
Maximilian Brune347596a2023-03-05 20:55:32 +01002274 case 'F':
2275 mode_fmap_template = 1;
2276 layout_fname = strdup(optarg);
2277 if (!layout_fname) {
2278 fprintf(stderr, "No layout file specified\n");
2279 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
2280 exit(EXIT_FAILURE);
2281 }
2282 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002283 case 'x':
2284 mode_extract = 1;
2285 break;
2286 case 'i':
2287 // separate type and file name
2288 region_type_string = strdup(optarg);
2289 region_fname = strchr(region_type_string, ':');
2290 if (!region_fname) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002291 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002292 exit(EXIT_FAILURE);
2293 }
2294 region_fname[0] = '\0';
2295 region_fname++;
2296 // Descriptor, BIOS, ME, GbE, Platform
2297 // valid type?
2298 if (!strcasecmp("Descriptor", region_type_string))
2299 region_type = 0;
2300 else if (!strcasecmp("BIOS", region_type_string))
2301 region_type = 1;
2302 else if (!strcasecmp("ME", region_type_string))
2303 region_type = 2;
2304 else if (!strcasecmp("GbE", region_type_string))
2305 region_type = 3;
Jeff Daly3623eca2022-01-05 23:51:40 -05002306 else if (!strcasecmp("Platform Data", region_type_string))
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002307 region_type = 4;
Jeff Daly3623eca2022-01-05 23:51:40 -05002308 else if (!strcasecmp("Device Exp1", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07002309 region_type = 5;
Jeff Daly3623eca2022-01-05 23:51:40 -05002310 else if (!strcasecmp("Secondary BIOS", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07002311 region_type = 6;
Jeff Daly3623eca2022-01-05 23:51:40 -05002312 else if (!strcasecmp("Reserved", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07002313 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002314 else if (!strcasecmp("EC", region_type_string))
2315 region_type = 8;
Jeff Daly3623eca2022-01-05 23:51:40 -05002316 else if (!strcasecmp("Device Exp2", region_type_string))
2317 region_type = 9;
2318 else if (!strcasecmp("IE", region_type_string))
2319 region_type = 10;
2320 else if (!strcasecmp("10GbE_0", region_type_string))
2321 region_type = 11;
2322 else if (!strcasecmp("10GbE_1", region_type_string))
2323 region_type = 12;
2324 else if (!strcasecmp("PTT", region_type_string))
2325 region_type = 15;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002326 if (region_type == -1) {
2327 fprintf(stderr, "No such region type: '%s'\n\n",
2328 region_type_string);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002329 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002330 exit(EXIT_FAILURE);
2331 }
2332 mode_inject = 1;
2333 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002334 case 'n':
2335 mode_newlayout = 1;
2336 layout_fname = strdup(optarg);
2337 if (!layout_fname) {
2338 fprintf(stderr, "No layout file specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002339 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002340 exit(EXIT_FAILURE);
2341 }
2342 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002343 case 'O':
2344 new_filename = strdup(optarg);
2345 if (!new_filename) {
2346 fprintf(stderr, "No output filename specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002347 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002348 exit(EXIT_FAILURE);
2349 }
2350 break;
Jan Tatjefa317512016-03-11 00:52:07 +01002351 case 'D':
2352 mode_density = 1;
2353 new_density = strtoul(optarg, NULL, 0);
2354 switch (new_density) {
2355 case 512:
2356 new_density = COMPONENT_DENSITY_512KB;
2357 break;
2358 case 1:
2359 new_density = COMPONENT_DENSITY_1MB;
2360 break;
2361 case 2:
2362 new_density = COMPONENT_DENSITY_2MB;
2363 break;
2364 case 4:
2365 new_density = COMPONENT_DENSITY_4MB;
2366 break;
2367 case 8:
2368 new_density = COMPONENT_DENSITY_8MB;
2369 break;
2370 case 16:
2371 new_density = COMPONENT_DENSITY_16MB;
2372 break;
2373 case 32:
2374 new_density = COMPONENT_DENSITY_32MB;
2375 break;
2376 case 64:
2377 new_density = COMPONENT_DENSITY_64MB;
2378 break;
2379 case 0:
2380 new_density = COMPONENT_DENSITY_UNUSED;
2381 break;
2382 default:
2383 printf("error: Unknown density\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002384 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Jan Tatjefa317512016-03-11 00:52:07 +01002385 exit(EXIT_FAILURE);
2386 }
2387 break;
2388 case 'C':
2389 selected_chip = strtol(optarg, NULL, 0);
2390 if (selected_chip > 2) {
2391 fprintf(stderr, "error: Invalid chip selection\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002392 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Jan Tatjefa317512016-03-11 00:52:07 +01002393 exit(EXIT_FAILURE);
2394 }
2395 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08002396 case 'M':
2397 mode_altmedisable = 1;
2398 altmedisable = strtol(optarg, NULL, 0);
2399 if (altmedisable > 1) {
2400 fprintf(stderr, "error: Illegal value\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002401 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Bill XIEb3e15a22017-09-07 18:34:50 +08002402 exit(EXIT_FAILURE);
2403 }
2404 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002405 case 's':
2406 // Parse the requested SPI frequency
2407 inputfreq = strtol(optarg, NULL, 0);
2408 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002409 case 17:
2410 spifreq = SPI_FREQUENCY_17MHZ;
2411 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002412 case 20:
2413 spifreq = SPI_FREQUENCY_20MHZ;
2414 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002415 case 30:
2416 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
2417 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002418 case 33:
2419 spifreq = SPI_FREQUENCY_33MHZ;
2420 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002421 case 48:
2422 spifreq = SPI_FREQUENCY_48MHZ;
2423 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002424 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002425 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002426 break;
2427 default:
2428 fprintf(stderr, "Invalid SPI Frequency: %d\n",
2429 inputfreq);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002430 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002431 exit(EXIT_FAILURE);
2432 }
2433 mode_spifreq = 1;
2434 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002435 case 'e':
2436 mode_em100 = 1;
2437 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002438 case 'l':
2439 mode_locked = 1;
2440 if (mode_unlocked == 1) {
2441 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
2442 exit(EXIT_FAILURE);
2443 }
2444 break;
Usha P412679d2020-10-15 11:25:08 +05302445 case 'r':
2446 mode_read = 1;
2447 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002448 case 'u':
2449 mode_unlocked = 1;
2450 if (mode_locked == 1) {
2451 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
2452 exit(EXIT_FAILURE);
2453 }
2454 break;
Reka Normanc64be922023-10-03 09:47:01 +11002455 case 'g':
2456 mode_gpr0_disable = 1;
2457 break;
Subrata Banik5fe22972024-01-30 00:31:08 +05302458 case 'E':
2459 mode_gpr0_enable = 1;
2460 break;
Tyler Wang559ad552024-04-16 14:43:53 +08002461 case 'c':
2462 mode_gpr0_status = 1;
2463 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002464 case 'p':
2465 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002466 platform = PLATFORM_APL;
2467 } else if (!strcmp(optarg, "cnl")) {
2468 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08002469 } else if (!strcmp(optarg, "lbg")) {
2470 platform = PLATFORM_LBG;
Jeff Dalyabd4b962022-01-06 00:52:30 -05002471 } else if (!strcmp(optarg, "dnv")) {
2472 platform = PLATFORM_DNV;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002473 } else if (!strcmp(optarg, "ehl")) {
2474 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002475 } else if (!strcmp(optarg, "glk")) {
2476 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05302477 } else if (!strcmp(optarg, "icl")) {
2478 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05302479 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002480 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07002481 } else if (!strcmp(optarg, "sklkbl")) {
2482 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07002483 } else if (!strcmp(optarg, "tgl")) {
2484 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05302485 } else if (!strcmp(optarg, "adl")) {
2486 platform = PLATFORM_ADL;
Wonkyu Kim3922aa52022-02-02 15:19:05 -08002487 } else if (!strcmp(optarg, "ifd2")) {
2488 platform = PLATFORM_IFD2;
Subrata Banikca82e612022-01-20 18:51:21 +05302489 } else if (!strcmp(optarg, "mtl")) {
2490 platform = PLATFORM_MTL;
Subrata Banik6fc8bd92024-06-20 13:32:56 +05302491 } else if (!strcmp(optarg, "ptl")) {
2492 platform = PLATFORM_PTL;
Patrick Rudolph16598742022-10-21 15:13:43 +02002493 } else if (!strcmp(optarg, "wbg")) {
2494 platform = PLATFORM_WBG;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002495 } else {
2496 fprintf(stderr, "Unknown platform: %s\n", optarg);
2497 exit(EXIT_FAILURE);
2498 }
2499 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06002500 case 't':
2501 mode_validate = 1;
2502 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002503 case 'v':
2504 print_version();
2505 exit(EXIT_SUCCESS);
2506 break;
2507 case 'h':
2508 case '?':
2509 default:
2510 print_usage(argv[0]);
2511 exit(EXIT_SUCCESS);
2512 break;
2513 }
2514 }
2515
Maximilian Brune347596a2023-03-05 20:55:32 +01002516 if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject +
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002517 mode_setstrap + mode_newlayout + (mode_spifreq | mode_em100 |
Reka Normanc64be922023-10-03 09:47:01 +11002518 mode_unlocked | mode_locked) + mode_altmedisable + mode_validate +
Tyler Wang559ad552024-04-16 14:43:53 +08002519 (mode_gpr0_disable | mode_gpr0_enable) + mode_gpr0_status) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002520 fprintf(stderr, "You may not specify more than one mode.\n\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002521 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002522 exit(EXIT_FAILURE);
2523 }
2524
Maximilian Brune347596a2023-03-05 20:55:32 +01002525 if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject +
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002526 mode_setstrap + mode_newlayout + mode_spifreq + mode_em100 +
Reka Normanc64be922023-10-03 09:47:01 +11002527 mode_locked + mode_unlocked + mode_density + mode_altmedisable +
Tyler Wang559ad552024-04-16 14:43:53 +08002528 mode_validate + (mode_gpr0_disable | mode_gpr0_enable) + mode_gpr0_status) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002529 fprintf(stderr, "You need to specify a mode.\n\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002530 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002531 exit(EXIT_FAILURE);
2532 }
2533
2534 if (optind + 1 != argc) {
2535 fprintf(stderr, "You need to specify a file.\n\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002536 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002537 exit(EXIT_FAILURE);
2538 }
2539
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002540 if (platform == -1)
2541 fprintf(stderr, "Warning: No platform specified. Output may be incomplete\n");
2542
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002543 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06002544 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002545 if (bios_fd == -1) {
2546 perror("Could not open file");
2547 exit(EXIT_FAILURE);
2548 }
2549 struct stat buf;
2550 if (fstat(bios_fd, &buf) == -1) {
2551 perror("Could not stat file");
2552 exit(EXIT_FAILURE);
2553 }
2554 int size = buf.st_size;
2555
2556 printf("File %s is %d bytes\n", filename, size);
2557
2558 char *image = malloc(size);
2559 if (!image) {
2560 printf("Out of memory.\n");
2561 exit(EXIT_FAILURE);
2562 }
2563
2564 if (read(bios_fd, image, size) != size) {
2565 perror("Could not read file");
2566 exit(EXIT_FAILURE);
2567 }
2568
2569 close(bios_fd);
2570
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002571 // generate new filename
2572 if (new_filename == NULL) {
2573 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
2574 if (!new_filename) {
2575 printf("Out of memory.\n");
2576 exit(EXIT_FAILURE);
2577 }
2578 // - 5: leave room for ".new\0"
2579 strcpy(new_filename, filename);
2580 strcat(new_filename, ".new");
2581 }
2582
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002583 check_ifd_version(image, size);
2584
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002585 if (mode_dump)
2586 dump_fd(image, size);
2587
Chris Douglass03ce0142014-02-26 13:30:13 -05002588 if (mode_layout)
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002589 dump_flashrom_layout(image, size, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -05002590
Maximilian Brune347596a2023-03-05 20:55:32 +01002591 if (mode_fmap_template)
2592 create_fmap_template(image, size, layout_fname);
2593
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002594 if (mode_extract)
2595 write_regions(image, size);
2596
Mathew Kingc7ddc992019-08-08 14:59:25 -06002597 if (mode_validate)
2598 validate_layout(image, size);
2599
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002600 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002601 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002602 region_fname);
2603
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002604 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002605 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002606
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002607 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002608 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002609
Jan Tatjefa317512016-03-11 00:52:07 +01002610 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002611 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002612
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002613 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002614 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002615
Alexander Couzensd12ea112016-09-10 13:33:05 +02002616 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002617 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002618
Usha P412679d2020-10-15 11:25:08 +05302619 if (mode_read)
2620 enable_cpu_read_me(new_filename, image, size);
2621
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002622 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002623 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002624
Reka Normanc64be922023-10-03 09:47:01 +11002625 if (mode_gpr0_disable)
2626 disable_gpr0(new_filename, image, size);
2627
Subrata Banik5fe22972024-01-30 00:31:08 +05302628 if (mode_gpr0_enable)
2629 enable_gpr0(new_filename, image, size);
2630
Tyler Wang559ad552024-04-16 14:43:53 +08002631 if (mode_gpr0_status)
2632 is_gpr0_protected(image, size);
2633
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002634 if (mode_setstrap) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002635 struct fpsba *fpsba = find_fpsba(image, size);
2636 const struct fdbar *fdb = find_fd(image, size);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002637 set_pchstrap(fpsba, fdb, pchstrap, value);
2638 write_image(new_filename, image, size);
2639 }
2640
Bill XIEb3e15a22017-09-07 18:34:50 +08002641 if (mode_altmedisable) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002642 struct fpsba *fpsba = find_fpsba(image, size);
2643 struct fmsba *fmsba = find_fmsba(image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002644 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002645 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002646 }
2647
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002648 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002649 free(image);
2650
2651 return 0;
2652}