blob: 07cc26823ba04b6390d12b7b1158de8f9954c711 [file] [log] [blame]
Patrick Georgiea063cb2020-05-08 19:28:13 +02001/* ifdtool - dump Intel Firmware Descriptor information */
Patrick Georgi7333a112020-05-08 20:48:04 +02002/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07003
4#include <unistd.h>
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8#include <getopt.h>
9#include <fcntl.h>
10#include <sys/types.h>
11#include <sys/stat.h>
Bill XIE4651d452017-09-12 11:54:48 +080012#include <commonlib/helpers.h>
Mathew Kingc7ddc992019-08-08 14:59:25 -060013#include <fmap.h>
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070014#include "ifdtool.h"
15
Scott Duplichanf2c98372014-12-12 21:03:06 -060016#ifndef O_BINARY
17#define O_BINARY 0
18#endif
19
Bill XIE612ec0e2017-08-30 16:10:27 +080020/**
21 * PTR_IN_RANGE - examine whether a pointer falls in [base, base + limit)
22 * @param ptr: the non-void* pointer to a single arbitrary-sized object.
23 * @param base: base address represented with char* type.
24 * @param limit: upper limit of the legal address.
25 *
26 */
27#define PTR_IN_RANGE(ptr, base, limit) \
28 ((const char *)(ptr) >= (base) && \
29 (const char *)&(ptr)[1] <= (base) + (limit))
30
Jeff Dalyabd4b962022-01-06 00:52:30 -050031/**
32 * PLATFORM_HAS_GBE_REGION - some platforms do not support the PCH GbE LAN region
33 */
34#define PLATFORM_HAS_GBE_REGION (platform != PLATFORM_DNV)
35
36/*
37 * PLATFORM_HAS_EC_REGION - some platforms do not support the EC region
38 */
39#define PLATFORM_HAS_EC_REGION (ifd_version >= IFD_VERSION_2 && platform != PLATFORM_DNV)
40
41/*
42 * PLATFORM_HAS_10GBE_X_REGION - some platforms have 1 or more 10GbE LAN regions
43 */
44#define PLATFORM_HAS_10GBE_0_REGION (platform == PLATFORM_DNV)
45#define PLATFORM_HAS_10GBE_1_REGION (platform == PLATFORM_DNV)
46
Maximilian Bruneab0e6802023-03-05 04:34:40 +010047static int max_regions_from_fdbar(const struct fdbar *fdb);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +020048
Duncan Laurie1f7fd722015-06-22 11:14:48 -070049static int ifd_version;
Bill XIEb3e15a22017-09-07 18:34:50 +080050static int chipset;
Bill XIEfa5f9942017-09-12 11:22:29 +080051static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010052static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070053static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050054
Duncan Laurie1f7fd722015-06-22 11:14:48 -070055static const struct region_name region_names[MAX_REGIONS] = {
Mathew Kingc7ddc992019-08-08 14:59:25 -060056 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin", "SI_DESC" },
57 { "BIOS", "bios", "flashregion_1_bios.bin", "SI_BIOS" },
58 { "Intel ME", "me", "flashregion_2_intel_me.bin", "SI_ME" },
59 { "GbE", "gbe", "flashregion_3_gbe.bin", "SI_GBE" },
60 { "Platform Data", "pd", "flashregion_4_platform_data.bin", "SI_PDR" },
Jeff Daly3623eca2022-01-05 23:51:40 -050061 { "Device Exp1", "devexp", "flashregion_5_device_exp.bin", "SI_DEVICEEXT" },
62 { "Secondary BIOS", "bios2", "flashregion_6_bios2.bin", "SI_BIOS2" },
63 { "Reserved", "res7", "flashregion_7_reserved.bin", NULL },
Mathew Kingc7ddc992019-08-08 14:59:25 -060064 { "EC", "ec", "flashregion_8_ec.bin", "SI_EC" },
Jeff Daly3623eca2022-01-05 23:51:40 -050065 { "Device Exp2", "devexp2", "flashregion_9_device_exp.bin", "SI_DEVICEEXT2" },
66 { "IE", "ie", "flashregion_10_ie.bin", "SI_IE" },
67 { "10GbE_0", "10gbe_0", "flashregion_11_10gbe0.bin", "SI_10GBE0" },
68 { "10GbE_1", "10gbe_1", "flashregion_12_10gbe1.bin", "SI_10GBE1" },
69 { "Reserved", "res13", "flashregion_13_reserved.bin", NULL },
70 { "Reserved", "res14", "flashregion_14_reserved.bin", NULL },
71 { "PTT", "ptt", "flashregion_15_ptt.bin", "SI_PTT" },
Chris Douglass03ce0142014-02-26 13:30:13 -050072};
73
Bill XIEb3e15a22017-09-07 18:34:50 +080074/* port from flashrom */
75static const char *const ich_chipset_names[] = {
76 "Unknown ICH",
Bill XIEb3e15a22017-09-07 18:34:50 +080077 "ICH8",
78 "ICH9",
79 "ICH10",
Subrata Banik89db2252020-08-26 14:49:17 +053080 "Unknown PCH",
Bill XIEb3e15a22017-09-07 18:34:50 +080081 "5 series Ibex Peak",
82 "6 series Cougar Point",
83 "7 series Panther Point",
84 "8 series Lynx Point",
85 "Baytrail",
86 "8 series Lynx Point LP",
87 "8 series Wellsburg",
88 "9 series Wildcat Point",
89 "9 series Wildcat Point LP",
Subrata Banik8c082e52021-06-10 23:02:29 +053090 "Apollo Lake: N3xxx, J3xxx",
Subrata Banik89db2252020-08-26 14:49:17 +053091 "Gemini Lake: N5xxx, J5xxx, N4xxx, J4xxx",
Subrata Banik8c082e52021-06-10 23:02:29 +053092 "Jasper Lake: N6xxx, N51xx, N45xx",
93 "Elkhart Lake: x6000 series Atom",
Subrata Banik89db2252020-08-26 14:49:17 +053094 "100/200 series Sunrise Point",
Subrata Banik8c082e52021-06-10 23:02:29 +053095 "300 series Cannon Point",
96 "400 series Ice Point",
Subrata Banika5f47812020-09-29 11:43:01 +053097 "500 series Tiger Point/ 600 series Alder Point",
Subrata Banik9cd85d02023-05-24 23:18:49 +053098 "800 series Meteor Lake",
Bill XIEb3e15a22017-09-07 18:34:50 +080099 "C620 series Lewisburg",
Patrick Rudolph19209002022-10-22 10:34:05 +0200100 "Denverton: C39xx",
Bill XIEb3e15a22017-09-07 18:34:50 +0800101 NULL
102};
103
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100104static struct fdbar *find_fd(char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700105{
106 int i, found = 0;
107
108 /* Scan for FD signature */
109 for (i = 0; i < (size - 4); i += 4) {
110 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
111 found = 1;
112 break; // signature found.
113 }
114 }
115
116 if (!found) {
117 printf("No Flash Descriptor found in this image\n");
118 return NULL;
119 }
120
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100121 struct fdbar *fdb = (struct fdbar *) (image + i);
Bill XIE612ec0e2017-08-30 16:10:27 +0800122 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
123}
124
Stefan Tauner0d226142018-08-05 18:56:53 +0200125static char *find_flumap(char *image, int size)
126{
127 /* The upper map is located in the word before the 256B-long OEM section
128 * at the end of the 4kB-long flash descriptor. In the official
129 * documentation this is defined as FDBAR + 0xEFC. However, starting
130 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
131 * has moved 16 bytes back to offset 0x10 of the image. Although
132 * official documentation still maintains the offset relative to FDBAR
133 * this is wrong and a simple fixed offset from the start of the image
134 * works.
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100135 */
Stefan Tauner0d226142018-08-05 18:56:53 +0200136 char *flumap = image + 4096 - 256 - 4;
137 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
138}
139
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100140static struct fcba *find_fcba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800141{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100142 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800143 if (!fdb)
144 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100145 struct fcba *fcba = (struct fcba *) (image + ((fdb->flmap0 & 0xff) << 4));
Bill XIE612ec0e2017-08-30 16:10:27 +0800146 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
147
148}
149
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100150static struct fmba *find_fmba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800151{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100152 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800153 if (!fdb)
154 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100155 struct fmba *fmba = (struct fmba *) (image + ((fdb->flmap1 & 0xff) << 4));
Bill XIE612ec0e2017-08-30 16:10:27 +0800156 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
157}
158
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100159static struct frba *find_frba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800160{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100161 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800162 if (!fdb)
163 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100164 struct frba *frba =
165 (struct frba *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
Bill XIE612ec0e2017-08-30 16:10:27 +0800166 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
167}
168
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100169static struct fpsba *find_fpsba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800170{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100171 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800172 if (!fdb)
173 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100174 struct fpsba *fpsba =
175 (struct fpsba *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200176
177 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
178 if ((((char *)fpsba) + SSL) >= (image + size))
179 return NULL;
180 return fpsba;
Bill XIE612ec0e2017-08-30 16:10:27 +0800181}
182
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100183static struct fmsba *find_fmsba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800184{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100185 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800186 if (!fdb)
187 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100188 struct fmsba *fmsba = (struct fmsba *) (image + ((fdb->flmap2 & 0xff) << 4));
Bill XIE612ec0e2017-08-30 16:10:27 +0800189 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700190}
191
Bill XIEb3e15a22017-09-07 18:34:50 +0800192/* port from flashrom */
Subrata Banik8c082e52021-06-10 23:02:29 +0530193static enum ich_chipset ifd1_guess_chipset(char *image, int size)
Bill XIEb3e15a22017-09-07 18:34:50 +0800194{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100195 const struct fdbar *fdb = find_fd(image, size);
Subrata Banik8c082e52021-06-10 23:02:29 +0530196 if (!fdb)
197 exit(EXIT_FAILURE);
Bill XIEb3e15a22017-09-07 18:34:50 +0800198 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
199 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
200 uint32_t isl = (fdb->flmap1 >> 24);
Subrata Banik89db2252020-08-26 14:49:17 +0530201
202 /* Rest for IFD1 chipset type */
Bill XIEb3e15a22017-09-07 18:34:50 +0800203 if (iccriba == 0x00) {
204 if (msl == 0 && isl <= 2)
205 return CHIPSET_ICH8;
206 else if (isl <= 2)
207 return CHIPSET_ICH9;
208 else if (isl <= 10)
209 return CHIPSET_ICH10;
210 else if (isl <= 16)
211 return CHIPSET_5_SERIES_IBEX_PEAK;
212 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
213 return CHIPSET_5_SERIES_IBEX_PEAK;
214 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
215 if (msl == 0 && isl <= 17)
216 return CHIPSET_BAYTRAIL;
217 else if (msl <= 1 && isl <= 18)
218 return CHIPSET_6_SERIES_COUGAR_POINT;
219 else if (msl <= 1 && isl <= 21)
220 return CHIPSET_8_SERIES_LYNX_POINT;
221 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
222 return CHIPSET_9_SERIES_WILDCAT_POINT;
Bill XIEb3e15a22017-09-07 18:34:50 +0800223 }
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200224 return CHIPSET_PCH_UNKNOWN;
Bill XIEb3e15a22017-09-07 18:34:50 +0800225}
226
Subrata Banik8c082e52021-06-10 23:02:29 +0530227static enum ich_chipset ifd2_platform_to_chipset(const int pindex)
228{
229 switch (pindex) {
Subrata Banik6da003c2021-07-14 13:52:03 +0530230 case PLATFORM_APL:
231 return CHIPSET_N_J_SERIES_APOLLO_LAKE;
Subrata Banik8c082e52021-06-10 23:02:29 +0530232 case PLATFORM_GLK:
233 return CHIPSET_N_J_SERIES_GEMINI_LAKE;
234 case PLATFORM_JSL:
235 return CHIPSET_N_SERIES_JASPER_LAKE;
236 case PLATFORM_EHL:
237 return CHIPSET_x6000_SERIES_ELKHART_LAKE;
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200238 case PLATFORM_SKLKBL:
239 return CHIPSET_100_200_SERIES_SUNRISE_POINT;
Subrata Banik8c082e52021-06-10 23:02:29 +0530240 case PLATFORM_CNL:
241 return CHIPSET_300_SERIES_CANNON_POINT;
242 case PLATFORM_TGL:
243 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800244 case PLATFORM_IFD2:
Subrata Banik8c082e52021-06-10 23:02:29 +0530245 return CHIPSET_500_600_SERIES_TIGER_ALDER_POINT;
Subrata Banik9cd85d02023-05-24 23:18:49 +0530246 case PLATFORM_MTL:
247 return CHIPSET_800_SERIES_METEOR_LAKE;
Subrata Banik8c082e52021-06-10 23:02:29 +0530248 case PLATFORM_ICL:
249 return CHIPSET_400_SERIES_ICE_POINT;
Johnny Line273a022021-06-22 11:26:46 +0800250 case PLATFORM_LBG:
251 return CHIPSET_C620_SERIES_LEWISBURG;
Jeff Dalyabd4b962022-01-06 00:52:30 -0500252 case PLATFORM_DNV:
253 return CHIPSET_DENVERTON;
Patrick Rudolph16598742022-10-21 15:13:43 +0200254 case PLATFORM_WBG:
255 return CHIPSET_8_SERIES_WELLSBURG;
Subrata Banik8c082e52021-06-10 23:02:29 +0530256 default:
257 return CHIPSET_PCH_UNKNOWN;
258 }
259}
260
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700261/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700262 * Some newer platforms have re-defined the FCBA field that was used to
263 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
264 * have the required FCBA field, but are IFD v2 and return true if current
265 * platform is one of them.
266 */
267static int is_platform_ifd_2(void)
268{
269 static const int ifd_2_platforms[] = {
Subrata Banik6da003c2021-07-14 13:52:03 +0530270 PLATFORM_APL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700271 PLATFORM_GLK,
272 PLATFORM_CNL,
Johnny Line273a022021-06-22 11:26:46 +0800273 PLATFORM_LBG,
Jeff Dalyabd4b962022-01-06 00:52:30 -0500274 PLATFORM_DNV,
Aamir Bohra1018be22018-06-29 15:08:50 +0530275 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700276 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530277 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700278 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530279 PLATFORM_ADL,
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200280 PLATFORM_SKLKBL,
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800281 PLATFORM_IFD2,
Subrata Banikca82e612022-01-20 18:51:21 +0530282 PLATFORM_MTL,
Patrick Rudolph16598742022-10-21 15:13:43 +0200283 PLATFORM_WBG,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700284 };
285 unsigned int i;
286
287 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
288 if (platform == ifd_2_platforms[i])
289 return 1;
290 }
291
292 return 0;
293}
294
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700295static void check_ifd_version(char *image, int size)
296{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100297 const struct fdbar *fdb = find_fd(image, size);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200298
Subrata Banik8c082e52021-06-10 23:02:29 +0530299 if (is_platform_ifd_2()) {
Subrata Banik8c082e52021-06-10 23:02:29 +0530300 chipset = ifd2_platform_to_chipset(platform);
Patrick Rudolph16598742022-10-21 15:13:43 +0200301 if (chipset == CHIPSET_8_SERIES_WELLSBURG)
302 ifd_version = IFD_VERSION_1_5;
303 else
304 ifd_version = IFD_VERSION_2;
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200305 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS);
Subrata Banik8c082e52021-06-10 23:02:29 +0530306 } else {
307 ifd_version = IFD_VERSION_1;
308 chipset = ifd1_guess_chipset(image, size);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200309 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS_OLD);
Subrata Banik8c082e52021-06-10 23:02:29 +0530310 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700311}
312
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100313static struct region get_region(const struct frba *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700314{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500315 int base_mask;
316 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700317 uint32_t flreg;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100318 struct region region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500319
320 if (ifd_version >= IFD_VERSION_2)
321 base_mask = 0x7fff;
322 else
323 base_mask = 0xfff;
324
325 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700326
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400327 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800328 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700329 exit (EXIT_FAILURE);
330 }
331
Bill XIE4651d452017-09-12 11:54:48 +0800332 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700333 region.base = (flreg & base_mask) << 12;
334 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700335 region.size = region.limit - region.base + 1;
Maximilian Brune347596a2023-03-05 20:55:32 +0100336 region.type = region_type;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500337
Chris Douglass03ce0142014-02-26 13:30:13 -0500338 if (region.size < 0)
339 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700340
341 return region;
342}
343
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100344static void set_region(struct frba *frba, unsigned int region_type,
345 const struct region *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500346{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400347 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800348 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500349 exit (EXIT_FAILURE);
350 }
Bill XIE4651d452017-09-12 11:54:48 +0800351
352 frba->flreg[region_type] =
353 (((region->limit >> 12) & 0x7fff) << 16) |
354 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500355}
356
Bill XIEfa5f9942017-09-12 11:22:29 +0800357static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700358{
Bill XIEfa5f9942017-09-12 11:22:29 +0800359 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700360 fprintf(stderr, "Invalid region type.\n");
361 exit (EXIT_FAILURE);
362 }
363
Chris Douglass03ce0142014-02-26 13:30:13 -0500364 return region_names[region_type].pretty;
365}
366
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500367static int region_num(const char *name)
368{
Bill XIEfa5f9942017-09-12 11:22:29 +0800369 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500370
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200371 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500372 if (strcasecmp(name, region_names[i].pretty) == 0)
373 return i;
374 if (strcasecmp(name, region_names[i].terse) == 0)
375 return i;
376 }
377
378 return -1;
379}
380
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100381static void dump_region(unsigned int num, const struct frba *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700382{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100383 struct region region = get_region(frba, num);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700384 printf(" Flash Region %d (%s): %08x - %08x %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100385 num, region_name(num), region.base, region.limit,
386 region.size < 1 ? "(unused)" : "");
Chris Douglass03ce0142014-02-26 13:30:13 -0500387}
388
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200389static int sort_compare(const void *a, const void *b)
390{
391 return *(size_t *)a - *(size_t *)b;
392}
393
394/*
395 * IFDv1 always has 8 regions, while IFDv2 always has 16 regions.
396 *
397 * It's platform specific which regions are used or are reserved.
398 * The 'SPI programming guide' as the name says is a guide only,
399 * not a specification what the hardware actually does.
400 * The best to do is not to rely on the guide, but detect how many
401 * regions are present in the IFD and expose them all.
402 *
403 * Very early IFDv2 chipsets, sometimes unofficially referred to as
404 * IFDv1.5 platforms, only have 8 regions. To not corrupt the IFD when
405 * operating on an IFDv1.5 detect how much space is actually present
406 * in the IFD.
407 */
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100408static int max_regions_from_fdbar(const struct fdbar *fdb)
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200409{
410 const size_t fcba = (fdb->flmap0 & 0xff) << 4;
411 const size_t fmba = (fdb->flmap1 & 0xff) << 4;
412 const size_t frba = ((fdb->flmap0 >> 16) & 0xff) << 4;
413 const size_t fpsba = ((fdb->flmap1 >> 16) & 0xff) << 4;
414 const size_t flumap = 4096 - 256 - 4;
415 size_t sorted[5] = {fcba, fmba, frba, fpsba, flumap};
416
417 qsort(sorted, ARRAY_SIZE(sorted), sizeof(size_t), sort_compare);
418
419 for (size_t i = 0; i < 4; i++) {
420 /*
421 * Find FRBA in the sorted array and determine the size of the
422 * region by the start of the next region. Every region requires
423 * 4 bytes of space.
424 */
425 if (sorted[i] == frba)
426 return MIN((sorted[i+1] - sorted[i])/4, MAX_REGIONS);
427 }
428 /* Never reaches this point */
429 return 0;
430}
431
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100432static void dump_frba(const struct frba *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700433{
Bill XIE4651d452017-09-12 11:54:48 +0800434 unsigned int i;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100435 struct region region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700436 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800437 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530438 region = get_region(frba, i);
439 /* Skip unused & reserved Flash Region */
440 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
441 continue;
442
Bill XIE4651d452017-09-12 11:54:48 +0800443 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
444 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700445 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700446}
447
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100448static void dump_flashrom_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500449{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100450 const struct frba *frba = find_frba(image, size);
451 if (!frba)
452 exit(EXIT_FAILURE);
Chris Douglass03ce0142014-02-26 13:30:13 -0500453
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100454 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
Chris Douglass03ce0142014-02-26 13:30:13 -0500455 if (layout_fd == -1) {
456 perror("Could not open file");
457 exit(EXIT_FAILURE);
458 }
459
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100460 for (unsigned int i = 0; i < max_regions; i++) {
461 struct region region = get_region(frba, i);
Maximilian Brune2c895aa2023-04-24 19:28:21 +0200462
463 /* A region limit of 0 is an indicator of an unused region
464 * A region base of 7FFFh is an indicator of a reserved region
465 */
466 if (region.limit == 0 || region.base == 0x07FFF000)
Alexander Couzenseff596b2016-10-08 00:53:09 +0200467 continue;
468
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100469 char buf[LAYOUT_LINELEN];
470 snprintf(buf, LAYOUT_LINELEN, "%08x:%08x %s\n", region.base, region.limit, region_names[i].terse);
Chris Douglass03ce0142014-02-26 13:30:13 -0500471 if (write(layout_fd, buf, strlen(buf)) < 0) {
472 perror("Could not write to file");
473 exit(EXIT_FAILURE);
474 }
475 }
476 close(layout_fd);
477 printf("Wrote layout to %s\n", layout_fname);
478}
479
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530480static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700481{
482 switch (freq) {
483 case SPI_FREQUENCY_20MHZ:
484 printf("20MHz");
485 break;
486 case SPI_FREQUENCY_33MHZ:
487 printf("33MHz");
488 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700489 case SPI_FREQUENCY_48MHZ:
490 printf("48MHz");
491 break;
492 case SPI_FREQUENCY_50MHZ_30MHZ:
493 switch (ifd_version) {
494 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +0200495 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700496 printf("50MHz");
497 break;
498 case IFD_VERSION_2:
499 printf("30MHz");
500 break;
501 }
502 break;
503 case SPI_FREQUENCY_17MHZ:
504 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700505 break;
506 default:
507 printf("unknown<%x>MHz", freq);
508 }
509}
510
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530511static void _decode_spi_frequency_500_series(unsigned int freq)
512{
513 switch (freq) {
514 case SPI_FREQUENCY_100MHZ:
515 printf("100MHz");
516 break;
517 case SPI_FREQUENCY_50MHZ:
518 printf("50MHz");
519 break;
520 case SPI_FREQUENCY_500SERIES_33MHZ:
521 printf("33MHz");
522 break;
523 case SPI_FREQUENCY_25MHZ:
524 printf("25MHz");
525 break;
526 case SPI_FREQUENCY_14MHZ:
527 printf("14MHz");
528 break;
529 default:
530 printf("unknown<%x>MHz", freq);
531 }
532}
533
534static void decode_spi_frequency(unsigned int freq)
535{
Subrata Banik9cd85d02023-05-24 23:18:49 +0530536 switch (chipset) {
537 case CHIPSET_500_600_SERIES_TIGER_ALDER_POINT:
538 case CHIPSET_800_SERIES_METEOR_LAKE:
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530539 _decode_spi_frequency_500_series(freq);
Subrata Banik9cd85d02023-05-24 23:18:49 +0530540 break;
541 default:
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530542 _decode_spi_frequency(freq);
Subrata Banik9cd85d02023-05-24 23:18:49 +0530543 }
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530544}
545
Subrata Banike5d39922020-08-26 16:01:42 +0530546static void _decode_espi_frequency(unsigned int freq)
547{
548 switch (freq) {
549 case ESPI_FREQUENCY_20MHZ:
550 printf("20MHz");
551 break;
552 case ESPI_FREQUENCY_24MHZ:
553 printf("24MHz");
554 break;
555 case ESPI_FREQUENCY_30MHZ:
556 printf("30MHz");
557 break;
558 case ESPI_FREQUENCY_48MHZ:
559 printf("48MHz");
560 break;
561 case ESPI_FREQUENCY_60MHZ:
562 printf("60MHz");
563 break;
564 case ESPI_FREQUENCY_17MHZ:
565 printf("17MHz");
566 break;
567 default:
568 printf("unknown<%x>MHz", freq);
569 }
570}
571
572static void _decode_espi_frequency_500_series(unsigned int freq)
573{
574 switch (freq) {
575 case ESPI_FREQUENCY_500SERIES_20MHZ:
576 printf("20MHz");
577 break;
578 case ESPI_FREQUENCY_500SERIES_24MHZ:
579 printf("24MHz");
580 break;
581 case ESPI_FREQUENCY_500SERIES_25MHZ:
582 printf("25MHz");
583 break;
584 case ESPI_FREQUENCY_500SERIES_48MHZ:
585 printf("48MHz");
586 break;
587 case ESPI_FREQUENCY_500SERIES_60MHZ:
588 printf("60MHz");
589 break;
590 default:
591 printf("unknown<%x>MHz", freq);
592 }
593}
594
Subrata Banik9cd85d02023-05-24 23:18:49 +0530595static void _decode_espi_frequency_800_series(unsigned int freq)
596{
597 switch (freq) {
598 case ESPI_FREQUENCY_800SERIES_20MHZ:
599 printf("20MHz");
600 break;
601 case ESPI_FREQUENCY_800SERIES_25MHZ:
602 printf("25MHz");
603 break;
604 case ESPI_FREQUENCY_800SERIES_33MHZ:
605 printf("33MHz");
606 break;
607 case ESPI_FREQUENCY_800SERIES_50MHZ:
608 printf("50MHz");
609 break;
610 default:
611 printf("unknown<%x>MHz", freq);
612 }
613}
614
Subrata Banike5d39922020-08-26 16:01:42 +0530615static void decode_espi_frequency(unsigned int freq)
616{
Subrata Banika5f47812020-09-29 11:43:01 +0530617 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530618 _decode_espi_frequency_500_series(freq);
Subrata Banik9cd85d02023-05-24 23:18:49 +0530619 else if (chipset == CHIPSET_800_SERIES_METEOR_LAKE)
620 _decode_espi_frequency_800_series(freq);
Subrata Banike5d39922020-08-26 16:01:42 +0530621 else
622 _decode_espi_frequency(freq);
623}
624
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700625static void decode_component_density(unsigned int density)
626{
627 switch (density) {
628 case COMPONENT_DENSITY_512KB:
629 printf("512KB");
630 break;
631 case COMPONENT_DENSITY_1MB:
632 printf("1MB");
633 break;
634 case COMPONENT_DENSITY_2MB:
635 printf("2MB");
636 break;
637 case COMPONENT_DENSITY_4MB:
638 printf("4MB");
639 break;
640 case COMPONENT_DENSITY_8MB:
641 printf("8MB");
642 break;
643 case COMPONENT_DENSITY_16MB:
644 printf("16MB");
645 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700646 case COMPONENT_DENSITY_32MB:
647 printf("32MB");
648 break;
649 case COMPONENT_DENSITY_64MB:
650 printf("64MB");
651 break;
652 case COMPONENT_DENSITY_UNUSED:
653 printf("UNUSED");
654 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700655 default:
656 printf("unknown<%x>MB", density);
657 }
658}
659
Subrata Banik26058dc2020-08-26 15:12:16 +0530660static int is_platform_with_pch(void)
661{
662 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
663 return 1;
664
665 return 0;
666}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530667
668/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
669static int is_platform_with_100x_series_pch(void)
670{
671 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banik9cd85d02023-05-24 23:18:49 +0530672 chipset <= CHIPSET_800_SERIES_METEOR_LAKE)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530673 return 1;
674
675 return 0;
676}
677
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100678static void dump_fcba(const struct fcba *fcba, const struct fpsba *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700679{
Subrata Banike5d39922020-08-26 16:01:42 +0530680 unsigned int freq;
681
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700682 printf("\nFound Component Section\n");
683 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700684 printf(" Dual Output Fast Read Support: %ssupported\n",
685 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700686 printf(" Read ID/Read Status Clock Frequency: ");
687 decode_spi_frequency((fcba->flcomp >> 27) & 7);
688 printf("\n Write/Erase Clock Frequency: ");
689 decode_spi_frequency((fcba->flcomp >> 24) & 7);
690 printf("\n Fast Read Clock Frequency: ");
691 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700692 printf("\n Fast Read Support: %ssupported",
693 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530694 if (is_platform_with_100x_series_pch() &&
695 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
696 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530697 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530698 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
Subrata Banik9cd85d02023-05-24 23:18:49 +0530699 else if (chipset == CHIPSET_800_SERIES_METEOR_LAKE)
700 freq = (fpsba->pchstrp[65] & 0x38) >> 3;
Subrata Banike5d39922020-08-26 16:01:42 +0530701 else
702 freq = (fcba->flcomp >> 17) & 7;
703 decode_espi_frequency(freq);
704 } else {
705 printf("\n Read Clock Frequency: ");
706 decode_spi_frequency((fcba->flcomp >> 17) & 7);
707 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700708
709 switch (ifd_version) {
710 case IFD_VERSION_1:
711 printf("\n Component 2 Density: ");
712 decode_component_density((fcba->flcomp >> 3) & 7);
713 printf("\n Component 1 Density: ");
714 decode_component_density(fcba->flcomp & 7);
715 break;
Patrick Rudolph16598742022-10-21 15:13:43 +0200716 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700717 case IFD_VERSION_2:
718 printf("\n Component 2 Density: ");
719 decode_component_density((fcba->flcomp >> 4) & 0xf);
720 printf("\n Component 1 Density: ");
721 decode_component_density(fcba->flcomp & 0xf);
722 break;
723 }
724
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700725 printf("\n");
726 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700727 printf(" Invalid Instruction 3: 0x%02x\n",
728 (fcba->flill >> 24) & 0xff);
729 printf(" Invalid Instruction 2: 0x%02x\n",
730 (fcba->flill >> 16) & 0xff);
731 printf(" Invalid Instruction 1: 0x%02x\n",
732 (fcba->flill >> 8) & 0xff);
733 printf(" Invalid Instruction 0: 0x%02x\n",
734 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530735 if (is_platform_with_100x_series_pch()) {
736 printf("FLILL1 0x%08x\n", fcba->flpb);
737 printf(" Invalid Instruction 7: 0x%02x\n",
738 (fcba->flpb >> 24) & 0xff);
739 printf(" Invalid Instruction 6: 0x%02x\n",
740 (fcba->flpb >> 16) & 0xff);
741 printf(" Invalid Instruction 5: 0x%02x\n",
742 (fcba->flpb >> 8) & 0xff);
743 printf(" Invalid Instruction 4: 0x%02x\n",
744 fcba->flpb & 0xff);
745 } else {
746 printf("FLPB 0x%08x\n", fcba->flpb);
747 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
748 (fcba->flpb & 0xfff) << 12);
749 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700750}
751
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100752static void dump_fpsba(const struct fdbar *fdb, const struct fpsba *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700753{
Bill XIE4651d452017-09-12 11:54:48 +0800754 unsigned int i;
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200755 /* SoC Straps, aka PSL, aka ISL */
756 unsigned int SS = (fdb->flmap1 >> 24) & 0xff;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200757
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700758 printf("Found PCH Strap Section\n");
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200759 for (i = 0; i < SS; i++)
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200760 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800761
762 if (ifd_version >= IFD_VERSION_2) {
763 printf("HAP bit is %sset\n",
764 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100765 } else if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
Bill XIEb3e15a22017-09-07 18:34:50 +0800766 printf("ICH_MeDisable bit is %sset\n",
767 fpsba->pchstrp[0] & 1 ? "" : "not ");
768 } else {
769 printf("AltMeDisable bit is %sset\n",
770 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
771 }
772
Bill XIE4651d452017-09-12 11:54:48 +0800773 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700774}
775
776static void decode_flmstr(uint32_t flmstr)
777{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700778 int wr_shift, rd_shift;
779 if (ifd_version >= IFD_VERSION_2) {
780 wr_shift = FLMSTR_WR_SHIFT_V2;
781 rd_shift = FLMSTR_RD_SHIFT_V2;
782 } else {
783 wr_shift = FLMSTR_WR_SHIFT_V1;
784 rd_shift = FLMSTR_RD_SHIFT_V1;
785 }
786
787 /* EC region access only available on v2+ */
Jeff Dalyabd4b962022-01-06 00:52:30 -0500788 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700789 printf(" EC Region Write Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100790 (flmstr & (1 << (wr_shift + 8))) ?
791 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700792 printf(" Platform Data Region Write Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100793 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500794 if (PLATFORM_HAS_GBE_REGION) {
795 printf(" GbE Region Write Access: %s\n",
796 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
797 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700798 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700799 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700800 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700801 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700802 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700803 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500804 if (PLATFORM_HAS_10GBE_0_REGION) {
805 printf(" 10GbE_0 Write Access: %s\n",
806 (flmstr & (1 << (wr_shift + 11))) ? "enabled" : "disabled");
807 }
808 if (PLATFORM_HAS_10GBE_1_REGION) {
809 printf(" 10GbE_1 Write Access: %s\n",
810 (flmstr & (1 << 4)) ? "enabled" : "disabled");
811 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700812
Jeff Dalyabd4b962022-01-06 00:52:30 -0500813 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700814 printf(" EC Region Read Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100815 (flmstr & (1 << (rd_shift + 8))) ?
816 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700817 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700818 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500819 if (PLATFORM_HAS_GBE_REGION) {
820 printf(" GbE Region Read Access: %s\n",
821 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
822 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700823 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700824 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700825 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700826 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700827 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700828 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500829 if (PLATFORM_HAS_10GBE_0_REGION) {
830 printf(" 10GbE_0 Read Access: %s\n",
831 (flmstr & (1 << (rd_shift + 11))) ? "enabled" : "disabled");
832 }
833 if (PLATFORM_HAS_10GBE_1_REGION) {
834 printf(" 10GbE_1 Read Access: %s\n",
835 (flmstr & (1 << 0)) ? "enabled" : "disabled");
836 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700837
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700838 /* Requestor ID doesn't exist for ifd 2 */
839 if (ifd_version < IFD_VERSION_2)
840 printf(" Requester ID: 0x%04x\n\n",
841 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700842}
843
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100844static void dump_fmba(const struct fmba *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700845{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700846 printf("Found Master Section\n");
847 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
848 decode_flmstr(fmba->flmstr1);
849 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
850 decode_flmstr(fmba->flmstr2);
Jeff Dalyabd4b962022-01-06 00:52:30 -0500851 if (PLATFORM_HAS_GBE_REGION) {
852 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
853 decode_flmstr(fmba->flmstr3);
854 if (ifd_version >= IFD_VERSION_2) {
855 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
856 decode_flmstr(fmba->flmstr5);
857 }
858 } else {
859 printf("FLMSTR6: 0x%08x (IE)\n", fmba->flmstr6);
860 decode_flmstr(fmba->flmstr6);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700861 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700862}
863
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100864static void dump_fmsba(const struct fmsba *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700865{
Bill XIE612ec0e2017-08-30 16:10:27 +0800866 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700867 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800868 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
869 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800870
871 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
872 printf("MCH_MeDisable bit is %sset\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100873 fmsba->data[0] & 1 ? "" : "not ");
Bill XIEb3e15a22017-09-07 18:34:50 +0800874 printf("MCH_AltMeDisable bit is %sset\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100875 fmsba->data[0] & (1 << 7) ? "" : "not ");
Bill XIEb3e15a22017-09-07 18:34:50 +0800876 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700877}
878
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700879static void dump_jid(uint32_t jid)
880{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100881 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700882 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100883 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200884 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100885 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200886 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700887}
888
889static void dump_vscc(uint32_t vscc)
890{
891 printf(" Lower Erase Opcode: 0x%02x\n",
892 vscc >> 24);
893 printf(" Lower Write Enable on Write Status: 0x%02x\n",
894 vscc & (1 << 20) ? 0x06 : 0x50);
895 printf(" Lower Write Status Required: %s\n",
896 vscc & (1 << 19) ? "Yes" : "No");
897 printf(" Lower Write Granularity: %d bytes\n",
898 vscc & (1 << 18) ? 64 : 1);
899 printf(" Lower Block / Sector Erase Size: ");
900 switch ((vscc >> 16) & 0x3) {
901 case 0:
902 printf("256 Byte\n");
903 break;
904 case 1:
905 printf("4KB\n");
906 break;
907 case 2:
908 printf("8KB\n");
909 break;
910 case 3:
911 printf("64KB\n");
912 break;
913 }
914
915 printf(" Upper Erase Opcode: 0x%02x\n",
916 (vscc >> 8) & 0xff);
917 printf(" Upper Write Enable on Write Status: 0x%02x\n",
918 vscc & (1 << 4) ? 0x06 : 0x50);
919 printf(" Upper Write Status Required: %s\n",
920 vscc & (1 << 3) ? "Yes" : "No");
921 printf(" Upper Write Granularity: %d bytes\n",
922 vscc & (1 << 2) ? 64 : 1);
923 printf(" Upper Block / Sector Erase Size: ");
924 switch (vscc & 0x3) {
925 case 0:
926 printf("256 Byte\n");
927 break;
928 case 1:
929 printf("4KB\n");
930 break;
931 case 2:
932 printf("8KB\n");
933 break;
934 case 3:
935 printf("64KB\n");
936 break;
937 }
938}
939
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100940static void dump_vtba(const struct vtba *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700941{
942 int i;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100943 int max_len = sizeof(struct vtba)/sizeof(struct vscc);
Stefan Tauner0d226142018-08-05 18:56:53 +0200944 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700945
946 printf("ME VSCC table:\n");
947 for (i = 0; i < num; i++) {
948 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
949 dump_jid(vtba->entry[i].jid);
950 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
951 dump_vscc(vtba->entry[i].vscc);
952 }
953 printf("\n");
954}
955
Bill XIEfa5f9942017-09-12 11:22:29 +0800956static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700957{
958 int i, j;
959 printf("OEM Section:\n");
960 for (i = 0; i < 4; i++) {
961 printf("%02x:", i << 4);
962 for (j = 0; j < 16; j++)
963 printf(" %02x", oem[(i<<4)+j]);
964 printf ("\n");
965 }
966 printf ("\n");
967}
968
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700969static void dump_fd(char *image, int size)
970{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100971 const struct fdbar *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700972 if (!fdb)
973 exit(EXIT_FAILURE);
974
Subrata Banik26058dc2020-08-26 15:12:16 +0530975 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
976 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700977 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530978 if (!is_platform_with_100x_series_pch())
979 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700980 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
981 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
982 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
983
984 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530985 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
986 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700987 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
988 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
989 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
990
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530991 if (!is_platform_with_100x_series_pch()) {
992 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
993 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
994 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
995 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700996
Subrata Banik9cd85d02023-05-24 23:18:49 +0530997 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT ||
998 chipset == CHIPSET_800_SERIES_METEOR_LAKE) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530999 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
1000 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
1001 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
1002 }
1003
Stefan Tauner0d226142018-08-05 18:56:53 +02001004 char *flumap = find_flumap(image, size);
1005 uint32_t flumap1 = *(uint32_t *)flumap;
1006 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001007 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +02001008 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001009 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +02001010 (flumap1 & 0xff) << 4);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001011 dump_vtba((struct vtba *)
Stefan Tauner0d226142018-08-05 18:56:53 +02001012 (image + ((flumap1 & 0xff) << 4)),
1013 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +08001014 dump_oem((const uint8_t *)image + 0xf00);
1015
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001016 const struct frba *frba = find_frba(image, size);
1017 const struct fcba *fcba = find_fcba(image, size);
1018 const struct fpsba *fpsba = find_fpsba(image, size);
1019 const struct fmba *fmba = find_fmba(image, size);
1020 const struct fmsba *fmsba = find_fmsba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001021
1022 if (frba && fcba && fpsba && fmba && fmsba) {
1023 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +05301024 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001025 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +08001026 dump_fmba(fmba);
1027 dump_fmsba(fmsba);
1028 } else {
1029 printf("FD is corrupted!\n");
1030 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001031}
1032
Maximilian Brune347596a2023-03-05 20:55:32 +01001033/* Takes an image containing an IFD and creates a Flashmap .fmd file template.
1034 * This flashmap will contain all IFD regions except the BIOS region.
1035 * The BIOS region is created by coreboot itself and 'should' match the IFD region
1036 * anyway (CONFIG_VALIDATE_INTEL_DESCRIPTOR should make sure). coreboot built system will use
1037 * this template to generate the final Flashmap file.
1038 */
1039static void create_fmap_template(char *image, int size, const char *layout_fname)
1040{
1041 const struct frba *frba = find_frba(image, size);
1042 if (!frba)
1043 exit(EXIT_FAILURE);
1044
1045 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1046 if (layout_fd == -1) {
1047 perror("Could not open file");
1048 exit(EXIT_FAILURE);
1049 }
1050
1051 char *bbuf = "FLASH@##ROM_BASE## ##ROM_SIZE## {\n";
1052 if (write(layout_fd, bbuf, strlen(bbuf)) < 0) {
1053 perror("Could not write to file");
1054 exit(EXIT_FAILURE);
1055 }
1056
1057 /* fmaptool requires regions in .fmd to be sorted.
1058 * => We need to sort the regions by base address before writing them in .fmd File
1059 */
1060 int count_regions = 0;
1061 struct region sorted_regions[MAX_REGIONS] = { 0 };
1062 for (unsigned int i = 0; i < max_regions; i++) {
1063 struct region region = get_region(frba, i);
Maximilian Brune2c895aa2023-04-24 19:28:21 +02001064
1065 /* A region limit of 0 is an indicator of an unused region
1066 * A region base of 7FFFh is an indicator of a reserved region
1067 */
1068 if (region.limit == 0 || region.base == 0x07FFF000)
Maximilian Brune347596a2023-03-05 20:55:32 +01001069 continue;
1070
Maximilian Brune794d1d72023-11-13 02:07:01 +01001071 /* Is there an FMAP equivalent? IFD reserved regions are usually thrown out
1072 * of the FMAP here
1073 */
1074 if (!region_names[region.type].fmapname) {
1075 printf("Skip IFD region: %s\n", region_names[region.type].pretty);
1076 continue;
1077 }
1078
Maximilian Brune347596a2023-03-05 20:55:32 +01001079 /* Here we decide to use the coreboot generated FMAP BIOS region, instead of
1080 * the one specified in the IFD. The case when IFD and FMAP BIOS region do not
1081 * match cannot be caught here, therefore one should still validate IFD and
1082 * FMAP via CONFIG_VALIDATE_INTEL_DESCRIPTOR
1083 */
1084 if (i == REGION_BIOS)
1085 continue;
1086
1087 sorted_regions[count_regions] = region;
1088 // basically insertion sort
1089 for (int i = count_regions-1; i >= 0 ; i--) {
1090 if (sorted_regions[i].base > sorted_regions[i+1].base) {
1091 struct region tmp = sorted_regions[i];
1092 sorted_regions[i] = sorted_regions[i+1];
1093 sorted_regions[i+1] = tmp;
1094 }
1095 }
1096 count_regions++;
1097 }
1098
1099 // Now write regions sorted by base address in the fmap file
1100 for (int i = 0; i < count_regions; i++) {
1101 struct region region = sorted_regions[i];
1102 char buf[LAYOUT_LINELEN];
1103 snprintf(buf, LAYOUT_LINELEN, "\t%s@0x%X 0x%X\n", region_names[region.type].fmapname, region.base, region.size);
1104 if (write(layout_fd, buf, strlen(buf)) < 0) {
1105 perror("Could not write to file");
1106 exit(EXIT_FAILURE);
1107 }
1108 }
1109
1110 char *ebuf = "\tSI_BIOS@##BIOS_BASE## ##BIOS_SIZE## {\n"
1111 "\t\t##CONSOLE_ENTRY##\n"
1112 "\t\t##MRC_CACHE_ENTRY##\n"
1113 "\t\t##SMMSTORE_ENTRY##\n"
1114 "\t\t##SPD_CACHE_ENTRY##\n"
1115 "\t\t##VPD_ENTRY##\n"
1116 "\t\tFMAP@##FMAP_BASE## ##FMAP_SIZE##\n"
1117 "\t\tCOREBOOT(CBFS)@##CBFS_BASE## ##CBFS_SIZE##\n"
1118 "\t}\n"
1119 "}\n";
1120 if (write(layout_fd, ebuf, strlen(ebuf)) < 0) {
1121 perror("Could not write to file");
1122 exit(EXIT_FAILURE);
1123 }
1124
1125 close(layout_fd);
1126 printf("Wrote layout to %s\n", layout_fname);
1127}
1128
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001129static void write_regions(char *image, int size)
1130{
Bill XIEfa5f9942017-09-12 11:22:29 +08001131 unsigned int i;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001132 const struct frba *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001133
Bill XIE612ec0e2017-08-30 16:10:27 +08001134 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001135 exit(EXIT_FAILURE);
1136
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001137 for (i = 0; i < max_regions; i++) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001138 struct region region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001139 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001140 if (region.size > 0) {
1141 int region_fd;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001142 region_fd = open(region_names[i].filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001143 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001144 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001145 if (region_fd < 0) {
1146 perror("Error while trying to open file");
1147 exit(EXIT_FAILURE);
1148 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001149 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001150 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001151 close(region_fd);
1152 }
1153 }
1154}
1155
Mathew Kingc7ddc992019-08-08 14:59:25 -06001156static void validate_layout(char *image, int size)
1157{
1158 uint i, errors = 0;
1159 struct fmap *fmap;
1160 long int fmap_loc = fmap_find((uint8_t *)image, size);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001161 const struct frba *frba = find_frba(image, size);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001162
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001163 if (fmap_loc < 0 || !frba) {
1164 printf("Could not find FMAP (%p) or Intel Flash Descriptor (%p)\n",
1165 (void *)fmap_loc, frba);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001166 exit(EXIT_FAILURE);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001167 }
Mathew Kingc7ddc992019-08-08 14:59:25 -06001168
1169 fmap = (struct fmap *)(image + fmap_loc);
1170
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001171 int matches = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001172 for (i = 0; i < max_regions; i++) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001173 struct region region = get_region(frba, i);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001174 if (region.size == 0)
1175 continue;
1176
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001177 const struct fmap_area *area = fmap_find_area(fmap, region_names[i].fmapname);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001178 if (!area)
1179 continue;
1180
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001181 matches++; // found a match between FMAP and IFD region
1182
1183 if ((uint)region.base != area->offset || (uint)region.size != area->size) {
1184 printf("Region mismatch between %s and %s\n", region_names[i].terse, area->name);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001185 printf(" Descriptor region %s:\n", region_names[i].terse);
1186 printf(" offset: 0x%08x\n", region.base);
1187 printf(" length: 0x%08x\n", region.size);
1188 printf(" FMAP area %s:\n", area->name);
1189 printf(" offset: 0x%08x\n", area->offset);
1190 printf(" length: 0x%08x\n", area->size);
1191 errors++;
1192 }
1193 }
1194
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001195 if (!matches) {
1196 // At least a BIOS region should be present in both IFD and FMAP
1197 fprintf(stderr, "Warning: Not a single IFD region found in FMAP\n");
1198 }
1199
Mathew Kingc7ddc992019-08-08 14:59:25 -06001200 if (errors > 0)
1201 exit(EXIT_FAILURE);
1202}
1203
Bill XIEfa5f9942017-09-12 11:22:29 +08001204static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001205{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001206 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001207 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001208
1209 // Now write out new image
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001210 new_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001211 if (new_fd < 0) {
1212 perror("Error while trying to open file");
1213 exit(EXIT_FAILURE);
1214 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001215 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001216 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001217 close(new_fd);
1218}
1219
Bill XIEfa5f9942017-09-12 11:22:29 +08001220static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001221 enum spi_frequency freq)
1222{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001223 struct fcba *fcba = find_fcba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001224 if (!fcba)
1225 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001226
1227 /* clear bits 21-29 */
1228 fcba->flcomp &= ~0x3fe00000;
1229 /* Read ID and Read Status Clock Frequency */
1230 fcba->flcomp |= freq << 27;
1231 /* Write and Erase Clock Frequency */
1232 fcba->flcomp |= freq << 24;
1233 /* Fast Read Clock Frequency */
1234 fcba->flcomp |= freq << 21;
1235
1236 write_image(filename, image, size);
1237}
1238
Bill XIEfa5f9942017-09-12 11:22:29 +08001239static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001240{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001241 struct fcba *fcba = find_fcba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001242 if (!fcba)
1243 exit(EXIT_FAILURE);
1244
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001245 int freq;
1246
1247 switch (ifd_version) {
1248 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +02001249 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001250 freq = SPI_FREQUENCY_20MHZ;
1251 break;
1252 case IFD_VERSION_2:
1253 freq = SPI_FREQUENCY_17MHZ;
1254 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001255 default:
1256 freq = SPI_FREQUENCY_17MHZ;
1257 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001258 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001259
1260 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001261 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001262}
1263
Bill XIEfa5f9942017-09-12 11:22:29 +08001264static void set_chipdensity(const char *filename, char *image, int size,
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001265 unsigned int density)
Jan Tatjefa317512016-03-11 00:52:07 +01001266{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001267 struct fcba *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001268 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001269 if (!fcba)
1270 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001271
1272 printf("Setting chip density to ");
1273 decode_component_density(density);
1274 printf("\n");
1275
1276 switch (ifd_version) {
1277 case IFD_VERSION_1:
1278 /* fail if selected density is not supported by this version */
1279 if ( (density == COMPONENT_DENSITY_32MB) ||
1280 (density == COMPONENT_DENSITY_64MB) ||
1281 (density == COMPONENT_DENSITY_UNUSED) ) {
1282 printf("error: Selected density not supported in IFD version 1.\n");
1283 exit(EXIT_FAILURE);
1284 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001285 mask = 0x7;
1286 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001287 break;
Patrick Rudolph16598742022-10-21 15:13:43 +02001288 case IFD_VERSION_1_5:
Jan Tatjefa317512016-03-11 00:52:07 +01001289 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001290 mask = 0xf;
1291 chip2_offset = 4;
1292 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001293 default:
1294 printf("error: Unknown IFD version\n");
1295 exit(EXIT_FAILURE);
1296 break;
1297 }
1298
1299 /* clear chip density for corresponding chip */
1300 switch (selected_chip) {
1301 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001302 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001303 break;
1304 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001305 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001306 break;
1307 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001308 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001309 break;
1310 }
1311
1312 /* set the new density */
1313 if (selected_chip == 1 || selected_chip == 0)
1314 fcba->flcomp |= (density); /* first chip */
1315 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001316 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001317
1318 write_image(filename, image, size);
1319}
1320
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001321static int check_region(const struct frba *frba, unsigned int region_type)
Duncan Laurie7775d672019-06-06 13:39:26 -07001322{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001323 struct region region;
Duncan Laurie7775d672019-06-06 13:39:26 -07001324
1325 if (!frba)
1326 return 0;
1327
1328 region = get_region(frba, region_type);
1329 return !!((region.base < region.limit) && (region.size > 0));
1330}
1331
Reka Normanafed45d2024-01-05 12:54:44 +11001332/*
1333 * Platforms from CNL onwards support up to 16 flash regions, not 12. The
1334 * permissions for regions [15:12] are stored in extended region read/write
1335 * access fields in the FLMSTR registers.
1336 *
1337 * FLMSTR with extended regions:
1338 * 31:20 Region Write Access
1339 * 19:8 Region Read Access
1340 * 7:4 Extended Region Write Access
1341 * 3:0 Extended Region Read Access
1342 *
1343 * FLMSTR without extended regions:
1344 * 31:20 Region Write Access
1345 * 19:8 Region Read Access
1346 * 7:0 Reserved
1347 */
1348static bool platform_has_extended_regions(void)
1349{
1350 switch (platform) {
1351 case PLATFORM_CNL:
1352 case PLATFORM_JSL:
1353 case PLATFORM_TGL:
1354 case PLATFORM_ADL:
1355 case PLATFORM_MTL:
1356 return true;
1357 default:
1358 return false;
1359 }
1360}
1361
Bill XIEfa5f9942017-09-12 11:22:29 +08001362static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001363{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001364 int wr_shift, rd_shift;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001365 struct fmba *fmba = find_fmba(image, size);
1366 const struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001367 if (!fmba)
1368 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001369
1370 if (ifd_version >= IFD_VERSION_2) {
1371 wr_shift = FLMSTR_WR_SHIFT_V2;
1372 rd_shift = FLMSTR_RD_SHIFT_V2;
1373
Reka Normanafed45d2024-01-05 12:54:44 +11001374 /*
1375 * Clear all read/write access bits. See comment on
1376 * platform_has_extended_regions() for bitfields.
1377 */
1378 if (platform_has_extended_regions()) {
1379 fmba->flmstr1 = 0;
1380 fmba->flmstr2 = 0;
1381 fmba->flmstr3 = 0;
1382 fmba->flmstr5 = 0;
1383 } else {
1384 fmba->flmstr1 &= 0xff;
1385 fmba->flmstr2 &= 0xff;
1386 fmba->flmstr3 &= 0xff;
1387 fmba->flmstr5 &= 0xff;
1388 }
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001389 } else {
1390 wr_shift = FLMSTR_WR_SHIFT_V1;
1391 rd_shift = FLMSTR_RD_SHIFT_V1;
1392
1393 fmba->flmstr1 = 0;
1394 fmba->flmstr2 = 0;
1395 /* Requestor ID */
1396 fmba->flmstr3 = 0x118;
1397 }
1398
Andrey Petrov96ecb772016-10-31 19:31:54 -07001399 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001400 case PLATFORM_APL:
1401 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001402 /* CPU/BIOS can read descriptor and BIOS */
1403 fmba->flmstr1 |= 0x3 << rd_shift;
1404 /* CPU/BIOS can write BIOS */
1405 fmba->flmstr1 |= 0x2 << wr_shift;
1406 /* TXE can read descriptor, BIOS and Device Expansion */
1407 fmba->flmstr2 |= 0x23 << rd_shift;
1408 /* TXE can only write Device Expansion */
1409 fmba->flmstr2 |= 0x20 << wr_shift;
1410 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001411 case PLATFORM_CNL:
1412 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001413 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001414 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301415 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001416 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301417 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001418 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +05301419 case PLATFORM_MTL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001420 /* CPU/BIOS can read descriptor and BIOS. */
1421 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1422 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1423 /* CPU/BIOS can write BIOS. */
1424 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1425 /* ME can read descriptor and ME. */
1426 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1427 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001428 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001429 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1430 if (check_region(frba, REGION_GBE)) {
1431 /* BIOS can read/write GbE. */
1432 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1433 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1434 /* ME can read GbE. */
1435 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1436 /* GbE can read descriptor and read/write GbE.. */
1437 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1438 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1439 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1440 }
1441 if (check_region(frba, REGION_PDR)) {
1442 /* BIOS can read/write PDR. */
1443 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1444 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1445 }
1446 if (check_region(frba, REGION_EC)) {
1447 /* BIOS can read EC. */
1448 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1449 /* EC can read descriptor and read/write EC. */
1450 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1451 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1452 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1453 }
Subrata Banike8cfb882024-01-12 01:30:13 +05301454 if (check_region(frba, REGION_DEV_EXP2)) {
1455 /* BIOS can read SPI device expansion 2 region. */
1456 fmba->flmstr1 |= (1 << REGION_DEV_EXP2) << rd_shift;
1457 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001458 break;
Jeff Dalyabd4b962022-01-06 00:52:30 -05001459 case PLATFORM_DNV:
Patrick Rudolph16598742022-10-21 15:13:43 +02001460 case PLATFORM_WBG:
Jeff Dalyabd4b962022-01-06 00:52:30 -05001461 /* CPU/BIOS can read descriptor and BIOS. */
1462 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1463 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1464 /* CPU/BIOS can write BIOS. */
1465 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1466 /* ME can read descriptor and ME. */
1467 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1468 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1469 /* ME can write ME. */
1470 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1471 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001472 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001473 /* CPU/BIOS can read descriptor and BIOS. */
1474 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1475 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1476 /* CPU/BIOS can write BIOS. */
1477 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1478 /* ME can read descriptor and ME. */
1479 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1480 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1481 /* ME can write ME. */
1482 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1483 if (check_region(frba, REGION_GBE)) {
1484 /* BIOS can read GbE. */
1485 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1486 /* BIOS can write GbE. */
1487 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1488 /* ME can read GbE. */
1489 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1490 /* ME can write GbE. */
1491 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1492 /* GbE can write GbE. */
1493 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1494 /* GbE can read GbE. */
1495 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1496 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001497 break;
1498 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001499
1500 write_image(filename, image, size);
1501}
1502
Usha P412679d2020-10-15 11:25:08 +05301503static void enable_cpu_read_me(const char *filename, char *image, int size)
1504{
1505 int rd_shift;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001506 struct fmba *fmba = find_fmba(image, size);
Usha P412679d2020-10-15 11:25:08 +05301507
1508 if (!fmba)
1509 exit(EXIT_FAILURE);
1510
1511 if (ifd_version >= IFD_VERSION_2)
1512 rd_shift = FLMSTR_RD_SHIFT_V2;
1513 else
1514 rd_shift = FLMSTR_RD_SHIFT_V1;
1515
1516 /* CPU/BIOS can read ME. */
1517 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1518
1519 write_image(filename, image, size);
1520}
1521
Bill XIEfa5f9942017-09-12 11:22:29 +08001522static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001523{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001524 struct fmba *fmba = find_fmba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001525 if (!fmba)
1526 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001527
1528 if (ifd_version >= IFD_VERSION_2) {
Reka Normanafed45d2024-01-05 12:54:44 +11001529 /*
1530 * Set all read/write access bits. See comment on
1531 * platform_has_extended_regions() for bitfields.
1532 */
1533 if (platform_has_extended_regions()) {
1534 fmba->flmstr1 = 0xffffffff;
1535 fmba->flmstr2 = 0xffffffff;
1536 fmba->flmstr3 = 0xffffffff;
1537 fmba->flmstr5 = 0xffffffff;
1538 } else {
1539 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1540 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1541 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
1542 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
1543 }
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001544 } else {
1545 fmba->flmstr1 = 0xffff0000;
1546 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001547 /* Keep chipset specific Requester ID */
1548 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001549 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001550
1551 write_image(filename, image, size);
1552}
1553
Reka Normanc64be922023-10-03 09:47:01 +11001554static void disable_gpr0(const char *filename, char *image, int size)
1555{
1556 struct fpsba *fpsba = find_fpsba(image, size);
1557 if (!fpsba)
1558 exit(EXIT_FAILURE);
1559
1560 /* Offset expressed as number of 32-bit fields from FPSBA */
1561 uint32_t gpr0_offset;
1562 switch (platform) {
1563 case PLATFORM_CNL:
1564 gpr0_offset = 0x10;
1565 break;
1566 case PLATFORM_JSL:
1567 gpr0_offset = 0x12;
1568 break;
1569 case PLATFORM_TGL:
1570 case PLATFORM_ADL:
1571 gpr0_offset = 0x15;
1572 break;
1573 case PLATFORM_MTL:
1574 gpr0_offset = 0x40;
1575 break;
1576 default:
1577 fprintf(stderr, "Disabling GPR0 not supported on this platform\n");
1578 exit(EXIT_FAILURE);
1579 }
Subrata Banik2820d2a2024-01-26 19:09:15 +05301580 /* If bit 31 is set then GPR0 protection is enable */
1581 bool gpr0_status = fpsba->pchstrp[gpr0_offset] & 0x80000000;
1582 if (!gpr0_status) {
1583 printf("GPR0 protection is already disabled\n");
1584 return;
1585 }
Reka Normanc64be922023-10-03 09:47:01 +11001586
Subrata Banik2820d2a2024-01-26 19:09:15 +05301587 printf("Value at GPRD offset (%d) is 0x%08x\n", gpr0_offset, fpsba->pchstrp[gpr0_offset]);
1588 printf("--------- GPR0 Protected Range --------------\n");
1589 /*
1590 * Start Address: bit 0-15 of the GPRD represents the protected region start address,
1591 * where bit 0-11 of the start address are assumed to be zero.
1592 */
1593 printf("Start address = 0x%08x\n", (fpsba->pchstrp[gpr0_offset] & 0xffff) << 12);
1594 /*
1595 * End Address: bit 16-30 of the GPRD represents the protected region end address,
1596 * where bit 0-11 of the end address are assumed to be 0xfff.
1597 */
1598 printf("End address = 0x%08x\n",
1599 ((fpsba->pchstrp[gpr0_offset] >> 16) & 0x7fff) << 12 | 0xfff);
Reka Normanc64be922023-10-03 09:47:01 +11001600 /* 0 means GPR0 protection is disabled */
1601 fpsba->pchstrp[gpr0_offset] = 0;
Reka Normanc64be922023-10-03 09:47:01 +11001602 write_image(filename, image, size);
1603}
1604
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001605static void set_pchstrap(struct fpsba *fpsba, const struct fdbar *fdb, const int strap,
1606 const unsigned int value)
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001607{
1608 if (!fpsba || !fdb) {
1609 fprintf(stderr, "Internal error\n");
1610 exit(EXIT_FAILURE);
1611 }
1612
Arthur Heymans0424a2c2021-06-22 11:14:24 +02001613 /* SoC Strap, aka PSL, aka ISL */
1614 int SS = (fdb->flmap1 >> 24) & 0xff;
1615 if (strap >= SS) {
1616 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SS);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001617 exit(EXIT_FAILURE);
1618 }
1619 fpsba->pchstrp[strap] = value;
1620}
1621
Bill XIEb3e15a22017-09-07 18:34:50 +08001622/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001623static void fpsba_set_altmedisable(struct fpsba *fpsba, struct fmsba *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001624{
1625 if (ifd_version >= IFD_VERSION_2) {
1626 printf("%sting the HAP bit to %s Intel ME...\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001627 altmedisable?"Set":"Unset",
1628 altmedisable?"disable":"enable");
Bill XIEb3e15a22017-09-07 18:34:50 +08001629 if (altmedisable)
1630 fpsba->pchstrp[0] |= (1 << 16);
1631 else
1632 fpsba->pchstrp[0] &= ~(1 << 16);
1633 } else {
1634 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1635 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1636 "and MCH_AltMeDisable to %s Intel ME...\n",
1637 altmedisable?"Set":"Unset",
1638 altmedisable?"disable":"enable");
1639 if (altmedisable) {
1640 /* MCH_MeDisable */
1641 fmsba->data[0] |= 1;
1642 /* MCH_AltMeDisable */
1643 fmsba->data[0] |= (1 << 7);
1644 /* ICH_MeDisable */
1645 fpsba->pchstrp[0] |= 1;
1646 } else {
1647 fmsba->data[0] &= ~1;
1648 fmsba->data[0] &= ~(1 << 7);
1649 fpsba->pchstrp[0] &= ~1;
1650 }
1651 } else {
1652 printf("%sting the AltMeDisable to %s Intel ME...\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001653 altmedisable?"Set":"Unset",
1654 altmedisable?"disable":"enable");
Bill XIEb3e15a22017-09-07 18:34:50 +08001655 if (altmedisable)
1656 fpsba->pchstrp[10] |= (1 << 7);
1657 else
1658 fpsba->pchstrp[10] &= ~(1 << 7);
1659 }
1660 }
1661}
1662
Jacob Garber595d9262019-06-27 17:33:10 -06001663static void inject_region(const char *filename, char *image, int size,
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001664 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001665{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001666 struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001667 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001668 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001669
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001670 struct region region = get_region(frba, region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001671 if (region.size <= 0xfff) {
1672 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1673 region_name(region_type));
1674 exit(EXIT_FAILURE);
1675 }
1676
Scott Duplichanf2c98372014-12-12 21:03:06 -06001677 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001678 if (region_fd == -1) {
1679 perror("Could not open file");
1680 exit(EXIT_FAILURE);
1681 }
1682 struct stat buf;
1683 if (fstat(region_fd, &buf) == -1) {
1684 perror("Could not stat file");
1685 exit(EXIT_FAILURE);
1686 }
1687 int region_size = buf.st_size;
1688
1689 printf("File %s is %d bytes\n", region_fname, region_size);
1690
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001691 if (region_size > region.size) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001692 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1693 " bytes. Not injecting.\n",
1694 region_name(region_type), region.size,
1695 region.size, region_size, region_size);
1696 exit(EXIT_FAILURE);
1697 }
1698
1699 int offset = 0;
1700 if ((region_type == 1) && (region_size < region.size)) {
1701 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1702 " bytes. Padding before injecting.\n",
1703 region_name(region_type), region.size,
1704 region.size, region_size, region_size);
1705 offset = region.size - region_size;
1706 memset(image + region.base, 0xff, offset);
1707 }
1708
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001709 if (size < region.base + offset + region_size) {
1710 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1711 size, region.base + offset + region_size);
1712 exit(EXIT_FAILURE);
1713 }
1714
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001715 if (read(region_fd, image + region.base + offset, region_size) != region_size) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001716 perror("Could not read file");
1717 exit(EXIT_FAILURE);
1718 }
1719
1720 close(region_fd);
1721
1722 printf("Adding %s as the %s section of %s\n",
1723 region_fname, region_name(region_type), filename);
1724 write_image(filename, image, size);
1725}
1726
Jacob Garber595d9262019-06-27 17:33:10 -06001727static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001728{
1729 unsigned int y = 1;
1730 if (x == 0)
1731 return 0;
1732 while (y <= x)
1733 y = y << 1;
1734
1735 return y;
1736}
1737
1738/**
1739 * Determine if two memory regions overlap.
1740 *
1741 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001742 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001743 * @return 1 if the two regions overlap
1744 */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001745static int regions_collide(const struct region *r1, const struct region *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001746{
Bill XIEfa5f9942017-09-12 11:22:29 +08001747 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001748 return 0;
1749
Nico Huber844eda02019-01-05 00:06:19 +01001750 /* r1 should be either completely below or completely above r2 */
1751 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001752}
1753
Jacob Garber595d9262019-06-27 17:33:10 -06001754static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001755 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001756{
1757 FILE *romlayout;
1758 char tempstr[256];
1759 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001760 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001761 int region_number;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001762 struct region current_regions[MAX_REGIONS];
1763 struct region new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001764 int new_extent = 0;
1765 char *new_image;
1766
1767 /* load current descriptor map and regions */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001768 struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001769 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001770 exit(EXIT_FAILURE);
1771
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001772 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001773 current_regions[i] = get_region(frba, i);
1774 new_regions[i] = get_region(frba, i);
1775 }
1776
1777 /* read new layout */
1778 romlayout = fopen(layout_fname, "r");
1779
1780 if (!romlayout) {
1781 perror("Could not read layout file.\n");
1782 exit(EXIT_FAILURE);
1783 }
1784
1785 while (!feof(romlayout)) {
1786 char *tstr1, *tstr2;
1787
Patrick Georgi802ad522014-08-09 17:12:23 +02001788 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001789 layout_region_name))
1790 continue;
1791
1792 region_number = region_num(layout_region_name);
1793 if (region_number < 0)
1794 continue;
1795
1796 tstr1 = strtok(tempstr, ":");
1797 tstr2 = strtok(NULL, ":");
1798 if (!tstr1 || !tstr2) {
1799 fprintf(stderr, "Could not parse layout file.\n");
1800 exit(EXIT_FAILURE);
1801 }
1802 new_regions[region_number].base = strtol(tstr1,
1803 (char **)NULL, 16);
1804 new_regions[region_number].limit = strtol(tstr2,
1805 (char **)NULL, 16);
1806 new_regions[region_number].size =
1807 new_regions[region_number].limit -
1808 new_regions[region_number].base + 1;
1809
1810 if (new_regions[region_number].size < 0)
1811 new_regions[region_number].size = 0;
1812 }
1813 fclose(romlayout);
1814
1815 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001816 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001817 if (new_regions[i].size == 0)
1818 continue;
1819
1820 if (new_regions[i].size < current_regions[i].size) {
1821 printf("DANGER: Region %s is shrinking.\n",
1822 region_name(i));
1823 printf(" The region will be truncated to fit.\n");
1824 printf(" This may result in an unusable image.\n");
1825 }
1826
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001827 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001828 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001829 fprintf(stderr, "Regions would overlap.\n");
1830 exit(EXIT_FAILURE);
1831 }
1832 }
1833
1834 /* detect if the image size should grow */
1835 if (new_extent < new_regions[i].limit)
1836 new_extent = new_regions[i].limit;
1837 }
1838
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001839 /* check if the image is actually a Flash Descriptor region */
1840 if (size == new_regions[0].size) {
1841 printf("The image is a single Flash Descriptor:\n");
1842 printf(" Only the descriptor will be modified\n");
1843 new_extent = size;
1844 } else {
1845 new_extent = next_pow2(new_extent - 1);
1846 if (new_extent != size) {
1847 printf("The image has changed in size.\n");
1848 printf("The old image is %d bytes.\n", size);
1849 printf("The new image is %d bytes.\n", new_extent);
1850 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001851 }
1852
1853 /* copy regions to a new image */
1854 new_image = malloc(new_extent);
1855 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001856 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001857 int copy_size = new_regions[i].size;
1858 int offset_current = 0, offset_new = 0;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001859 const struct region *current = &current_regions[i];
1860 const struct region *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001861
Bill XIEfa5f9942017-09-12 11:22:29 +08001862 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001863 continue;
1864
Bill XIEfa5f9942017-09-12 11:22:29 +08001865 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001866 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001867 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001868 if (i == REGION_BIOS)
1869 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001870 }
1871
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001872 if ((i == REGION_BIOS) && (new->size < current->size)) {
1873 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001874 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001875 }
1876
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001877 if (size < current->base + offset_current + copy_size) {
1878 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1879 region_name(i));
1880 continue;
1881 };
1882
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001883 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1884 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001885 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1886 offset_current, current->limit, current->size);
1887 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1888 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001889
Bill XIEfa5f9942017-09-12 11:22:29 +08001890 memcpy(new_image + new->base + offset_new,
1891 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001892 copy_size);
1893 }
1894
1895 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001896 frba = find_frba(new_image, new_extent);
1897 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001898 exit(EXIT_FAILURE);
1899
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001900 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001901 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001902 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001903
1904 write_image(filename, new_image, new_extent);
1905 free(new_image);
1906}
1907
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001908static void print_version(void)
1909{
1910 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1911 printf("Copyright (C) 2011 Google Inc.\n\n");
1912 printf
1913 ("This program is free software: you can redistribute it and/or modify\n"
1914 "it under the terms of the GNU General Public License as published by\n"
1915 "the Free Software Foundation, version 2 of the License.\n\n"
1916 "This program is distributed in the hope that it will be useful,\n"
1917 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1918 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001919 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001920}
1921
1922static void print_usage(const char *name)
1923{
1924 printf("usage: %s [-vhdix?] <filename>\n", name);
1925 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001926 " -d | --dump: dump intel firmware descriptor\n"
1927 " -f | --layout <filename> dump regions into a flashrom layout file\n"
Maximilian Brune347596a2023-03-05 20:55:32 +01001928 " -F | --fmap-layout <filename> dump IFD regions into a fmap layout template (.fmd) file\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001929 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1930 " -x | --extract: extract intel fd modules\n"
1931 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1932 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001933 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001934 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1935 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1936 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1937 " can only be used once per run:\n"
1938 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1939 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1940 " Dual Output Fast Read Support\n"
1941 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301942 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001943 " -u | --unlock Unlock firmware descriptor and ME region\n"
Reka Normanc64be922023-10-03 09:47:01 +11001944 " -g | --gpr0-disable Disable GPR0 (Global Protected Range) register\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001945 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1946 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001947 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301948 " adl - Alder Lake\n"
1949 " aplk - Apollo Lake\n"
1950 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08001951 " lbg - Lewisburg PCH\n"
Jeff Dalyabd4b962022-01-06 00:52:30 -05001952 " dnv - Denverton\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001953 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301954 " glk - Gemini Lake\n"
1955 " icl - Ice Lake\n"
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001956 " ifd2 - IFDv2 Platform\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301957 " jsl - Jasper Lake\n"
Subrata Banik9cd85d02023-05-24 23:18:49 +05301958 " mtl - Meteor Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301959 " sklkbl - Sky Lake/Kaby Lake\n"
1960 " tgl - Tiger Lake\n"
Patrick Rudolph16598742022-10-21 15:13:43 +02001961 " wbg - Wellsburg\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001962 " -S | --setpchstrap Write a PCH strap\n"
1963 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001964 " -v | --version: print the version\n"
1965 " -h | --help: print this help\n\n"
Jeff Daly3623eca2022-01-05 23:51:40 -05001966 "<region> is one of Descriptor, BIOS, ME, GbE, Platform Data, Secondary BIOS, "
1967 "Device Exp1, EC, Device Exp2, IE, 10GbE_0, 10GbE_1, PTT\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001968 "\n");
1969}
1970
1971int main(int argc, char *argv[])
1972{
1973 int opt, option_index = 0;
1974 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001975 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001976 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Maximilian Brune347596a2023-03-05 20:55:32 +01001977 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0, mode_fmap_template = 0;
Reka Normanc64be922023-10-03 09:47:01 +11001978 int mode_gpr0_disable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001979 char *region_type_string = NULL, *region_fname = NULL;
1980 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001981 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001982 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001983 unsigned int value = 0;
1984 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001985 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001986 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1987
Bill XIEfa5f9942017-09-12 11:22:29 +08001988 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001989 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001990 {"layout", 1, NULL, 'f'},
Maximilian Brune347596a2023-03-05 20:55:32 +01001991 {"fmap-template", 1, NULL, 'F'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001992 {"extract", 0, NULL, 'x'},
1993 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001994 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001995 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001996 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001997 {"density", 1, NULL, 'D'},
1998 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001999 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002000 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002001 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05302002 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002003 {"unlock", 0, NULL, 'u'},
Reka Normanc64be922023-10-03 09:47:01 +11002004 {"gpr0-disable", 0, NULL, 'g'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002005 {"version", 0, NULL, 'v'},
2006 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07002007 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06002008 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002009 {"setpchstrap", 1, NULL, 'S'},
2010 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002011 {0, 0, 0, 0}
2012 };
2013
Reka Normanc64be922023-10-03 09:47:01 +11002014 while ((opt = getopt_long(argc, argv, "S:V:df:F:D:C:M:xi:n:O:s:p:elrugvth?",
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002015 long_options, &option_index)) != EOF) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002016 switch (opt) {
2017 case 'd':
2018 mode_dump = 1;
2019 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002020 case 'S':
2021 mode_setstrap = 1;
2022 pchstrap = strtoul(optarg, NULL, 0);
2023 break;
2024 case 'V':
2025 value = strtoul(optarg, NULL, 0);
2026 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05002027 case 'f':
2028 mode_layout = 1;
2029 layout_fname = strdup(optarg);
2030 if (!layout_fname) {
2031 fprintf(stderr, "No layout file specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002032 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Chris Douglass03ce0142014-02-26 13:30:13 -05002033 exit(EXIT_FAILURE);
2034 }
2035 break;
Maximilian Brune347596a2023-03-05 20:55:32 +01002036 case 'F':
2037 mode_fmap_template = 1;
2038 layout_fname = strdup(optarg);
2039 if (!layout_fname) {
2040 fprintf(stderr, "No layout file specified\n");
2041 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
2042 exit(EXIT_FAILURE);
2043 }
2044 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002045 case 'x':
2046 mode_extract = 1;
2047 break;
2048 case 'i':
2049 // separate type and file name
2050 region_type_string = strdup(optarg);
2051 region_fname = strchr(region_type_string, ':');
2052 if (!region_fname) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002053 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002054 exit(EXIT_FAILURE);
2055 }
2056 region_fname[0] = '\0';
2057 region_fname++;
2058 // Descriptor, BIOS, ME, GbE, Platform
2059 // valid type?
2060 if (!strcasecmp("Descriptor", region_type_string))
2061 region_type = 0;
2062 else if (!strcasecmp("BIOS", region_type_string))
2063 region_type = 1;
2064 else if (!strcasecmp("ME", region_type_string))
2065 region_type = 2;
2066 else if (!strcasecmp("GbE", region_type_string))
2067 region_type = 3;
Jeff Daly3623eca2022-01-05 23:51:40 -05002068 else if (!strcasecmp("Platform Data", region_type_string))
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002069 region_type = 4;
Jeff Daly3623eca2022-01-05 23:51:40 -05002070 else if (!strcasecmp("Device Exp1", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07002071 region_type = 5;
Jeff Daly3623eca2022-01-05 23:51:40 -05002072 else if (!strcasecmp("Secondary BIOS", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07002073 region_type = 6;
Jeff Daly3623eca2022-01-05 23:51:40 -05002074 else if (!strcasecmp("Reserved", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07002075 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002076 else if (!strcasecmp("EC", region_type_string))
2077 region_type = 8;
Jeff Daly3623eca2022-01-05 23:51:40 -05002078 else if (!strcasecmp("Device Exp2", region_type_string))
2079 region_type = 9;
2080 else if (!strcasecmp("IE", region_type_string))
2081 region_type = 10;
2082 else if (!strcasecmp("10GbE_0", region_type_string))
2083 region_type = 11;
2084 else if (!strcasecmp("10GbE_1", region_type_string))
2085 region_type = 12;
2086 else if (!strcasecmp("PTT", region_type_string))
2087 region_type = 15;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002088 if (region_type == -1) {
2089 fprintf(stderr, "No such region type: '%s'\n\n",
2090 region_type_string);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002091 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002092 exit(EXIT_FAILURE);
2093 }
2094 mode_inject = 1;
2095 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002096 case 'n':
2097 mode_newlayout = 1;
2098 layout_fname = strdup(optarg);
2099 if (!layout_fname) {
2100 fprintf(stderr, "No layout file specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002101 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002102 exit(EXIT_FAILURE);
2103 }
2104 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002105 case 'O':
2106 new_filename = strdup(optarg);
2107 if (!new_filename) {
2108 fprintf(stderr, "No output filename specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002109 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002110 exit(EXIT_FAILURE);
2111 }
2112 break;
Jan Tatjefa317512016-03-11 00:52:07 +01002113 case 'D':
2114 mode_density = 1;
2115 new_density = strtoul(optarg, NULL, 0);
2116 switch (new_density) {
2117 case 512:
2118 new_density = COMPONENT_DENSITY_512KB;
2119 break;
2120 case 1:
2121 new_density = COMPONENT_DENSITY_1MB;
2122 break;
2123 case 2:
2124 new_density = COMPONENT_DENSITY_2MB;
2125 break;
2126 case 4:
2127 new_density = COMPONENT_DENSITY_4MB;
2128 break;
2129 case 8:
2130 new_density = COMPONENT_DENSITY_8MB;
2131 break;
2132 case 16:
2133 new_density = COMPONENT_DENSITY_16MB;
2134 break;
2135 case 32:
2136 new_density = COMPONENT_DENSITY_32MB;
2137 break;
2138 case 64:
2139 new_density = COMPONENT_DENSITY_64MB;
2140 break;
2141 case 0:
2142 new_density = COMPONENT_DENSITY_UNUSED;
2143 break;
2144 default:
2145 printf("error: Unknown density\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002146 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Jan Tatjefa317512016-03-11 00:52:07 +01002147 exit(EXIT_FAILURE);
2148 }
2149 break;
2150 case 'C':
2151 selected_chip = strtol(optarg, NULL, 0);
2152 if (selected_chip > 2) {
2153 fprintf(stderr, "error: Invalid chip selection\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002154 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Jan Tatjefa317512016-03-11 00:52:07 +01002155 exit(EXIT_FAILURE);
2156 }
2157 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08002158 case 'M':
2159 mode_altmedisable = 1;
2160 altmedisable = strtol(optarg, NULL, 0);
2161 if (altmedisable > 1) {
2162 fprintf(stderr, "error: Illegal value\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002163 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Bill XIEb3e15a22017-09-07 18:34:50 +08002164 exit(EXIT_FAILURE);
2165 }
2166 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002167 case 's':
2168 // Parse the requested SPI frequency
2169 inputfreq = strtol(optarg, NULL, 0);
2170 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002171 case 17:
2172 spifreq = SPI_FREQUENCY_17MHZ;
2173 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002174 case 20:
2175 spifreq = SPI_FREQUENCY_20MHZ;
2176 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002177 case 30:
2178 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
2179 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002180 case 33:
2181 spifreq = SPI_FREQUENCY_33MHZ;
2182 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002183 case 48:
2184 spifreq = SPI_FREQUENCY_48MHZ;
2185 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002186 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002187 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002188 break;
2189 default:
2190 fprintf(stderr, "Invalid SPI Frequency: %d\n",
2191 inputfreq);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002192 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002193 exit(EXIT_FAILURE);
2194 }
2195 mode_spifreq = 1;
2196 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002197 case 'e':
2198 mode_em100 = 1;
2199 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002200 case 'l':
2201 mode_locked = 1;
2202 if (mode_unlocked == 1) {
2203 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
2204 exit(EXIT_FAILURE);
2205 }
2206 break;
Usha P412679d2020-10-15 11:25:08 +05302207 case 'r':
2208 mode_read = 1;
2209 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002210 case 'u':
2211 mode_unlocked = 1;
2212 if (mode_locked == 1) {
2213 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
2214 exit(EXIT_FAILURE);
2215 }
2216 break;
Reka Normanc64be922023-10-03 09:47:01 +11002217 case 'g':
2218 mode_gpr0_disable = 1;
2219 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002220 case 'p':
2221 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002222 platform = PLATFORM_APL;
2223 } else if (!strcmp(optarg, "cnl")) {
2224 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08002225 } else if (!strcmp(optarg, "lbg")) {
2226 platform = PLATFORM_LBG;
Jeff Dalyabd4b962022-01-06 00:52:30 -05002227 } else if (!strcmp(optarg, "dnv")) {
2228 platform = PLATFORM_DNV;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002229 } else if (!strcmp(optarg, "ehl")) {
2230 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07002231 } else if (!strcmp(optarg, "glk")) {
2232 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05302233 } else if (!strcmp(optarg, "icl")) {
2234 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05302235 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07002236 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07002237 } else if (!strcmp(optarg, "sklkbl")) {
2238 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07002239 } else if (!strcmp(optarg, "tgl")) {
2240 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05302241 } else if (!strcmp(optarg, "adl")) {
2242 platform = PLATFORM_ADL;
Wonkyu Kim3922aa52022-02-02 15:19:05 -08002243 } else if (!strcmp(optarg, "ifd2")) {
2244 platform = PLATFORM_IFD2;
Subrata Banikca82e612022-01-20 18:51:21 +05302245 } else if (!strcmp(optarg, "mtl")) {
2246 platform = PLATFORM_MTL;
Patrick Rudolph16598742022-10-21 15:13:43 +02002247 } else if (!strcmp(optarg, "wbg")) {
2248 platform = PLATFORM_WBG;
Andrey Petrov96ecb772016-10-31 19:31:54 -07002249 } else {
2250 fprintf(stderr, "Unknown platform: %s\n", optarg);
2251 exit(EXIT_FAILURE);
2252 }
2253 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06002254 case 't':
2255 mode_validate = 1;
2256 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002257 case 'v':
2258 print_version();
2259 exit(EXIT_SUCCESS);
2260 break;
2261 case 'h':
2262 case '?':
2263 default:
2264 print_usage(argv[0]);
2265 exit(EXIT_SUCCESS);
2266 break;
2267 }
2268 }
2269
Maximilian Brune347596a2023-03-05 20:55:32 +01002270 if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject +
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002271 mode_setstrap + mode_newlayout + (mode_spifreq | mode_em100 |
Reka Normanc64be922023-10-03 09:47:01 +11002272 mode_unlocked | mode_locked) + mode_altmedisable + mode_validate +
2273 mode_gpr0_disable) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002274 fprintf(stderr, "You may not specify more than one mode.\n\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002275 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002276 exit(EXIT_FAILURE);
2277 }
2278
Maximilian Brune347596a2023-03-05 20:55:32 +01002279 if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject +
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002280 mode_setstrap + mode_newlayout + mode_spifreq + mode_em100 +
Reka Normanc64be922023-10-03 09:47:01 +11002281 mode_locked + mode_unlocked + mode_density + mode_altmedisable +
2282 mode_validate + mode_gpr0_disable) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002283 fprintf(stderr, "You need to specify a mode.\n\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002284 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002285 exit(EXIT_FAILURE);
2286 }
2287
2288 if (optind + 1 != argc) {
2289 fprintf(stderr, "You need to specify a file.\n\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002290 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002291 exit(EXIT_FAILURE);
2292 }
2293
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002294 if (platform == -1)
2295 fprintf(stderr, "Warning: No platform specified. Output may be incomplete\n");
2296
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002297 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06002298 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002299 if (bios_fd == -1) {
2300 perror("Could not open file");
2301 exit(EXIT_FAILURE);
2302 }
2303 struct stat buf;
2304 if (fstat(bios_fd, &buf) == -1) {
2305 perror("Could not stat file");
2306 exit(EXIT_FAILURE);
2307 }
2308 int size = buf.st_size;
2309
2310 printf("File %s is %d bytes\n", filename, size);
2311
2312 char *image = malloc(size);
2313 if (!image) {
2314 printf("Out of memory.\n");
2315 exit(EXIT_FAILURE);
2316 }
2317
2318 if (read(bios_fd, image, size) != size) {
2319 perror("Could not read file");
2320 exit(EXIT_FAILURE);
2321 }
2322
2323 close(bios_fd);
2324
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002325 // generate new filename
2326 if (new_filename == NULL) {
2327 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
2328 if (!new_filename) {
2329 printf("Out of memory.\n");
2330 exit(EXIT_FAILURE);
2331 }
2332 // - 5: leave room for ".new\0"
2333 strcpy(new_filename, filename);
2334 strcat(new_filename, ".new");
2335 }
2336
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002337 check_ifd_version(image, size);
2338
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002339 if (mode_dump)
2340 dump_fd(image, size);
2341
Chris Douglass03ce0142014-02-26 13:30:13 -05002342 if (mode_layout)
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002343 dump_flashrom_layout(image, size, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -05002344
Maximilian Brune347596a2023-03-05 20:55:32 +01002345 if (mode_fmap_template)
2346 create_fmap_template(image, size, layout_fname);
2347
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002348 if (mode_extract)
2349 write_regions(image, size);
2350
Mathew Kingc7ddc992019-08-08 14:59:25 -06002351 if (mode_validate)
2352 validate_layout(image, size);
2353
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002354 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002355 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002356 region_fname);
2357
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002358 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002359 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002360
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002361 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002362 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002363
Jan Tatjefa317512016-03-11 00:52:07 +01002364 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002365 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002366
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002367 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002368 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002369
Alexander Couzensd12ea112016-09-10 13:33:05 +02002370 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002371 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002372
Usha P412679d2020-10-15 11:25:08 +05302373 if (mode_read)
2374 enable_cpu_read_me(new_filename, image, size);
2375
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002376 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002377 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002378
Reka Normanc64be922023-10-03 09:47:01 +11002379 if (mode_gpr0_disable)
2380 disable_gpr0(new_filename, image, size);
2381
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002382 if (mode_setstrap) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002383 struct fpsba *fpsba = find_fpsba(image, size);
2384 const struct fdbar *fdb = find_fd(image, size);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002385 set_pchstrap(fpsba, fdb, pchstrap, value);
2386 write_image(new_filename, image, size);
2387 }
2388
Bill XIEb3e15a22017-09-07 18:34:50 +08002389 if (mode_altmedisable) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002390 struct fpsba *fpsba = find_fpsba(image, size);
2391 struct fmsba *fmsba = find_fmsba(image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002392 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002393 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002394 }
2395
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002396 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002397 free(image);
2398
2399 return 0;
2400}