blob: c2dde3c28992e4c78d7d43e836e0568894e37d74 [file] [log] [blame]
Patrick Georgiea063cb2020-05-08 19:28:13 +02001/* ifdtool - dump Intel Firmware Descriptor information */
Patrick Georgi7333a112020-05-08 20:48:04 +02002/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07003
4#include <unistd.h>
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8#include <getopt.h>
9#include <fcntl.h>
10#include <sys/types.h>
11#include <sys/stat.h>
Bill XIE4651d452017-09-12 11:54:48 +080012#include <commonlib/helpers.h>
Mathew Kingc7ddc992019-08-08 14:59:25 -060013#include <fmap.h>
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070014#include "ifdtool.h"
15
Scott Duplichanf2c98372014-12-12 21:03:06 -060016#ifndef O_BINARY
17#define O_BINARY 0
18#endif
19
Bill XIE612ec0e2017-08-30 16:10:27 +080020/**
21 * PTR_IN_RANGE - examine whether a pointer falls in [base, base + limit)
22 * @param ptr: the non-void* pointer to a single arbitrary-sized object.
23 * @param base: base address represented with char* type.
24 * @param limit: upper limit of the legal address.
25 *
26 */
27#define PTR_IN_RANGE(ptr, base, limit) \
28 ((const char *)(ptr) >= (base) && \
29 (const char *)&(ptr)[1] <= (base) + (limit))
30
Jeff Dalyabd4b962022-01-06 00:52:30 -050031/**
32 * PLATFORM_HAS_GBE_REGION - some platforms do not support the PCH GbE LAN region
33 */
34#define PLATFORM_HAS_GBE_REGION (platform != PLATFORM_DNV)
35
36/*
37 * PLATFORM_HAS_EC_REGION - some platforms do not support the EC region
38 */
39#define PLATFORM_HAS_EC_REGION (ifd_version >= IFD_VERSION_2 && platform != PLATFORM_DNV)
40
41/*
42 * PLATFORM_HAS_10GBE_X_REGION - some platforms have 1 or more 10GbE LAN regions
43 */
44#define PLATFORM_HAS_10GBE_0_REGION (platform == PLATFORM_DNV)
45#define PLATFORM_HAS_10GBE_1_REGION (platform == PLATFORM_DNV)
46
Maximilian Bruneab0e6802023-03-05 04:34:40 +010047static int max_regions_from_fdbar(const struct fdbar *fdb);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +020048
Duncan Laurie1f7fd722015-06-22 11:14:48 -070049static int ifd_version;
Bill XIEb3e15a22017-09-07 18:34:50 +080050static int chipset;
Bill XIEfa5f9942017-09-12 11:22:29 +080051static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010052static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070053static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050054
Duncan Laurie1f7fd722015-06-22 11:14:48 -070055static const struct region_name region_names[MAX_REGIONS] = {
Mathew Kingc7ddc992019-08-08 14:59:25 -060056 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin", "SI_DESC" },
57 { "BIOS", "bios", "flashregion_1_bios.bin", "SI_BIOS" },
58 { "Intel ME", "me", "flashregion_2_intel_me.bin", "SI_ME" },
59 { "GbE", "gbe", "flashregion_3_gbe.bin", "SI_GBE" },
60 { "Platform Data", "pd", "flashregion_4_platform_data.bin", "SI_PDR" },
Jeff Daly3623eca2022-01-05 23:51:40 -050061 { "Device Exp1", "devexp", "flashregion_5_device_exp.bin", "SI_DEVICEEXT" },
62 { "Secondary BIOS", "bios2", "flashregion_6_bios2.bin", "SI_BIOS2" },
63 { "Reserved", "res7", "flashregion_7_reserved.bin", NULL },
Mathew Kingc7ddc992019-08-08 14:59:25 -060064 { "EC", "ec", "flashregion_8_ec.bin", "SI_EC" },
Jeff Daly3623eca2022-01-05 23:51:40 -050065 { "Device Exp2", "devexp2", "flashregion_9_device_exp.bin", "SI_DEVICEEXT2" },
66 { "IE", "ie", "flashregion_10_ie.bin", "SI_IE" },
67 { "10GbE_0", "10gbe_0", "flashregion_11_10gbe0.bin", "SI_10GBE0" },
68 { "10GbE_1", "10gbe_1", "flashregion_12_10gbe1.bin", "SI_10GBE1" },
69 { "Reserved", "res13", "flashregion_13_reserved.bin", NULL },
70 { "Reserved", "res14", "flashregion_14_reserved.bin", NULL },
71 { "PTT", "ptt", "flashregion_15_ptt.bin", "SI_PTT" },
Chris Douglass03ce0142014-02-26 13:30:13 -050072};
73
Bill XIEb3e15a22017-09-07 18:34:50 +080074/* port from flashrom */
75static const char *const ich_chipset_names[] = {
76 "Unknown ICH",
Bill XIEb3e15a22017-09-07 18:34:50 +080077 "ICH8",
78 "ICH9",
79 "ICH10",
Subrata Banik89db2252020-08-26 14:49:17 +053080 "Unknown PCH",
Bill XIEb3e15a22017-09-07 18:34:50 +080081 "5 series Ibex Peak",
82 "6 series Cougar Point",
83 "7 series Panther Point",
84 "8 series Lynx Point",
85 "Baytrail",
86 "8 series Lynx Point LP",
87 "8 series Wellsburg",
88 "9 series Wildcat Point",
89 "9 series Wildcat Point LP",
Subrata Banik8c082e52021-06-10 23:02:29 +053090 "Apollo Lake: N3xxx, J3xxx",
Subrata Banik89db2252020-08-26 14:49:17 +053091 "Gemini Lake: N5xxx, J5xxx, N4xxx, J4xxx",
Subrata Banik8c082e52021-06-10 23:02:29 +053092 "Jasper Lake: N6xxx, N51xx, N45xx",
93 "Elkhart Lake: x6000 series Atom",
Subrata Banik89db2252020-08-26 14:49:17 +053094 "100/200 series Sunrise Point",
Subrata Banik8c082e52021-06-10 23:02:29 +053095 "300 series Cannon Point",
96 "400 series Ice Point",
Subrata Banika5f47812020-09-29 11:43:01 +053097 "500 series Tiger Point/ 600 series Alder Point",
Bill XIEb3e15a22017-09-07 18:34:50 +080098 "C620 series Lewisburg",
Patrick Rudolph19209002022-10-22 10:34:05 +020099 "Denverton: C39xx",
Bill XIEb3e15a22017-09-07 18:34:50 +0800100 NULL
101};
102
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100103static struct fdbar *find_fd(char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700104{
105 int i, found = 0;
106
107 /* Scan for FD signature */
108 for (i = 0; i < (size - 4); i += 4) {
109 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
110 found = 1;
111 break; // signature found.
112 }
113 }
114
115 if (!found) {
116 printf("No Flash Descriptor found in this image\n");
117 return NULL;
118 }
119
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100120 struct fdbar *fdb = (struct fdbar *) (image + i);
Bill XIE612ec0e2017-08-30 16:10:27 +0800121 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
122}
123
Stefan Tauner0d226142018-08-05 18:56:53 +0200124static char *find_flumap(char *image, int size)
125{
126 /* The upper map is located in the word before the 256B-long OEM section
127 * at the end of the 4kB-long flash descriptor. In the official
128 * documentation this is defined as FDBAR + 0xEFC. However, starting
129 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
130 * has moved 16 bytes back to offset 0x10 of the image. Although
131 * official documentation still maintains the offset relative to FDBAR
132 * this is wrong and a simple fixed offset from the start of the image
133 * works.
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100134 */
Stefan Tauner0d226142018-08-05 18:56:53 +0200135 char *flumap = image + 4096 - 256 - 4;
136 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
137}
138
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100139static struct fcba *find_fcba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800140{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100141 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800142 if (!fdb)
143 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100144 struct fcba *fcba = (struct fcba *) (image + ((fdb->flmap0 & 0xff) << 4));
Bill XIE612ec0e2017-08-30 16:10:27 +0800145 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
146
147}
148
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100149static struct fmba *find_fmba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800150{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100151 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800152 if (!fdb)
153 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100154 struct fmba *fmba = (struct fmba *) (image + ((fdb->flmap1 & 0xff) << 4));
Bill XIE612ec0e2017-08-30 16:10:27 +0800155 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
156}
157
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100158static struct frba *find_frba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800159{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100160 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800161 if (!fdb)
162 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100163 struct frba *frba =
164 (struct frba *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
Bill XIE612ec0e2017-08-30 16:10:27 +0800165 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
166}
167
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100168static struct fpsba *find_fpsba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800169{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100170 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800171 if (!fdb)
172 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100173 struct fpsba *fpsba =
174 (struct fpsba *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200175
176 int SSL = ((fdb->flmap1 >> 24) & 0xff) * sizeof(uint32_t);
177 if ((((char *)fpsba) + SSL) >= (image + size))
178 return NULL;
179 return fpsba;
Bill XIE612ec0e2017-08-30 16:10:27 +0800180}
181
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100182static struct fmsba *find_fmsba(char *image, int size)
Bill XIE612ec0e2017-08-30 16:10:27 +0800183{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100184 struct fdbar *fdb = find_fd(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800185 if (!fdb)
186 return NULL;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100187 struct fmsba *fmsba = (struct fmsba *) (image + ((fdb->flmap2 & 0xff) << 4));
Bill XIE612ec0e2017-08-30 16:10:27 +0800188 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700189}
190
Bill XIEb3e15a22017-09-07 18:34:50 +0800191/* port from flashrom */
Subrata Banik8c082e52021-06-10 23:02:29 +0530192static enum ich_chipset ifd1_guess_chipset(char *image, int size)
Bill XIEb3e15a22017-09-07 18:34:50 +0800193{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100194 const struct fdbar *fdb = find_fd(image, size);
Subrata Banik8c082e52021-06-10 23:02:29 +0530195 if (!fdb)
196 exit(EXIT_FAILURE);
Bill XIEb3e15a22017-09-07 18:34:50 +0800197 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
198 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
199 uint32_t isl = (fdb->flmap1 >> 24);
Subrata Banik89db2252020-08-26 14:49:17 +0530200
201 /* Rest for IFD1 chipset type */
Bill XIEb3e15a22017-09-07 18:34:50 +0800202 if (iccriba == 0x00) {
203 if (msl == 0 && isl <= 2)
204 return CHIPSET_ICH8;
205 else if (isl <= 2)
206 return CHIPSET_ICH9;
207 else if (isl <= 10)
208 return CHIPSET_ICH10;
209 else if (isl <= 16)
210 return CHIPSET_5_SERIES_IBEX_PEAK;
211 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
212 return CHIPSET_5_SERIES_IBEX_PEAK;
213 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
214 if (msl == 0 && isl <= 17)
215 return CHIPSET_BAYTRAIL;
216 else if (msl <= 1 && isl <= 18)
217 return CHIPSET_6_SERIES_COUGAR_POINT;
218 else if (msl <= 1 && isl <= 21)
219 return CHIPSET_8_SERIES_LYNX_POINT;
220 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
221 return CHIPSET_9_SERIES_WILDCAT_POINT;
Bill XIEb3e15a22017-09-07 18:34:50 +0800222 }
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200223 return CHIPSET_PCH_UNKNOWN;
Bill XIEb3e15a22017-09-07 18:34:50 +0800224}
225
Subrata Banik8c082e52021-06-10 23:02:29 +0530226static enum ich_chipset ifd2_platform_to_chipset(const int pindex)
227{
228 switch (pindex) {
Subrata Banik6da003c2021-07-14 13:52:03 +0530229 case PLATFORM_APL:
230 return CHIPSET_N_J_SERIES_APOLLO_LAKE;
Subrata Banik8c082e52021-06-10 23:02:29 +0530231 case PLATFORM_GLK:
232 return CHIPSET_N_J_SERIES_GEMINI_LAKE;
233 case PLATFORM_JSL:
234 return CHIPSET_N_SERIES_JASPER_LAKE;
235 case PLATFORM_EHL:
236 return CHIPSET_x6000_SERIES_ELKHART_LAKE;
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200237 case PLATFORM_SKLKBL:
238 return CHIPSET_100_200_SERIES_SUNRISE_POINT;
Subrata Banik8c082e52021-06-10 23:02:29 +0530239 case PLATFORM_CNL:
240 return CHIPSET_300_SERIES_CANNON_POINT;
241 case PLATFORM_TGL:
242 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800243 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +0530244 case PLATFORM_MTL:
Subrata Banik8c082e52021-06-10 23:02:29 +0530245 return CHIPSET_500_600_SERIES_TIGER_ALDER_POINT;
246 case PLATFORM_ICL:
247 return CHIPSET_400_SERIES_ICE_POINT;
Johnny Line273a022021-06-22 11:26:46 +0800248 case PLATFORM_LBG:
249 return CHIPSET_C620_SERIES_LEWISBURG;
Jeff Dalyabd4b962022-01-06 00:52:30 -0500250 case PLATFORM_DNV:
251 return CHIPSET_DENVERTON;
Patrick Rudolph16598742022-10-21 15:13:43 +0200252 case PLATFORM_WBG:
253 return CHIPSET_8_SERIES_WELLSBURG;
Subrata Banik8c082e52021-06-10 23:02:29 +0530254 default:
255 return CHIPSET_PCH_UNKNOWN;
256 }
257}
258
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700259/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700260 * Some newer platforms have re-defined the FCBA field that was used to
261 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
262 * have the required FCBA field, but are IFD v2 and return true if current
263 * platform is one of them.
264 */
265static int is_platform_ifd_2(void)
266{
267 static const int ifd_2_platforms[] = {
Subrata Banik6da003c2021-07-14 13:52:03 +0530268 PLATFORM_APL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700269 PLATFORM_GLK,
270 PLATFORM_CNL,
Johnny Line273a022021-06-22 11:26:46 +0800271 PLATFORM_LBG,
Jeff Dalyabd4b962022-01-06 00:52:30 -0500272 PLATFORM_DNV,
Aamir Bohra1018be22018-06-29 15:08:50 +0530273 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700274 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530275 PLATFORM_JSL,
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -0700276 PLATFORM_EHL,
Subrata Banik46f80732020-03-14 15:01:42 +0530277 PLATFORM_ADL,
Jan Tatjeb7eec4a2021-07-05 08:03:07 +0200278 PLATFORM_SKLKBL,
Wonkyu Kim3922aa52022-02-02 15:19:05 -0800279 PLATFORM_IFD2,
Subrata Banikca82e612022-01-20 18:51:21 +0530280 PLATFORM_MTL,
Patrick Rudolph16598742022-10-21 15:13:43 +0200281 PLATFORM_WBG,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700282 };
283 unsigned int i;
284
285 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
286 if (platform == ifd_2_platforms[i])
287 return 1;
288 }
289
290 return 0;
291}
292
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700293static void check_ifd_version(char *image, int size)
294{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100295 const struct fdbar *fdb = find_fd(image, size);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200296
Subrata Banik8c082e52021-06-10 23:02:29 +0530297 if (is_platform_ifd_2()) {
Subrata Banik8c082e52021-06-10 23:02:29 +0530298 chipset = ifd2_platform_to_chipset(platform);
Patrick Rudolph16598742022-10-21 15:13:43 +0200299 if (chipset == CHIPSET_8_SERIES_WELLSBURG)
300 ifd_version = IFD_VERSION_1_5;
301 else
302 ifd_version = IFD_VERSION_2;
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200303 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS);
Subrata Banik8c082e52021-06-10 23:02:29 +0530304 } else {
305 ifd_version = IFD_VERSION_1;
306 chipset = ifd1_guess_chipset(image, size);
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200307 max_regions = MIN(max_regions_from_fdbar(fdb), MAX_REGIONS_OLD);
Subrata Banik8c082e52021-06-10 23:02:29 +0530308 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700309}
310
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100311static struct region get_region(const struct frba *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700312{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500313 int base_mask;
314 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700315 uint32_t flreg;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100316 struct region region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500317
318 if (ifd_version >= IFD_VERSION_2)
319 base_mask = 0x7fff;
320 else
321 base_mask = 0xfff;
322
323 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700324
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400325 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800326 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700327 exit (EXIT_FAILURE);
328 }
329
Bill XIE4651d452017-09-12 11:54:48 +0800330 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700331 region.base = (flreg & base_mask) << 12;
332 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700333 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500334
Chris Douglass03ce0142014-02-26 13:30:13 -0500335 if (region.size < 0)
336 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700337
338 return region;
339}
340
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100341static void set_region(struct frba *frba, unsigned int region_type,
342 const struct region *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500343{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400344 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800345 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500346 exit (EXIT_FAILURE);
347 }
Bill XIE4651d452017-09-12 11:54:48 +0800348
349 frba->flreg[region_type] =
350 (((region->limit >> 12) & 0x7fff) << 16) |
351 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500352}
353
Bill XIEfa5f9942017-09-12 11:22:29 +0800354static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700355{
Bill XIEfa5f9942017-09-12 11:22:29 +0800356 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700357 fprintf(stderr, "Invalid region type.\n");
358 exit (EXIT_FAILURE);
359 }
360
Chris Douglass03ce0142014-02-26 13:30:13 -0500361 return region_names[region_type].pretty;
362}
363
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500364static int region_num(const char *name)
365{
Bill XIEfa5f9942017-09-12 11:22:29 +0800366 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500367
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200368 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500369 if (strcasecmp(name, region_names[i].pretty) == 0)
370 return i;
371 if (strcasecmp(name, region_names[i].terse) == 0)
372 return i;
373 }
374
375 return -1;
376}
377
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100378static void dump_region(unsigned int num, const struct frba *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700379{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100380 struct region region = get_region(frba, num);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700381 printf(" Flash Region %d (%s): %08x - %08x %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100382 num, region_name(num), region.base, region.limit,
383 region.size < 1 ? "(unused)" : "");
Chris Douglass03ce0142014-02-26 13:30:13 -0500384}
385
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200386static int sort_compare(const void *a, const void *b)
387{
388 return *(size_t *)a - *(size_t *)b;
389}
390
391/*
392 * IFDv1 always has 8 regions, while IFDv2 always has 16 regions.
393 *
394 * It's platform specific which regions are used or are reserved.
395 * The 'SPI programming guide' as the name says is a guide only,
396 * not a specification what the hardware actually does.
397 * The best to do is not to rely on the guide, but detect how many
398 * regions are present in the IFD and expose them all.
399 *
400 * Very early IFDv2 chipsets, sometimes unofficially referred to as
401 * IFDv1.5 platforms, only have 8 regions. To not corrupt the IFD when
402 * operating on an IFDv1.5 detect how much space is actually present
403 * in the IFD.
404 */
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100405static int max_regions_from_fdbar(const struct fdbar *fdb)
Patrick Rudolph98ecaa42022-10-24 15:06:15 +0200406{
407 const size_t fcba = (fdb->flmap0 & 0xff) << 4;
408 const size_t fmba = (fdb->flmap1 & 0xff) << 4;
409 const size_t frba = ((fdb->flmap0 >> 16) & 0xff) << 4;
410 const size_t fpsba = ((fdb->flmap1 >> 16) & 0xff) << 4;
411 const size_t flumap = 4096 - 256 - 4;
412 size_t sorted[5] = {fcba, fmba, frba, fpsba, flumap};
413
414 qsort(sorted, ARRAY_SIZE(sorted), sizeof(size_t), sort_compare);
415
416 for (size_t i = 0; i < 4; i++) {
417 /*
418 * Find FRBA in the sorted array and determine the size of the
419 * region by the start of the next region. Every region requires
420 * 4 bytes of space.
421 */
422 if (sorted[i] == frba)
423 return MIN((sorted[i+1] - sorted[i])/4, MAX_REGIONS);
424 }
425 /* Never reaches this point */
426 return 0;
427}
428
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100429static void dump_frba(const struct frba *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700430{
Bill XIE4651d452017-09-12 11:54:48 +0800431 unsigned int i;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100432 struct region region;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700433 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800434 for (i = 0; i < max_regions; i++) {
Subrata Banikd52df3cd2020-08-26 14:02:01 +0530435 region = get_region(frba, i);
436 /* Skip unused & reserved Flash Region */
437 if (region.size < 1 && !strcmp(region_name(i), "Reserved"))
438 continue;
439
Bill XIE4651d452017-09-12 11:54:48 +0800440 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
441 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700442 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700443}
444
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100445static void dump_flashrom_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500446{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100447 const struct frba *frba = find_frba(image, size);
448 if (!frba)
449 exit(EXIT_FAILURE);
Chris Douglass03ce0142014-02-26 13:30:13 -0500450
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100451 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
Chris Douglass03ce0142014-02-26 13:30:13 -0500452 if (layout_fd == -1) {
453 perror("Could not open file");
454 exit(EXIT_FAILURE);
455 }
456
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100457 for (unsigned int i = 0; i < max_regions; i++) {
458 struct region region = get_region(frba, i);
Alexander Couzenseff596b2016-10-08 00:53:09 +0200459 /* is region invalid? */
460 if (region.size < 1)
461 continue;
462
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100463 char buf[LAYOUT_LINELEN];
464 snprintf(buf, LAYOUT_LINELEN, "%08x:%08x %s\n", region.base, region.limit, region_names[i].terse);
Chris Douglass03ce0142014-02-26 13:30:13 -0500465 if (write(layout_fd, buf, strlen(buf)) < 0) {
466 perror("Could not write to file");
467 exit(EXIT_FAILURE);
468 }
469 }
470 close(layout_fd);
471 printf("Wrote layout to %s\n", layout_fname);
472}
473
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530474static void _decode_spi_frequency(unsigned int freq)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700475{
476 switch (freq) {
477 case SPI_FREQUENCY_20MHZ:
478 printf("20MHz");
479 break;
480 case SPI_FREQUENCY_33MHZ:
481 printf("33MHz");
482 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700483 case SPI_FREQUENCY_48MHZ:
484 printf("48MHz");
485 break;
486 case SPI_FREQUENCY_50MHZ_30MHZ:
487 switch (ifd_version) {
488 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +0200489 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700490 printf("50MHz");
491 break;
492 case IFD_VERSION_2:
493 printf("30MHz");
494 break;
495 }
496 break;
497 case SPI_FREQUENCY_17MHZ:
498 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700499 break;
500 default:
501 printf("unknown<%x>MHz", freq);
502 }
503}
504
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530505static void _decode_spi_frequency_500_series(unsigned int freq)
506{
507 switch (freq) {
508 case SPI_FREQUENCY_100MHZ:
509 printf("100MHz");
510 break;
511 case SPI_FREQUENCY_50MHZ:
512 printf("50MHz");
513 break;
514 case SPI_FREQUENCY_500SERIES_33MHZ:
515 printf("33MHz");
516 break;
517 case SPI_FREQUENCY_25MHZ:
518 printf("25MHz");
519 break;
520 case SPI_FREQUENCY_14MHZ:
521 printf("14MHz");
522 break;
523 default:
524 printf("unknown<%x>MHz", freq);
525 }
526}
527
528static void decode_spi_frequency(unsigned int freq)
529{
Subrata Banika5f47812020-09-29 11:43:01 +0530530 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikd16ef4d2020-08-26 15:53:00 +0530531 _decode_spi_frequency_500_series(freq);
532 else
533 _decode_spi_frequency(freq);
534}
535
Subrata Banike5d39922020-08-26 16:01:42 +0530536static void _decode_espi_frequency(unsigned int freq)
537{
538 switch (freq) {
539 case ESPI_FREQUENCY_20MHZ:
540 printf("20MHz");
541 break;
542 case ESPI_FREQUENCY_24MHZ:
543 printf("24MHz");
544 break;
545 case ESPI_FREQUENCY_30MHZ:
546 printf("30MHz");
547 break;
548 case ESPI_FREQUENCY_48MHZ:
549 printf("48MHz");
550 break;
551 case ESPI_FREQUENCY_60MHZ:
552 printf("60MHz");
553 break;
554 case ESPI_FREQUENCY_17MHZ:
555 printf("17MHz");
556 break;
557 default:
558 printf("unknown<%x>MHz", freq);
559 }
560}
561
562static void _decode_espi_frequency_500_series(unsigned int freq)
563{
564 switch (freq) {
565 case ESPI_FREQUENCY_500SERIES_20MHZ:
566 printf("20MHz");
567 break;
568 case ESPI_FREQUENCY_500SERIES_24MHZ:
569 printf("24MHz");
570 break;
571 case ESPI_FREQUENCY_500SERIES_25MHZ:
572 printf("25MHz");
573 break;
574 case ESPI_FREQUENCY_500SERIES_48MHZ:
575 printf("48MHz");
576 break;
577 case ESPI_FREQUENCY_500SERIES_60MHZ:
578 printf("60MHz");
579 break;
580 default:
581 printf("unknown<%x>MHz", freq);
582 }
583}
584
585static void decode_espi_frequency(unsigned int freq)
586{
Subrata Banika5f47812020-09-29 11:43:01 +0530587 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530588 _decode_espi_frequency_500_series(freq);
589 else
590 _decode_espi_frequency(freq);
591}
592
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700593static void decode_component_density(unsigned int density)
594{
595 switch (density) {
596 case COMPONENT_DENSITY_512KB:
597 printf("512KB");
598 break;
599 case COMPONENT_DENSITY_1MB:
600 printf("1MB");
601 break;
602 case COMPONENT_DENSITY_2MB:
603 printf("2MB");
604 break;
605 case COMPONENT_DENSITY_4MB:
606 printf("4MB");
607 break;
608 case COMPONENT_DENSITY_8MB:
609 printf("8MB");
610 break;
611 case COMPONENT_DENSITY_16MB:
612 printf("16MB");
613 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700614 case COMPONENT_DENSITY_32MB:
615 printf("32MB");
616 break;
617 case COMPONENT_DENSITY_64MB:
618 printf("64MB");
619 break;
620 case COMPONENT_DENSITY_UNUSED:
621 printf("UNUSED");
622 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700623 default:
624 printf("unknown<%x>MB", density);
625 }
626}
627
Subrata Banik26058dc2020-08-26 15:12:16 +0530628static int is_platform_with_pch(void)
629{
630 if (chipset >= CHIPSET_5_SERIES_IBEX_PEAK)
631 return 1;
632
633 return 0;
634}
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530635
636/* FLMAP0 register bit 24 onwards are reserved from SPT PCH */
637static int is_platform_with_100x_series_pch(void)
638{
639 if (chipset >= CHIPSET_100_200_SERIES_SUNRISE_POINT &&
Subrata Banika5f47812020-09-29 11:43:01 +0530640 chipset <= CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530641 return 1;
642
643 return 0;
644}
645
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100646static void dump_fcba(const struct fcba *fcba, const struct fpsba *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700647{
Subrata Banike5d39922020-08-26 16:01:42 +0530648 unsigned int freq;
649
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700650 printf("\nFound Component Section\n");
651 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700652 printf(" Dual Output Fast Read Support: %ssupported\n",
653 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700654 printf(" Read ID/Read Status Clock Frequency: ");
655 decode_spi_frequency((fcba->flcomp >> 27) & 7);
656 printf("\n Write/Erase Clock Frequency: ");
657 decode_spi_frequency((fcba->flcomp >> 24) & 7);
658 printf("\n Fast Read Clock Frequency: ");
659 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700660 printf("\n Fast Read Support: %ssupported",
661 (fcba->flcomp & (1 << 20))?"":"not ");
Subrata Banike5d39922020-08-26 16:01:42 +0530662 if (is_platform_with_100x_series_pch() &&
663 chipset != CHIPSET_100_200_SERIES_SUNRISE_POINT) {
664 printf("\n Read eSPI/EC Bus Frequency: ");
Subrata Banika5f47812020-09-29 11:43:01 +0530665 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT)
Subrata Banike5d39922020-08-26 16:01:42 +0530666 freq = (fpsba->pchstrp[22] & 0x38) >> 3;
667 else
668 freq = (fcba->flcomp >> 17) & 7;
669 decode_espi_frequency(freq);
670 } else {
671 printf("\n Read Clock Frequency: ");
672 decode_spi_frequency((fcba->flcomp >> 17) & 7);
673 }
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700674
675 switch (ifd_version) {
676 case IFD_VERSION_1:
677 printf("\n Component 2 Density: ");
678 decode_component_density((fcba->flcomp >> 3) & 7);
679 printf("\n Component 1 Density: ");
680 decode_component_density(fcba->flcomp & 7);
681 break;
Patrick Rudolph16598742022-10-21 15:13:43 +0200682 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700683 case IFD_VERSION_2:
684 printf("\n Component 2 Density: ");
685 decode_component_density((fcba->flcomp >> 4) & 0xf);
686 printf("\n Component 1 Density: ");
687 decode_component_density(fcba->flcomp & 0xf);
688 break;
689 }
690
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700691 printf("\n");
692 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700693 printf(" Invalid Instruction 3: 0x%02x\n",
694 (fcba->flill >> 24) & 0xff);
695 printf(" Invalid Instruction 2: 0x%02x\n",
696 (fcba->flill >> 16) & 0xff);
697 printf(" Invalid Instruction 1: 0x%02x\n",
698 (fcba->flill >> 8) & 0xff);
699 printf(" Invalid Instruction 0: 0x%02x\n",
700 fcba->flill & 0xff);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530701 if (is_platform_with_100x_series_pch()) {
702 printf("FLILL1 0x%08x\n", fcba->flpb);
703 printf(" Invalid Instruction 7: 0x%02x\n",
704 (fcba->flpb >> 24) & 0xff);
705 printf(" Invalid Instruction 6: 0x%02x\n",
706 (fcba->flpb >> 16) & 0xff);
707 printf(" Invalid Instruction 5: 0x%02x\n",
708 (fcba->flpb >> 8) & 0xff);
709 printf(" Invalid Instruction 4: 0x%02x\n",
710 fcba->flpb & 0xff);
711 } else {
712 printf("FLPB 0x%08x\n", fcba->flpb);
713 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
714 (fcba->flpb & 0xfff) << 12);
715 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700716}
717
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100718static void dump_fpsba(const struct fdbar *fdb, const struct fpsba *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700719{
Bill XIE4651d452017-09-12 11:54:48 +0800720 unsigned int i;
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200721 /* SoC Straps, aka PSL, aka ISL */
722 unsigned int SS = (fdb->flmap1 >> 24) & 0xff;
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200723
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700724 printf("Found PCH Strap Section\n");
Arthur Heymans0424a2c2021-06-22 11:14:24 +0200725 for (i = 0; i < SS; i++)
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200726 printf("PCHSTRP%-3u: 0x%08x\n", i, fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800727
728 if (ifd_version >= IFD_VERSION_2) {
729 printf("HAP bit is %sset\n",
730 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100731 } else if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
Bill XIEb3e15a22017-09-07 18:34:50 +0800732 printf("ICH_MeDisable bit is %sset\n",
733 fpsba->pchstrp[0] & 1 ? "" : "not ");
734 } else {
735 printf("AltMeDisable bit is %sset\n",
736 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
737 }
738
Bill XIE4651d452017-09-12 11:54:48 +0800739 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700740}
741
742static void decode_flmstr(uint32_t flmstr)
743{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700744 int wr_shift, rd_shift;
745 if (ifd_version >= IFD_VERSION_2) {
746 wr_shift = FLMSTR_WR_SHIFT_V2;
747 rd_shift = FLMSTR_RD_SHIFT_V2;
748 } else {
749 wr_shift = FLMSTR_WR_SHIFT_V1;
750 rd_shift = FLMSTR_RD_SHIFT_V1;
751 }
752
753 /* EC region access only available on v2+ */
Jeff Dalyabd4b962022-01-06 00:52:30 -0500754 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700755 printf(" EC Region Write Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100756 (flmstr & (1 << (wr_shift + 8))) ?
757 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700758 printf(" Platform Data Region Write Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100759 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500760 if (PLATFORM_HAS_GBE_REGION) {
761 printf(" GbE Region Write Access: %s\n",
762 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
763 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700764 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700765 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700766 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700767 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700768 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700769 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500770 if (PLATFORM_HAS_10GBE_0_REGION) {
771 printf(" 10GbE_0 Write Access: %s\n",
772 (flmstr & (1 << (wr_shift + 11))) ? "enabled" : "disabled");
773 }
774 if (PLATFORM_HAS_10GBE_1_REGION) {
775 printf(" 10GbE_1 Write Access: %s\n",
776 (flmstr & (1 << 4)) ? "enabled" : "disabled");
777 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700778
Jeff Dalyabd4b962022-01-06 00:52:30 -0500779 if (PLATFORM_HAS_EC_REGION)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700780 printf(" EC Region Read Access: %s\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100781 (flmstr & (1 << (rd_shift + 8))) ?
782 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700783 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700784 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500785 if (PLATFORM_HAS_GBE_REGION) {
786 printf(" GbE Region Read Access: %s\n",
787 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
788 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700789 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700790 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700791 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700792 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700793 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700794 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Jeff Dalyabd4b962022-01-06 00:52:30 -0500795 if (PLATFORM_HAS_10GBE_0_REGION) {
796 printf(" 10GbE_0 Read Access: %s\n",
797 (flmstr & (1 << (rd_shift + 11))) ? "enabled" : "disabled");
798 }
799 if (PLATFORM_HAS_10GBE_1_REGION) {
800 printf(" 10GbE_1 Read Access: %s\n",
801 (flmstr & (1 << 0)) ? "enabled" : "disabled");
802 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700803
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700804 /* Requestor ID doesn't exist for ifd 2 */
805 if (ifd_version < IFD_VERSION_2)
806 printf(" Requester ID: 0x%04x\n\n",
807 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700808}
809
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100810static void dump_fmba(const struct fmba *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700811{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700812 printf("Found Master Section\n");
813 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
814 decode_flmstr(fmba->flmstr1);
815 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
816 decode_flmstr(fmba->flmstr2);
Jeff Dalyabd4b962022-01-06 00:52:30 -0500817 if (PLATFORM_HAS_GBE_REGION) {
818 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
819 decode_flmstr(fmba->flmstr3);
820 if (ifd_version >= IFD_VERSION_2) {
821 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
822 decode_flmstr(fmba->flmstr5);
823 }
824 } else {
825 printf("FLMSTR6: 0x%08x (IE)\n", fmba->flmstr6);
826 decode_flmstr(fmba->flmstr6);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700827 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700828}
829
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100830static void dump_fmsba(const struct fmsba *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700831{
Bill XIE612ec0e2017-08-30 16:10:27 +0800832 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700833 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800834 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
835 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800836
837 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
838 printf("MCH_MeDisable bit is %sset\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100839 fmsba->data[0] & 1 ? "" : "not ");
Bill XIEb3e15a22017-09-07 18:34:50 +0800840 printf("MCH_AltMeDisable bit is %sset\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100841 fmsba->data[0] & (1 << 7) ? "" : "not ");
Bill XIEb3e15a22017-09-07 18:34:50 +0800842 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700843}
844
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700845static void dump_jid(uint32_t jid)
846{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100847 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700848 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100849 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200850 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100851 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200852 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700853}
854
855static void dump_vscc(uint32_t vscc)
856{
857 printf(" Lower Erase Opcode: 0x%02x\n",
858 vscc >> 24);
859 printf(" Lower Write Enable on Write Status: 0x%02x\n",
860 vscc & (1 << 20) ? 0x06 : 0x50);
861 printf(" Lower Write Status Required: %s\n",
862 vscc & (1 << 19) ? "Yes" : "No");
863 printf(" Lower Write Granularity: %d bytes\n",
864 vscc & (1 << 18) ? 64 : 1);
865 printf(" Lower Block / Sector Erase Size: ");
866 switch ((vscc >> 16) & 0x3) {
867 case 0:
868 printf("256 Byte\n");
869 break;
870 case 1:
871 printf("4KB\n");
872 break;
873 case 2:
874 printf("8KB\n");
875 break;
876 case 3:
877 printf("64KB\n");
878 break;
879 }
880
881 printf(" Upper Erase Opcode: 0x%02x\n",
882 (vscc >> 8) & 0xff);
883 printf(" Upper Write Enable on Write Status: 0x%02x\n",
884 vscc & (1 << 4) ? 0x06 : 0x50);
885 printf(" Upper Write Status Required: %s\n",
886 vscc & (1 << 3) ? "Yes" : "No");
887 printf(" Upper Write Granularity: %d bytes\n",
888 vscc & (1 << 2) ? 64 : 1);
889 printf(" Upper Block / Sector Erase Size: ");
890 switch (vscc & 0x3) {
891 case 0:
892 printf("256 Byte\n");
893 break;
894 case 1:
895 printf("4KB\n");
896 break;
897 case 2:
898 printf("8KB\n");
899 break;
900 case 3:
901 printf("64KB\n");
902 break;
903 }
904}
905
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100906static void dump_vtba(const struct vtba *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700907{
908 int i;
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100909 int max_len = sizeof(struct vtba)/sizeof(struct vscc);
Stefan Tauner0d226142018-08-05 18:56:53 +0200910 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700911
912 printf("ME VSCC table:\n");
913 for (i = 0; i < num; i++) {
914 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
915 dump_jid(vtba->entry[i].jid);
916 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
917 dump_vscc(vtba->entry[i].vscc);
918 }
919 printf("\n");
920}
921
Bill XIEfa5f9942017-09-12 11:22:29 +0800922static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700923{
924 int i, j;
925 printf("OEM Section:\n");
926 for (i = 0; i < 4; i++) {
927 printf("%02x:", i << 4);
928 for (j = 0; j < 16; j++)
929 printf(" %02x", oem[(i<<4)+j]);
930 printf ("\n");
931 }
932 printf ("\n");
933}
934
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700935static void dump_fd(char *image, int size)
936{
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100937 const struct fdbar *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700938 if (!fdb)
939 exit(EXIT_FAILURE);
940
Subrata Banik26058dc2020-08-26 15:12:16 +0530941 printf("%s", is_platform_with_pch() ? "PCH" : "ICH");
942 printf(" Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700943 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530944 if (!is_platform_with_100x_series_pch())
945 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700946 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
947 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
948 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
949
950 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530951 printf(" %s: ", is_platform_with_100x_series_pch() ? "PSL" : "ISL");
952 printf("0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700953 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
954 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
955 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
956
Subrata Banikac1b1dd2020-08-26 15:29:58 +0530957 if (!is_platform_with_100x_series_pch()) {
958 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
959 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
960 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
961 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700962
Subrata Banika5f47812020-09-29 11:43:01 +0530963 if (chipset == CHIPSET_500_600_SERIES_TIGER_ALDER_POINT) {
Subrata Banikbd2da5a2020-08-26 15:43:51 +0530964 printf("FLMAP3: 0x%08x\n", fdb->flmap3);
965 printf(" Minor Revision ID: 0x%04x\n", (fdb->flmap3 >> 14) & 0x7f);
966 printf(" Major Revision ID: 0x%04x\n", (fdb->flmap3 >> 21) & 0x7ff);
967 }
968
Stefan Tauner0d226142018-08-05 18:56:53 +0200969 char *flumap = find_flumap(image, size);
970 uint32_t flumap1 = *(uint32_t *)flumap;
971 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700972 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200973 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700974 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200975 (flumap1 & 0xff) << 4);
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100976 dump_vtba((struct vtba *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200977 (image + ((flumap1 & 0xff) << 4)),
978 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800979 dump_oem((const uint8_t *)image + 0xf00);
980
Maximilian Bruneab0e6802023-03-05 04:34:40 +0100981 const struct frba *frba = find_frba(image, size);
982 const struct fcba *fcba = find_fcba(image, size);
983 const struct fpsba *fpsba = find_fpsba(image, size);
984 const struct fmba *fmba = find_fmba(image, size);
985 const struct fmsba *fmsba = find_fmsba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800986
987 if (frba && fcba && fpsba && fmba && fmsba) {
988 dump_frba(frba);
Subrata Banike5d39922020-08-26 16:01:42 +0530989 dump_fcba(fcba, fpsba);
Patrick Rudolph802cbee2020-05-25 12:18:11 +0200990 dump_fpsba(fdb, fpsba);
Bill XIE612ec0e2017-08-30 16:10:27 +0800991 dump_fmba(fmba);
992 dump_fmsba(fmsba);
993 } else {
994 printf("FD is corrupted!\n");
995 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700996}
997
998static void write_regions(char *image, int size)
999{
Bill XIEfa5f9942017-09-12 11:22:29 +08001000 unsigned int i;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001001 const struct frba *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001002
Bill XIE612ec0e2017-08-30 16:10:27 +08001003 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001004 exit(EXIT_FAILURE);
1005
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001006 for (i = 0; i < max_regions; i++) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001007 struct region region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -07001008 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001009 if (region.size > 0) {
1010 int region_fd;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001011 region_fd = open(region_names[i].filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -06001012 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001013 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001014 if (region_fd < 0) {
1015 perror("Error while trying to open file");
1016 exit(EXIT_FAILURE);
1017 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001018 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001019 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001020 close(region_fd);
1021 }
1022 }
1023}
1024
Mathew Kingc7ddc992019-08-08 14:59:25 -06001025static void validate_layout(char *image, int size)
1026{
1027 uint i, errors = 0;
1028 struct fmap *fmap;
1029 long int fmap_loc = fmap_find((uint8_t *)image, size);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001030 const struct frba *frba = find_frba(image, size);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001031
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001032 if (fmap_loc < 0 || !frba) {
1033 printf("Could not find FMAP (%p) or Intel Flash Descriptor (%p)\n",
1034 (void *)fmap_loc, frba);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001035 exit(EXIT_FAILURE);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001036 }
Mathew Kingc7ddc992019-08-08 14:59:25 -06001037
1038 fmap = (struct fmap *)(image + fmap_loc);
1039
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001040 int matches = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001041 for (i = 0; i < max_regions; i++) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001042 struct region region = get_region(frba, i);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001043 if (region.size == 0)
1044 continue;
1045
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001046 const struct fmap_area *area = fmap_find_area(fmap, region_names[i].fmapname);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001047 if (!area)
1048 continue;
1049
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001050 matches++; // found a match between FMAP and IFD region
1051
1052 if ((uint)region.base != area->offset || (uint)region.size != area->size) {
1053 printf("Region mismatch between %s and %s\n", region_names[i].terse, area->name);
Mathew Kingc7ddc992019-08-08 14:59:25 -06001054 printf(" Descriptor region %s:\n", region_names[i].terse);
1055 printf(" offset: 0x%08x\n", region.base);
1056 printf(" length: 0x%08x\n", region.size);
1057 printf(" FMAP area %s:\n", area->name);
1058 printf(" offset: 0x%08x\n", area->offset);
1059 printf(" length: 0x%08x\n", area->size);
1060 errors++;
1061 }
1062 }
1063
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001064 if (!matches) {
1065 // At least a BIOS region should be present in both IFD and FMAP
1066 fprintf(stderr, "Warning: Not a single IFD region found in FMAP\n");
1067 }
1068
Mathew Kingc7ddc992019-08-08 14:59:25 -06001069 if (errors > 0)
1070 exit(EXIT_FAILURE);
1071}
1072
Bill XIEfa5f9942017-09-12 11:22:29 +08001073static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001074{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001075 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001076 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001077
1078 // Now write out new image
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001079 new_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +02001080 if (new_fd < 0) {
1081 perror("Error while trying to open file");
1082 exit(EXIT_FAILURE);
1083 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001084 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -07001085 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001086 close(new_fd);
1087}
1088
Bill XIEfa5f9942017-09-12 11:22:29 +08001089static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001090 enum spi_frequency freq)
1091{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001092 struct fcba *fcba = find_fcba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001093 if (!fcba)
1094 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001095
1096 /* clear bits 21-29 */
1097 fcba->flcomp &= ~0x3fe00000;
1098 /* Read ID and Read Status Clock Frequency */
1099 fcba->flcomp |= freq << 27;
1100 /* Write and Erase Clock Frequency */
1101 fcba->flcomp |= freq << 24;
1102 /* Fast Read Clock Frequency */
1103 fcba->flcomp |= freq << 21;
1104
1105 write_image(filename, image, size);
1106}
1107
Bill XIEfa5f9942017-09-12 11:22:29 +08001108static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001109{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001110 struct fcba *fcba = find_fcba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001111 if (!fcba)
1112 exit(EXIT_FAILURE);
1113
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001114 int freq;
1115
1116 switch (ifd_version) {
1117 case IFD_VERSION_1:
Patrick Rudolph16598742022-10-21 15:13:43 +02001118 case IFD_VERSION_1_5:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001119 freq = SPI_FREQUENCY_20MHZ;
1120 break;
1121 case IFD_VERSION_2:
1122 freq = SPI_FREQUENCY_17MHZ;
1123 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -07001124 default:
1125 freq = SPI_FREQUENCY_17MHZ;
1126 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001127 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001128
1129 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001130 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001131}
1132
Bill XIEfa5f9942017-09-12 11:22:29 +08001133static void set_chipdensity(const char *filename, char *image, int size,
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001134 unsigned int density)
Jan Tatjefa317512016-03-11 00:52:07 +01001135{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001136 struct fcba *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001137 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +08001138 if (!fcba)
1139 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +01001140
1141 printf("Setting chip density to ");
1142 decode_component_density(density);
1143 printf("\n");
1144
1145 switch (ifd_version) {
1146 case IFD_VERSION_1:
1147 /* fail if selected density is not supported by this version */
1148 if ( (density == COMPONENT_DENSITY_32MB) ||
1149 (density == COMPONENT_DENSITY_64MB) ||
1150 (density == COMPONENT_DENSITY_UNUSED) ) {
1151 printf("error: Selected density not supported in IFD version 1.\n");
1152 exit(EXIT_FAILURE);
1153 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001154 mask = 0x7;
1155 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +01001156 break;
Patrick Rudolph16598742022-10-21 15:13:43 +02001157 case IFD_VERSION_1_5:
Jan Tatjefa317512016-03-11 00:52:07 +01001158 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001159 mask = 0xf;
1160 chip2_offset = 4;
1161 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001162 default:
1163 printf("error: Unknown IFD version\n");
1164 exit(EXIT_FAILURE);
1165 break;
1166 }
1167
1168 /* clear chip density for corresponding chip */
1169 switch (selected_chip) {
1170 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001171 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +01001172 break;
1173 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001174 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +01001175 break;
1176 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001177 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +01001178 break;
1179 }
1180
1181 /* set the new density */
1182 if (selected_chip == 1 || selected_chip == 0)
1183 fcba->flcomp |= (density); /* first chip */
1184 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001185 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +01001186
1187 write_image(filename, image, size);
1188}
1189
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001190static int check_region(const struct frba *frba, unsigned int region_type)
Duncan Laurie7775d672019-06-06 13:39:26 -07001191{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001192 struct region region;
Duncan Laurie7775d672019-06-06 13:39:26 -07001193
1194 if (!frba)
1195 return 0;
1196
1197 region = get_region(frba, region_type);
1198 return !!((region.base < region.limit) && (region.size > 0));
1199}
1200
Bill XIEfa5f9942017-09-12 11:22:29 +08001201static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001202{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001203 int wr_shift, rd_shift;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001204 struct fmba *fmba = find_fmba(image, size);
1205 const struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001206 if (!fmba)
1207 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001208
1209 if (ifd_version >= IFD_VERSION_2) {
1210 wr_shift = FLMSTR_WR_SHIFT_V2;
1211 rd_shift = FLMSTR_RD_SHIFT_V2;
1212
1213 /* Clear non-reserved bits */
1214 fmba->flmstr1 &= 0xff;
1215 fmba->flmstr2 &= 0xff;
1216 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001217 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001218 } else {
1219 wr_shift = FLMSTR_WR_SHIFT_V1;
1220 rd_shift = FLMSTR_RD_SHIFT_V1;
1221
1222 fmba->flmstr1 = 0;
1223 fmba->flmstr2 = 0;
1224 /* Requestor ID */
1225 fmba->flmstr3 = 0x118;
1226 }
1227
Andrey Petrov96ecb772016-10-31 19:31:54 -07001228 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001229 case PLATFORM_APL:
1230 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001231 /* CPU/BIOS can read descriptor and BIOS */
1232 fmba->flmstr1 |= 0x3 << rd_shift;
1233 /* CPU/BIOS can write BIOS */
1234 fmba->flmstr1 |= 0x2 << wr_shift;
1235 /* TXE can read descriptor, BIOS and Device Expansion */
1236 fmba->flmstr2 |= 0x23 << rd_shift;
1237 /* TXE can only write Device Expansion */
1238 fmba->flmstr2 |= 0x20 << wr_shift;
1239 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001240 case PLATFORM_CNL:
1241 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001242 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001243 case PLATFORM_TGL:
Subrata Banika717e2f2020-07-30 11:22:53 +05301244 case PLATFORM_JSL:
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001245 case PLATFORM_EHL:
Subrata Banik46f80732020-03-14 15:01:42 +05301246 case PLATFORM_ADL:
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001247 case PLATFORM_IFD2:
Subrata Banikca82e612022-01-20 18:51:21 +05301248 case PLATFORM_MTL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001249 /* CPU/BIOS can read descriptor and BIOS. */
1250 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1251 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1252 /* CPU/BIOS can write BIOS. */
1253 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1254 /* ME can read descriptor and ME. */
1255 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1256 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001257 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001258 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1259 if (check_region(frba, REGION_GBE)) {
1260 /* BIOS can read/write GbE. */
1261 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1262 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1263 /* ME can read GbE. */
1264 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1265 /* GbE can read descriptor and read/write GbE.. */
1266 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1267 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1268 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1269 }
1270 if (check_region(frba, REGION_PDR)) {
1271 /* BIOS can read/write PDR. */
1272 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1273 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1274 }
1275 if (check_region(frba, REGION_EC)) {
1276 /* BIOS can read EC. */
1277 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1278 /* EC can read descriptor and read/write EC. */
1279 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1280 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1281 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1282 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001283 break;
Jeff Dalyabd4b962022-01-06 00:52:30 -05001284 case PLATFORM_DNV:
Patrick Rudolph16598742022-10-21 15:13:43 +02001285 case PLATFORM_WBG:
Jeff Dalyabd4b962022-01-06 00:52:30 -05001286 /* CPU/BIOS can read descriptor and BIOS. */
1287 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1288 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1289 /* CPU/BIOS can write BIOS. */
1290 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1291 /* ME can read descriptor and ME. */
1292 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1293 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1294 /* ME can write ME. */
1295 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1296 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001297 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001298 /* CPU/BIOS can read descriptor and BIOS. */
1299 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1300 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1301 /* CPU/BIOS can write BIOS. */
1302 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1303 /* ME can read descriptor and ME. */
1304 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1305 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1306 /* ME can write ME. */
1307 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1308 if (check_region(frba, REGION_GBE)) {
1309 /* BIOS can read GbE. */
1310 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1311 /* BIOS can write GbE. */
1312 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1313 /* ME can read GbE. */
1314 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1315 /* ME can write GbE. */
1316 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1317 /* GbE can write GbE. */
1318 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1319 /* GbE can read GbE. */
1320 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1321 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001322 break;
1323 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001324
1325 write_image(filename, image, size);
1326}
1327
Usha P412679d2020-10-15 11:25:08 +05301328static void enable_cpu_read_me(const char *filename, char *image, int size)
1329{
1330 int rd_shift;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001331 struct fmba *fmba = find_fmba(image, size);
Usha P412679d2020-10-15 11:25:08 +05301332
1333 if (!fmba)
1334 exit(EXIT_FAILURE);
1335
1336 if (ifd_version >= IFD_VERSION_2)
1337 rd_shift = FLMSTR_RD_SHIFT_V2;
1338 else
1339 rd_shift = FLMSTR_RD_SHIFT_V1;
1340
1341 /* CPU/BIOS can read ME. */
1342 fmba->flmstr1 |= (1 << REGION_ME) << rd_shift;
1343
1344 write_image(filename, image, size);
1345}
1346
Bill XIEfa5f9942017-09-12 11:22:29 +08001347static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001348{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001349 struct fmba *fmba = find_fmba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001350 if (!fmba)
1351 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001352
1353 if (ifd_version >= IFD_VERSION_2) {
1354 /* Access bits for each region are read: 19:8 write: 31:20 */
1355 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1356 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1357 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001358 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001359 } else {
1360 fmba->flmstr1 = 0xffff0000;
1361 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001362 /* Keep chipset specific Requester ID */
1363 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001364 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001365
1366 write_image(filename, image, size);
1367}
1368
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001369static void set_pchstrap(struct fpsba *fpsba, const struct fdbar *fdb, const int strap,
1370 const unsigned int value)
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001371{
1372 if (!fpsba || !fdb) {
1373 fprintf(stderr, "Internal error\n");
1374 exit(EXIT_FAILURE);
1375 }
1376
Arthur Heymans0424a2c2021-06-22 11:14:24 +02001377 /* SoC Strap, aka PSL, aka ISL */
1378 int SS = (fdb->flmap1 >> 24) & 0xff;
1379 if (strap >= SS) {
1380 fprintf(stderr, "Strap index %d out of range (max: %d)\n", strap, SS);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001381 exit(EXIT_FAILURE);
1382 }
1383 fpsba->pchstrp[strap] = value;
1384}
1385
Bill XIEb3e15a22017-09-07 18:34:50 +08001386/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001387static void fpsba_set_altmedisable(struct fpsba *fpsba, struct fmsba *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001388{
1389 if (ifd_version >= IFD_VERSION_2) {
1390 printf("%sting the HAP bit to %s Intel ME...\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001391 altmedisable?"Set":"Unset",
1392 altmedisable?"disable":"enable");
Bill XIEb3e15a22017-09-07 18:34:50 +08001393 if (altmedisable)
1394 fpsba->pchstrp[0] |= (1 << 16);
1395 else
1396 fpsba->pchstrp[0] &= ~(1 << 16);
1397 } else {
1398 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1399 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1400 "and MCH_AltMeDisable to %s Intel ME...\n",
1401 altmedisable?"Set":"Unset",
1402 altmedisable?"disable":"enable");
1403 if (altmedisable) {
1404 /* MCH_MeDisable */
1405 fmsba->data[0] |= 1;
1406 /* MCH_AltMeDisable */
1407 fmsba->data[0] |= (1 << 7);
1408 /* ICH_MeDisable */
1409 fpsba->pchstrp[0] |= 1;
1410 } else {
1411 fmsba->data[0] &= ~1;
1412 fmsba->data[0] &= ~(1 << 7);
1413 fpsba->pchstrp[0] &= ~1;
1414 }
1415 } else {
1416 printf("%sting the AltMeDisable to %s Intel ME...\n",
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001417 altmedisable?"Set":"Unset",
1418 altmedisable?"disable":"enable");
Bill XIEb3e15a22017-09-07 18:34:50 +08001419 if (altmedisable)
1420 fpsba->pchstrp[10] |= (1 << 7);
1421 else
1422 fpsba->pchstrp[10] &= ~(1 << 7);
1423 }
1424 }
1425}
1426
Jacob Garber595d9262019-06-27 17:33:10 -06001427static void inject_region(const char *filename, char *image, int size,
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001428 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001429{
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001430 struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001431 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001432 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001433
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001434 struct region region = get_region(frba, region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001435 if (region.size <= 0xfff) {
1436 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1437 region_name(region_type));
1438 exit(EXIT_FAILURE);
1439 }
1440
Scott Duplichanf2c98372014-12-12 21:03:06 -06001441 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001442 if (region_fd == -1) {
1443 perror("Could not open file");
1444 exit(EXIT_FAILURE);
1445 }
1446 struct stat buf;
1447 if (fstat(region_fd, &buf) == -1) {
1448 perror("Could not stat file");
1449 exit(EXIT_FAILURE);
1450 }
1451 int region_size = buf.st_size;
1452
1453 printf("File %s is %d bytes\n", region_fname, region_size);
1454
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001455 if (region_size > region.size) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001456 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1457 " bytes. Not injecting.\n",
1458 region_name(region_type), region.size,
1459 region.size, region_size, region_size);
1460 exit(EXIT_FAILURE);
1461 }
1462
1463 int offset = 0;
1464 if ((region_type == 1) && (region_size < region.size)) {
1465 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1466 " bytes. Padding before injecting.\n",
1467 region_name(region_type), region.size,
1468 region.size, region_size, region_size);
1469 offset = region.size - region_size;
1470 memset(image + region.base, 0xff, offset);
1471 }
1472
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001473 if (size < region.base + offset + region_size) {
1474 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1475 size, region.base + offset + region_size);
1476 exit(EXIT_FAILURE);
1477 }
1478
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001479 if (read(region_fd, image + region.base + offset, region_size) != region_size) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001480 perror("Could not read file");
1481 exit(EXIT_FAILURE);
1482 }
1483
1484 close(region_fd);
1485
1486 printf("Adding %s as the %s section of %s\n",
1487 region_fname, region_name(region_type), filename);
1488 write_image(filename, image, size);
1489}
1490
Jacob Garber595d9262019-06-27 17:33:10 -06001491static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001492{
1493 unsigned int y = 1;
1494 if (x == 0)
1495 return 0;
1496 while (y <= x)
1497 y = y << 1;
1498
1499 return y;
1500}
1501
1502/**
1503 * Determine if two memory regions overlap.
1504 *
1505 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001506 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001507 * @return 1 if the two regions overlap
1508 */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001509static int regions_collide(const struct region *r1, const struct region *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001510{
Bill XIEfa5f9942017-09-12 11:22:29 +08001511 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001512 return 0;
1513
Nico Huber844eda02019-01-05 00:06:19 +01001514 /* r1 should be either completely below or completely above r2 */
1515 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001516}
1517
Jacob Garber595d9262019-06-27 17:33:10 -06001518static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001519 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001520{
1521 FILE *romlayout;
1522 char tempstr[256];
1523 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001524 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001525 int region_number;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001526 struct region current_regions[MAX_REGIONS];
1527 struct region new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001528 int new_extent = 0;
1529 char *new_image;
1530
1531 /* load current descriptor map and regions */
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001532 struct frba *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +08001533 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001534 exit(EXIT_FAILURE);
1535
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001536 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001537 current_regions[i] = get_region(frba, i);
1538 new_regions[i] = get_region(frba, i);
1539 }
1540
1541 /* read new layout */
1542 romlayout = fopen(layout_fname, "r");
1543
1544 if (!romlayout) {
1545 perror("Could not read layout file.\n");
1546 exit(EXIT_FAILURE);
1547 }
1548
1549 while (!feof(romlayout)) {
1550 char *tstr1, *tstr2;
1551
Patrick Georgi802ad522014-08-09 17:12:23 +02001552 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001553 layout_region_name))
1554 continue;
1555
1556 region_number = region_num(layout_region_name);
1557 if (region_number < 0)
1558 continue;
1559
1560 tstr1 = strtok(tempstr, ":");
1561 tstr2 = strtok(NULL, ":");
1562 if (!tstr1 || !tstr2) {
1563 fprintf(stderr, "Could not parse layout file.\n");
1564 exit(EXIT_FAILURE);
1565 }
1566 new_regions[region_number].base = strtol(tstr1,
1567 (char **)NULL, 16);
1568 new_regions[region_number].limit = strtol(tstr2,
1569 (char **)NULL, 16);
1570 new_regions[region_number].size =
1571 new_regions[region_number].limit -
1572 new_regions[region_number].base + 1;
1573
1574 if (new_regions[region_number].size < 0)
1575 new_regions[region_number].size = 0;
1576 }
1577 fclose(romlayout);
1578
1579 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001580 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001581 if (new_regions[i].size == 0)
1582 continue;
1583
1584 if (new_regions[i].size < current_regions[i].size) {
1585 printf("DANGER: Region %s is shrinking.\n",
1586 region_name(i));
1587 printf(" The region will be truncated to fit.\n");
1588 printf(" This may result in an unusable image.\n");
1589 }
1590
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001591 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001592 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001593 fprintf(stderr, "Regions would overlap.\n");
1594 exit(EXIT_FAILURE);
1595 }
1596 }
1597
1598 /* detect if the image size should grow */
1599 if (new_extent < new_regions[i].limit)
1600 new_extent = new_regions[i].limit;
1601 }
1602
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001603 /* check if the image is actually a Flash Descriptor region */
1604 if (size == new_regions[0].size) {
1605 printf("The image is a single Flash Descriptor:\n");
1606 printf(" Only the descriptor will be modified\n");
1607 new_extent = size;
1608 } else {
1609 new_extent = next_pow2(new_extent - 1);
1610 if (new_extent != size) {
1611 printf("The image has changed in size.\n");
1612 printf("The old image is %d bytes.\n", size);
1613 printf("The new image is %d bytes.\n", new_extent);
1614 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001615 }
1616
1617 /* copy regions to a new image */
1618 new_image = malloc(new_extent);
1619 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001620 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001621 int copy_size = new_regions[i].size;
1622 int offset_current = 0, offset_new = 0;
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001623 const struct region *current = &current_regions[i];
1624 const struct region *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001625
Bill XIEfa5f9942017-09-12 11:22:29 +08001626 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001627 continue;
1628
Bill XIEfa5f9942017-09-12 11:22:29 +08001629 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001630 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001631 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001632 if (i == REGION_BIOS)
1633 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001634 }
1635
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001636 if ((i == REGION_BIOS) && (new->size < current->size)) {
1637 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001638 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001639 }
1640
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001641 if (size < current->base + offset_current + copy_size) {
1642 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1643 region_name(i));
1644 continue;
1645 };
1646
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001647 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1648 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001649 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1650 offset_current, current->limit, current->size);
1651 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1652 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001653
Bill XIEfa5f9942017-09-12 11:22:29 +08001654 memcpy(new_image + new->base + offset_new,
1655 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001656 copy_size);
1657 }
1658
1659 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001660 frba = find_frba(new_image, new_extent);
1661 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001662 exit(EXIT_FAILURE);
1663
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001664 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001665 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001666 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001667
1668 write_image(filename, new_image, new_extent);
1669 free(new_image);
1670}
1671
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001672static void print_version(void)
1673{
1674 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1675 printf("Copyright (C) 2011 Google Inc.\n\n");
1676 printf
1677 ("This program is free software: you can redistribute it and/or modify\n"
1678 "it under the terms of the GNU General Public License as published by\n"
1679 "the Free Software Foundation, version 2 of the License.\n\n"
1680 "This program is distributed in the hope that it will be useful,\n"
1681 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1682 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001683 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001684}
1685
1686static void print_usage(const char *name)
1687{
1688 printf("usage: %s [-vhdix?] <filename>\n", name);
1689 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001690 " -d | --dump: dump intel firmware descriptor\n"
1691 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1692 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1693 " -x | --extract: extract intel fd modules\n"
1694 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1695 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001696 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001697 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1698 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1699 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1700 " can only be used once per run:\n"
1701 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1702 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1703 " Dual Output Fast Read Support\n"
1704 " -l | --lock Lock firmware descriptor and ME region\n"
Usha P412679d2020-10-15 11:25:08 +05301705 " -r | --read Enable CPU/BIOS read access for ME region\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001706 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001707 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1708 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001709 " -p | --platform Add platform-specific quirks\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301710 " adl - Alder Lake\n"
1711 " aplk - Apollo Lake\n"
1712 " cnl - Cannon Lake\n"
Johnny Line273a022021-06-22 11:26:46 +08001713 " lbg - Lewisburg PCH\n"
Jeff Dalyabd4b962022-01-06 00:52:30 -05001714 " dnv - Denverton\n"
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001715 " ehl - Elkhart Lake\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301716 " glk - Gemini Lake\n"
1717 " icl - Ice Lake\n"
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001718 " ifd2 - IFDv2 Platform\n"
Subrata Banik15da1742020-08-26 13:27:21 +05301719 " jsl - Jasper Lake\n"
1720 " sklkbl - Sky Lake/Kaby Lake\n"
1721 " tgl - Tiger Lake\n"
Patrick Rudolph16598742022-10-21 15:13:43 +02001722 " wbg - Wellsburg\n"
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001723 " -S | --setpchstrap Write a PCH strap\n"
1724 " -V | --newvalue The new value to write into PCH strap specified by -S\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001725 " -v | --version: print the version\n"
1726 " -h | --help: print this help\n\n"
Jeff Daly3623eca2022-01-05 23:51:40 -05001727 "<region> is one of Descriptor, BIOS, ME, GbE, Platform Data, Secondary BIOS, "
1728 "Device Exp1, EC, Device Exp2, IE, 10GbE_0, 10GbE_1, PTT\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001729 "\n");
1730}
1731
1732int main(int argc, char *argv[])
1733{
1734 int opt, option_index = 0;
1735 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001736 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001737 int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0;
Usha P412679d2020-10-15 11:25:08 +05301738 int mode_read = 0, mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001739 char *region_type_string = NULL, *region_fname = NULL;
1740 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001741 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001742 int region_type = -1, inputfreq = 0;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001743 unsigned int value = 0;
1744 unsigned int pchstrap = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001745 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001746 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1747
Bill XIEfa5f9942017-09-12 11:22:29 +08001748 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001749 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001750 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001751 {"extract", 0, NULL, 'x'},
1752 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001753 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001754 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001755 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001756 {"density", 1, NULL, 'D'},
1757 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001758 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001759 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001760 {"lock", 0, NULL, 'l'},
Usha P412679d2020-10-15 11:25:08 +05301761 {"read", 0, NULL, 'r'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001762 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001763 {"version", 0, NULL, 'v'},
1764 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001765 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001766 {"validate", 0, NULL, 't'},
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001767 {"setpchstrap", 1, NULL, 'S'},
1768 {"newvalue", 1, NULL, 'V'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001769 {0, 0, 0, 0}
1770 };
1771
Usha P412679d2020-10-15 11:25:08 +05301772 while ((opt = getopt_long(argc, argv, "S:V:df:D:C:M:xi:n:O:s:p:elruvth?",
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001773 long_options, &option_index)) != EOF) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001774 switch (opt) {
1775 case 'd':
1776 mode_dump = 1;
1777 break;
Patrick Rudolph802cbee2020-05-25 12:18:11 +02001778 case 'S':
1779 mode_setstrap = 1;
1780 pchstrap = strtoul(optarg, NULL, 0);
1781 break;
1782 case 'V':
1783 value = strtoul(optarg, NULL, 0);
1784 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001785 case 'f':
1786 mode_layout = 1;
1787 layout_fname = strdup(optarg);
1788 if (!layout_fname) {
1789 fprintf(stderr, "No layout file specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001790 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Chris Douglass03ce0142014-02-26 13:30:13 -05001791 exit(EXIT_FAILURE);
1792 }
1793 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001794 case 'x':
1795 mode_extract = 1;
1796 break;
1797 case 'i':
1798 // separate type and file name
1799 region_type_string = strdup(optarg);
1800 region_fname = strchr(region_type_string, ':');
1801 if (!region_fname) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001802 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001803 exit(EXIT_FAILURE);
1804 }
1805 region_fname[0] = '\0';
1806 region_fname++;
1807 // Descriptor, BIOS, ME, GbE, Platform
1808 // valid type?
1809 if (!strcasecmp("Descriptor", region_type_string))
1810 region_type = 0;
1811 else if (!strcasecmp("BIOS", region_type_string))
1812 region_type = 1;
1813 else if (!strcasecmp("ME", region_type_string))
1814 region_type = 2;
1815 else if (!strcasecmp("GbE", region_type_string))
1816 region_type = 3;
Jeff Daly3623eca2022-01-05 23:51:40 -05001817 else if (!strcasecmp("Platform Data", region_type_string))
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001818 region_type = 4;
Jeff Daly3623eca2022-01-05 23:51:40 -05001819 else if (!strcasecmp("Device Exp1", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001820 region_type = 5;
Jeff Daly3623eca2022-01-05 23:51:40 -05001821 else if (!strcasecmp("Secondary BIOS", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001822 region_type = 6;
Jeff Daly3623eca2022-01-05 23:51:40 -05001823 else if (!strcasecmp("Reserved", region_type_string))
Stefan Reinauere4e08f22020-10-26 10:15:42 -07001824 region_type = 7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001825 else if (!strcasecmp("EC", region_type_string))
1826 region_type = 8;
Jeff Daly3623eca2022-01-05 23:51:40 -05001827 else if (!strcasecmp("Device Exp2", region_type_string))
1828 region_type = 9;
1829 else if (!strcasecmp("IE", region_type_string))
1830 region_type = 10;
1831 else if (!strcasecmp("10GbE_0", region_type_string))
1832 region_type = 11;
1833 else if (!strcasecmp("10GbE_1", region_type_string))
1834 region_type = 12;
1835 else if (!strcasecmp("PTT", region_type_string))
1836 region_type = 15;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001837 if (region_type == -1) {
1838 fprintf(stderr, "No such region type: '%s'\n\n",
1839 region_type_string);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001840 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001841 exit(EXIT_FAILURE);
1842 }
1843 mode_inject = 1;
1844 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001845 case 'n':
1846 mode_newlayout = 1;
1847 layout_fname = strdup(optarg);
1848 if (!layout_fname) {
1849 fprintf(stderr, "No layout file specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001850 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001851 exit(EXIT_FAILURE);
1852 }
1853 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001854 case 'O':
1855 new_filename = strdup(optarg);
1856 if (!new_filename) {
1857 fprintf(stderr, "No output filename specified\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001858 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001859 exit(EXIT_FAILURE);
1860 }
1861 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001862 case 'D':
1863 mode_density = 1;
1864 new_density = strtoul(optarg, NULL, 0);
1865 switch (new_density) {
1866 case 512:
1867 new_density = COMPONENT_DENSITY_512KB;
1868 break;
1869 case 1:
1870 new_density = COMPONENT_DENSITY_1MB;
1871 break;
1872 case 2:
1873 new_density = COMPONENT_DENSITY_2MB;
1874 break;
1875 case 4:
1876 new_density = COMPONENT_DENSITY_4MB;
1877 break;
1878 case 8:
1879 new_density = COMPONENT_DENSITY_8MB;
1880 break;
1881 case 16:
1882 new_density = COMPONENT_DENSITY_16MB;
1883 break;
1884 case 32:
1885 new_density = COMPONENT_DENSITY_32MB;
1886 break;
1887 case 64:
1888 new_density = COMPONENT_DENSITY_64MB;
1889 break;
1890 case 0:
1891 new_density = COMPONENT_DENSITY_UNUSED;
1892 break;
1893 default:
1894 printf("error: Unknown density\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001895 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Jan Tatjefa317512016-03-11 00:52:07 +01001896 exit(EXIT_FAILURE);
1897 }
1898 break;
1899 case 'C':
1900 selected_chip = strtol(optarg, NULL, 0);
1901 if (selected_chip > 2) {
1902 fprintf(stderr, "error: Invalid chip selection\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001903 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Jan Tatjefa317512016-03-11 00:52:07 +01001904 exit(EXIT_FAILURE);
1905 }
1906 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001907 case 'M':
1908 mode_altmedisable = 1;
1909 altmedisable = strtol(optarg, NULL, 0);
1910 if (altmedisable > 1) {
1911 fprintf(stderr, "error: Illegal value\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001912 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Bill XIEb3e15a22017-09-07 18:34:50 +08001913 exit(EXIT_FAILURE);
1914 }
1915 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001916 case 's':
1917 // Parse the requested SPI frequency
1918 inputfreq = strtol(optarg, NULL, 0);
1919 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001920 case 17:
1921 spifreq = SPI_FREQUENCY_17MHZ;
1922 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001923 case 20:
1924 spifreq = SPI_FREQUENCY_20MHZ;
1925 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001926 case 30:
1927 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1928 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001929 case 33:
1930 spifreq = SPI_FREQUENCY_33MHZ;
1931 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001932 case 48:
1933 spifreq = SPI_FREQUENCY_48MHZ;
1934 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001935 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001936 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001937 break;
1938 default:
1939 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1940 inputfreq);
Maximilian Bruneab0e6802023-03-05 04:34:40 +01001941 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001942 exit(EXIT_FAILURE);
1943 }
1944 mode_spifreq = 1;
1945 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001946 case 'e':
1947 mode_em100 = 1;
1948 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001949 case 'l':
1950 mode_locked = 1;
1951 if (mode_unlocked == 1) {
1952 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1953 exit(EXIT_FAILURE);
1954 }
1955 break;
Usha P412679d2020-10-15 11:25:08 +05301956 case 'r':
1957 mode_read = 1;
1958 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001959 case 'u':
1960 mode_unlocked = 1;
1961 if (mode_locked == 1) {
1962 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1963 exit(EXIT_FAILURE);
1964 }
1965 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001966 case 'p':
1967 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001968 platform = PLATFORM_APL;
1969 } else if (!strcmp(optarg, "cnl")) {
1970 platform = PLATFORM_CNL;
Johnny Line273a022021-06-22 11:26:46 +08001971 } else if (!strcmp(optarg, "lbg")) {
1972 platform = PLATFORM_LBG;
Jeff Dalyabd4b962022-01-06 00:52:30 -05001973 } else if (!strcmp(optarg, "dnv")) {
1974 platform = PLATFORM_DNV;
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001975 } else if (!strcmp(optarg, "ehl")) {
1976 platform = PLATFORM_EHL;
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001977 } else if (!strcmp(optarg, "glk")) {
1978 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301979 } else if (!strcmp(optarg, "icl")) {
1980 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301981 } else if (!strcmp(optarg, "jsl")) {
Lean Sheng Tan0faba3c2021-06-09 07:52:24 -07001982 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001983 } else if (!strcmp(optarg, "sklkbl")) {
1984 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001985 } else if (!strcmp(optarg, "tgl")) {
1986 platform = PLATFORM_TGL;
Subrata Banik46f80732020-03-14 15:01:42 +05301987 } else if (!strcmp(optarg, "adl")) {
1988 platform = PLATFORM_ADL;
Wonkyu Kim3922aa52022-02-02 15:19:05 -08001989 } else if (!strcmp(optarg, "ifd2")) {
1990 platform = PLATFORM_IFD2;
Subrata Banikca82e612022-01-20 18:51:21 +05301991 } else if (!strcmp(optarg, "mtl")) {
1992 platform = PLATFORM_MTL;
Patrick Rudolph16598742022-10-21 15:13:43 +02001993 } else if (!strcmp(optarg, "wbg")) {
1994 platform = PLATFORM_WBG;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001995 } else {
1996 fprintf(stderr, "Unknown platform: %s\n", optarg);
1997 exit(EXIT_FAILURE);
1998 }
1999 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06002000 case 't':
2001 mode_validate = 1;
2002 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002003 case 'v':
2004 print_version();
2005 exit(EXIT_SUCCESS);
2006 break;
2007 case 'h':
2008 case '?':
2009 default:
2010 print_usage(argv[0]);
2011 exit(EXIT_SUCCESS);
2012 break;
2013 }
2014 }
2015
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002016 if ((mode_dump + mode_layout + mode_extract + mode_inject +
2017 mode_setstrap + mode_newlayout + (mode_spifreq | mode_em100 |
2018 mode_unlocked | mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002019 fprintf(stderr, "You may not specify more than one mode.\n\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002020 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002021 exit(EXIT_FAILURE);
2022 }
2023
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002024 if ((mode_dump + mode_layout + mode_extract + mode_inject +
2025 mode_setstrap + mode_newlayout + mode_spifreq + mode_em100 +
2026 mode_locked + mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002027 fprintf(stderr, "You need to specify a mode.\n\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002028 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002029 exit(EXIT_FAILURE);
2030 }
2031
2032 if (optind + 1 != argc) {
2033 fprintf(stderr, "You need to specify a file.\n\n");
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002034 fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002035 exit(EXIT_FAILURE);
2036 }
2037
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002038 if (platform == -1)
2039 fprintf(stderr, "Warning: No platform specified. Output may be incomplete\n");
2040
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002041 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06002042 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002043 if (bios_fd == -1) {
2044 perror("Could not open file");
2045 exit(EXIT_FAILURE);
2046 }
2047 struct stat buf;
2048 if (fstat(bios_fd, &buf) == -1) {
2049 perror("Could not stat file");
2050 exit(EXIT_FAILURE);
2051 }
2052 int size = buf.st_size;
2053
2054 printf("File %s is %d bytes\n", filename, size);
2055
2056 char *image = malloc(size);
2057 if (!image) {
2058 printf("Out of memory.\n");
2059 exit(EXIT_FAILURE);
2060 }
2061
2062 if (read(bios_fd, image, size) != size) {
2063 perror("Could not read file");
2064 exit(EXIT_FAILURE);
2065 }
2066
2067 close(bios_fd);
2068
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002069 // generate new filename
2070 if (new_filename == NULL) {
2071 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
2072 if (!new_filename) {
2073 printf("Out of memory.\n");
2074 exit(EXIT_FAILURE);
2075 }
2076 // - 5: leave room for ".new\0"
2077 strcpy(new_filename, filename);
2078 strcat(new_filename, ".new");
2079 }
2080
Duncan Laurie1f7fd722015-06-22 11:14:48 -07002081 check_ifd_version(image, size);
2082
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002083 if (mode_dump)
2084 dump_fd(image, size);
2085
Chris Douglass03ce0142014-02-26 13:30:13 -05002086 if (mode_layout)
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002087 dump_flashrom_layout(image, size, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -05002088
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002089 if (mode_extract)
2090 write_regions(image, size);
2091
Mathew Kingc7ddc992019-08-08 14:59:25 -06002092 if (mode_validate)
2093 validate_layout(image, size);
2094
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002095 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002096 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002097 region_fname);
2098
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002099 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002100 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05002101
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002102 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002103 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002104
Jan Tatjefa317512016-03-11 00:52:07 +01002105 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002106 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01002107
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002108 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002109 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07002110
Alexander Couzensd12ea112016-09-10 13:33:05 +02002111 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002112 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002113
Usha P412679d2020-10-15 11:25:08 +05302114 if (mode_read)
2115 enable_cpu_read_me(new_filename, image, size);
2116
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002117 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002118 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07002119
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002120 if (mode_setstrap) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002121 struct fpsba *fpsba = find_fpsba(image, size);
2122 const struct fdbar *fdb = find_fd(image, size);
Patrick Rudolph802cbee2020-05-25 12:18:11 +02002123 set_pchstrap(fpsba, fdb, pchstrap, value);
2124 write_image(new_filename, image, size);
2125 }
2126
Bill XIEb3e15a22017-09-07 18:34:50 +08002127 if (mode_altmedisable) {
Maximilian Bruneab0e6802023-03-05 04:34:40 +01002128 struct fpsba *fpsba = find_fpsba(image, size);
2129 struct fmsba *fmsba = find_fmsba(image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002130 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002131 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08002132 }
2133
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01002134 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002135 free(image);
2136
2137 return 0;
2138}