blob: 08a65b3ff53babc40fca650c6f60be284fddf2e8 [file] [log] [blame]
Patrick Georgiea063cb2020-05-08 19:28:13 +02001/* ifdtool - dump Intel Firmware Descriptor information */
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07002/*
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07003 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; version 2 of the License.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070011 */
12
13#include <unistd.h>
14#include <stdlib.h>
15#include <stdio.h>
16#include <string.h>
17#include <getopt.h>
18#include <fcntl.h>
19#include <sys/types.h>
20#include <sys/stat.h>
Bill XIE4651d452017-09-12 11:54:48 +080021#include <commonlib/helpers.h>
Mathew Kingc7ddc992019-08-08 14:59:25 -060022#include <fmap.h>
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070023#include "ifdtool.h"
24
Scott Duplichanf2c98372014-12-12 21:03:06 -060025#ifndef O_BINARY
26#define O_BINARY 0
27#endif
28
Bill XIE612ec0e2017-08-30 16:10:27 +080029/**
30 * PTR_IN_RANGE - examine whether a pointer falls in [base, base + limit)
31 * @param ptr: the non-void* pointer to a single arbitrary-sized object.
32 * @param base: base address represented with char* type.
33 * @param limit: upper limit of the legal address.
34 *
35 */
36#define PTR_IN_RANGE(ptr, base, limit) \
37 ((const char *)(ptr) >= (base) && \
38 (const char *)&(ptr)[1] <= (base) + (limit))
39
Duncan Laurie1f7fd722015-06-22 11:14:48 -070040static int ifd_version;
Bill XIEb3e15a22017-09-07 18:34:50 +080041static int chipset;
Bill XIEfa5f9942017-09-12 11:22:29 +080042static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010043static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070044static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050045
Duncan Laurie1f7fd722015-06-22 11:14:48 -070046static const struct region_name region_names[MAX_REGIONS] = {
Mathew Kingc7ddc992019-08-08 14:59:25 -060047 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin", "SI_DESC" },
48 { "BIOS", "bios", "flashregion_1_bios.bin", "SI_BIOS" },
49 { "Intel ME", "me", "flashregion_2_intel_me.bin", "SI_ME" },
50 { "GbE", "gbe", "flashregion_3_gbe.bin", "SI_GBE" },
51 { "Platform Data", "pd", "flashregion_4_platform_data.bin", "SI_PDR" },
52 { "Reserved", "res1", "flashregion_5_reserved.bin", NULL },
53 { "Reserved", "res2", "flashregion_6_reserved.bin", NULL },
54 { "Reserved", "res3", "flashregion_7_reserved.bin", NULL },
55 { "EC", "ec", "flashregion_8_ec.bin", "SI_EC" },
Chris Douglass03ce0142014-02-26 13:30:13 -050056};
57
Bill XIEb3e15a22017-09-07 18:34:50 +080058/* port from flashrom */
59static const char *const ich_chipset_names[] = {
60 "Unknown ICH",
61 "ICH",
62 "ICH2345",
63 "ICH6",
64 "SCH U",
65 "Atom E6xx",
66 "Atom S1220 S1240 S1260",
67 "ICH7",
68 "ICH8",
69 "ICH9",
70 "ICH10",
71 "5 series Ibex Peak",
72 "6 series Cougar Point",
73 "7 series Panther Point",
74 "8 series Lynx Point",
75 "Baytrail",
76 "8 series Lynx Point LP",
77 "8 series Wellsburg",
78 "9 series Wildcat Point",
79 "9 series Wildcat Point LP",
80 "100 series Sunrise Point",
81 "C620 series Lewisburg",
82 NULL
83};
84
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070085static fdbar_t *find_fd(char *image, int size)
86{
87 int i, found = 0;
88
89 /* Scan for FD signature */
90 for (i = 0; i < (size - 4); i += 4) {
91 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
92 found = 1;
93 break; // signature found.
94 }
95 }
96
97 if (!found) {
98 printf("No Flash Descriptor found in this image\n");
99 return NULL;
100 }
101
Bill XIE612ec0e2017-08-30 16:10:27 +0800102 fdbar_t *fdb = (fdbar_t *) (image + i);
103 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
104}
105
Stefan Tauner0d226142018-08-05 18:56:53 +0200106static char *find_flumap(char *image, int size)
107{
108 /* The upper map is located in the word before the 256B-long OEM section
109 * at the end of the 4kB-long flash descriptor. In the official
110 * documentation this is defined as FDBAR + 0xEFC. However, starting
111 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
112 * has moved 16 bytes back to offset 0x10 of the image. Although
113 * official documentation still maintains the offset relative to FDBAR
114 * this is wrong and a simple fixed offset from the start of the image
115 * works.
116 */
117 char *flumap = image + 4096 - 256 - 4;
118 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
119}
120
Bill XIE612ec0e2017-08-30 16:10:27 +0800121static fcba_t *find_fcba(char *image, int size)
122{
123 fdbar_t *fdb = find_fd(image, size);
124 if (!fdb)
125 return NULL;
126 fcba_t *fcba = (fcba_t *) (image + ((fdb->flmap0 & 0xff) << 4));
127 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
128
129}
130
131static fmba_t *find_fmba(char *image, int size)
132{
133 fdbar_t *fdb = find_fd(image, size);
134 if (!fdb)
135 return NULL;
136 fmba_t *fmba = (fmba_t *) (image + ((fdb->flmap1 & 0xff) << 4));
137 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
138}
139
140static frba_t *find_frba(char *image, int size)
141{
142 fdbar_t *fdb = find_fd(image, size);
143 if (!fdb)
144 return NULL;
145 frba_t *frba =
146 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
147 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
148}
149
150static fpsba_t *find_fpsba(char *image, int size)
151{
152 fdbar_t *fdb = find_fd(image, size);
153 if (!fdb)
154 return NULL;
155 fpsba_t *fpsba =
156 (fpsba_t *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
157 return PTR_IN_RANGE(fpsba, image, size) ? fpsba : NULL;
158}
159
160static fmsba_t *find_fmsba(char *image, int size)
161{
162 fdbar_t *fdb = find_fd(image, size);
163 if (!fdb)
164 return NULL;
165 fmsba_t *fmsba = (fmsba_t *) (image + ((fdb->flmap2 & 0xff) << 4));
166 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700167}
168
Bill XIEb3e15a22017-09-07 18:34:50 +0800169/* port from flashrom */
170static enum ich_chipset guess_ich_chipset(const fdbar_t *fdb)
171{
172 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
173 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
174 uint32_t isl = (fdb->flmap1 >> 24);
175 uint32_t nm = (fdb->flmap1 >> 8) & 0x7;
176
177 if (iccriba == 0x00) {
178 if (msl == 0 && isl <= 2)
179 return CHIPSET_ICH8;
180 else if (isl <= 2)
181 return CHIPSET_ICH9;
182 else if (isl <= 10)
183 return CHIPSET_ICH10;
184 else if (isl <= 16)
185 return CHIPSET_5_SERIES_IBEX_PEAK;
186 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
187 return CHIPSET_5_SERIES_IBEX_PEAK;
188 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
189 if (msl == 0 && isl <= 17)
190 return CHIPSET_BAYTRAIL;
191 else if (msl <= 1 && isl <= 18)
192 return CHIPSET_6_SERIES_COUGAR_POINT;
193 else if (msl <= 1 && isl <= 21)
194 return CHIPSET_8_SERIES_LYNX_POINT;
195 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
196 return CHIPSET_9_SERIES_WILDCAT_POINT;
197 } else if (nm == 6) {
198 return CHIPSET_C620_SERIES_LEWISBURG;
199 } else {
200 return CHIPSET_100_SERIES_SUNRISE_POINT;
201 }
202}
203
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700204/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700205 * Some newer platforms have re-defined the FCBA field that was used to
206 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
207 * have the required FCBA field, but are IFD v2 and return true if current
208 * platform is one of them.
209 */
210static int is_platform_ifd_2(void)
211{
212 static const int ifd_2_platforms[] = {
213 PLATFORM_GLK,
214 PLATFORM_CNL,
Aamir Bohra1018be22018-06-29 15:08:50 +0530215 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700216 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530217 PLATFORM_JSL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700218 };
219 unsigned int i;
220
221 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
222 if (platform == ifd_2_platforms[i])
223 return 1;
224 }
225
226 return 0;
227}
228
229/*
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700230 * There is no version field in the descriptor so to determine
231 * if this is a new descriptor format we check the hardcoded SPI
232 * read frequency to see if it is fixed at 20MHz or 17MHz.
233 */
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700234static int get_ifd_version_from_fcba(char *image, int size)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700235{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700236 int read_freq;
Bill XIE612ec0e2017-08-30 16:10:27 +0800237 const fcba_t *fcba = find_fcba(image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +0800238 const fdbar_t *fdb = find_fd(image, size);
Jacob Garber9bb04612019-05-08 13:40:45 -0600239 if (!fcba || !fdb)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700240 exit(EXIT_FAILURE);
241
Bill XIEb3e15a22017-09-07 18:34:50 +0800242 chipset = guess_ich_chipset(fdb);
243 /* TODO: port ifd_version and max_regions
244 * against guess_ich_chipset()
245 */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700246 read_freq = (fcba->flcomp >> 17) & 7;
247
248 switch (read_freq) {
249 case SPI_FREQUENCY_20MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700250 return IFD_VERSION_1;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700251 case SPI_FREQUENCY_17MHZ:
Hannah Williams589fc342016-10-06 14:29:48 -0700252 case SPI_FREQUENCY_50MHZ_30MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700253 return IFD_VERSION_2;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700254 default:
255 fprintf(stderr, "Unknown descriptor version: %d\n",
256 read_freq);
257 exit(EXIT_FAILURE);
258 }
259}
260
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700261static void check_ifd_version(char *image, int size)
262{
263 if (is_platform_ifd_2())
264 ifd_version = IFD_VERSION_2;
265 else
266 ifd_version = get_ifd_version_from_fcba(image, size);
267
268 if (ifd_version == IFD_VERSION_1)
269 max_regions = MAX_REGIONS_OLD;
270 else
271 max_regions = MAX_REGIONS;
272}
273
Bill XIEfa5f9942017-09-12 11:22:29 +0800274static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700275{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500276 int base_mask;
277 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700278 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700279 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500280
281 if (ifd_version >= IFD_VERSION_2)
282 base_mask = 0x7fff;
283 else
284 base_mask = 0xfff;
285
286 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700287
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400288 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800289 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700290 exit (EXIT_FAILURE);
291 }
292
Bill XIE4651d452017-09-12 11:54:48 +0800293 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700294 region.base = (flreg & base_mask) << 12;
295 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700296 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500297
Chris Douglass03ce0142014-02-26 13:30:13 -0500298 if (region.size < 0)
299 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700300
301 return region;
302}
303
Bill XIEfa5f9942017-09-12 11:22:29 +0800304static void set_region(frba_t *frba, unsigned int region_type,
305 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500306{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400307 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800308 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500309 exit (EXIT_FAILURE);
310 }
Bill XIE4651d452017-09-12 11:54:48 +0800311
312 frba->flreg[region_type] =
313 (((region->limit >> 12) & 0x7fff) << 16) |
314 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500315}
316
Bill XIEfa5f9942017-09-12 11:22:29 +0800317static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700318{
Bill XIEfa5f9942017-09-12 11:22:29 +0800319 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700320 fprintf(stderr, "Invalid region type.\n");
321 exit (EXIT_FAILURE);
322 }
323
Chris Douglass03ce0142014-02-26 13:30:13 -0500324 return region_names[region_type].pretty;
325}
326
Bill XIEfa5f9942017-09-12 11:22:29 +0800327static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500328{
Bill XIEfa5f9942017-09-12 11:22:29 +0800329 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500330 fprintf(stderr, "Invalid region type.\n");
331 exit (EXIT_FAILURE);
332 }
333
334 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700335}
336
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500337static int region_num(const char *name)
338{
Bill XIEfa5f9942017-09-12 11:22:29 +0800339 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500340
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200341 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500342 if (strcasecmp(name, region_names[i].pretty) == 0)
343 return i;
344 if (strcasecmp(name, region_names[i].terse) == 0)
345 return i;
346 }
347
348 return -1;
349}
350
Bill XIEfa5f9942017-09-12 11:22:29 +0800351static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700352{
Bill XIEfa5f9942017-09-12 11:22:29 +0800353 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700354 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700355 exit (EXIT_FAILURE);
356 }
357
Bill XIE1bf65062017-09-12 11:31:37 +0800358 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700359}
360
Bill XIEfa5f9942017-09-12 11:22:29 +0800361static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700362{
363 region_t region = get_region(frba, num);
364 printf(" Flash Region %d (%s): %08x - %08x %s\n",
365 num, region_name(num), region.base, region.limit,
366 region.size < 1 ? "(unused)" : "");
367}
368
Bill XIEfa5f9942017-09-12 11:22:29 +0800369static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
370 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500371{
372 region_t region = get_region(frba, num);
373 snprintf(buf, bufsize, "%08x:%08x %s\n",
374 region.base, region.limit, region_name_short(num));
375}
376
Bill XIEfa5f9942017-09-12 11:22:29 +0800377static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700378{
Bill XIE4651d452017-09-12 11:54:48 +0800379 unsigned int i;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700380 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800381 for (i = 0; i < max_regions; i++) {
382 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
383 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700384 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700385}
386
Bill XIEfa5f9942017-09-12 11:22:29 +0800387static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500388{
389 char buf[LAYOUT_LINELEN];
390 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800391 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500392
393 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
394 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
395 if (layout_fd == -1) {
396 perror("Could not open file");
397 exit(EXIT_FAILURE);
398 }
399
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200400 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200401 region_t region = get_region(frba, i);
402 /* is region invalid? */
403 if (region.size < 1)
404 continue;
405
Chris Douglass03ce0142014-02-26 13:30:13 -0500406 dump_region_layout(buf, bufsize, i, frba);
407 if (write(layout_fd, buf, strlen(buf)) < 0) {
408 perror("Could not write to file");
409 exit(EXIT_FAILURE);
410 }
411 }
412 close(layout_fd);
413 printf("Wrote layout to %s\n", layout_fname);
414}
415
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700416static void decode_spi_frequency(unsigned int freq)
417{
418 switch (freq) {
419 case SPI_FREQUENCY_20MHZ:
420 printf("20MHz");
421 break;
422 case SPI_FREQUENCY_33MHZ:
423 printf("33MHz");
424 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700425 case SPI_FREQUENCY_48MHZ:
426 printf("48MHz");
427 break;
428 case SPI_FREQUENCY_50MHZ_30MHZ:
429 switch (ifd_version) {
430 case IFD_VERSION_1:
431 printf("50MHz");
432 break;
433 case IFD_VERSION_2:
434 printf("30MHz");
435 break;
436 }
437 break;
438 case SPI_FREQUENCY_17MHZ:
439 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700440 break;
441 default:
442 printf("unknown<%x>MHz", freq);
443 }
444}
445
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700446static void decode_component_density(unsigned int density)
447{
448 switch (density) {
449 case COMPONENT_DENSITY_512KB:
450 printf("512KB");
451 break;
452 case COMPONENT_DENSITY_1MB:
453 printf("1MB");
454 break;
455 case COMPONENT_DENSITY_2MB:
456 printf("2MB");
457 break;
458 case COMPONENT_DENSITY_4MB:
459 printf("4MB");
460 break;
461 case COMPONENT_DENSITY_8MB:
462 printf("8MB");
463 break;
464 case COMPONENT_DENSITY_16MB:
465 printf("16MB");
466 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700467 case COMPONENT_DENSITY_32MB:
468 printf("32MB");
469 break;
470 case COMPONENT_DENSITY_64MB:
471 printf("64MB");
472 break;
473 case COMPONENT_DENSITY_UNUSED:
474 printf("UNUSED");
475 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700476 default:
477 printf("unknown<%x>MB", density);
478 }
479}
480
Bill XIEfa5f9942017-09-12 11:22:29 +0800481static void dump_fcba(const fcba_t *fcba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700482{
483 printf("\nFound Component Section\n");
484 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700485 printf(" Dual Output Fast Read Support: %ssupported\n",
486 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700487 printf(" Read ID/Read Status Clock Frequency: ");
488 decode_spi_frequency((fcba->flcomp >> 27) & 7);
489 printf("\n Write/Erase Clock Frequency: ");
490 decode_spi_frequency((fcba->flcomp >> 24) & 7);
491 printf("\n Fast Read Clock Frequency: ");
492 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700493 printf("\n Fast Read Support: %ssupported",
494 (fcba->flcomp & (1 << 20))?"":"not ");
495 printf("\n Read Clock Frequency: ");
496 decode_spi_frequency((fcba->flcomp >> 17) & 7);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700497
498 switch (ifd_version) {
499 case IFD_VERSION_1:
500 printf("\n Component 2 Density: ");
501 decode_component_density((fcba->flcomp >> 3) & 7);
502 printf("\n Component 1 Density: ");
503 decode_component_density(fcba->flcomp & 7);
504 break;
505 case IFD_VERSION_2:
506 printf("\n Component 2 Density: ");
507 decode_component_density((fcba->flcomp >> 4) & 0xf);
508 printf("\n Component 1 Density: ");
509 decode_component_density(fcba->flcomp & 0xf);
510 break;
511 }
512
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700513 printf("\n");
514 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700515 printf(" Invalid Instruction 3: 0x%02x\n",
516 (fcba->flill >> 24) & 0xff);
517 printf(" Invalid Instruction 2: 0x%02x\n",
518 (fcba->flill >> 16) & 0xff);
519 printf(" Invalid Instruction 1: 0x%02x\n",
520 (fcba->flill >> 8) & 0xff);
521 printf(" Invalid Instruction 0: 0x%02x\n",
522 fcba->flill & 0xff);
523 printf("FLPB 0x%08x\n", fcba->flpb);
524 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
525 (fcba->flpb & 0xfff) << 12);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700526}
527
Bill XIEfa5f9942017-09-12 11:22:29 +0800528static void dump_fpsba(const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700529{
Bill XIE4651d452017-09-12 11:54:48 +0800530 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700531 printf("Found PCH Strap Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800532 for (i = 0; i < ARRAY_SIZE(fpsba->pchstrp); i++)
533 printf("PCHSTRP%u:%s 0x%08x\n", i,
534 i < 10 ? " " : "", fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800535
536 if (ifd_version >= IFD_VERSION_2) {
537 printf("HAP bit is %sset\n",
538 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
539 } else if (chipset >= CHIPSET_ICH8
540 && chipset <= CHIPSET_ICH10) {
541 printf("ICH_MeDisable bit is %sset\n",
542 fpsba->pchstrp[0] & 1 ? "" : "not ");
543 } else {
544 printf("AltMeDisable bit is %sset\n",
545 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
546 }
547
Bill XIE4651d452017-09-12 11:54:48 +0800548 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700549}
550
551static void decode_flmstr(uint32_t flmstr)
552{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700553 int wr_shift, rd_shift;
554 if (ifd_version >= IFD_VERSION_2) {
555 wr_shift = FLMSTR_WR_SHIFT_V2;
556 rd_shift = FLMSTR_RD_SHIFT_V2;
557 } else {
558 wr_shift = FLMSTR_WR_SHIFT_V1;
559 rd_shift = FLMSTR_RD_SHIFT_V1;
560 }
561
562 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700563 if (ifd_version >= IFD_VERSION_2)
564 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700565 (flmstr & (1 << (wr_shift + 8))) ?
566 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700567 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700568 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700569 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700570 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700571 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700572 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700573 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700574 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700575 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700576 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700577
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700578 if (ifd_version >= IFD_VERSION_2)
579 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700580 (flmstr & (1 << (rd_shift + 8))) ?
581 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700582 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700583 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700584 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700585 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700586 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700587 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700588 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700589 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700590 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700591 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700592
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700593 /* Requestor ID doesn't exist for ifd 2 */
594 if (ifd_version < IFD_VERSION_2)
595 printf(" Requester ID: 0x%04x\n\n",
596 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700597}
598
Bill XIEfa5f9942017-09-12 11:22:29 +0800599static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700600{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700601 printf("Found Master Section\n");
602 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
603 decode_flmstr(fmba->flmstr1);
604 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
605 decode_flmstr(fmba->flmstr2);
606 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
607 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700608 if (ifd_version >= IFD_VERSION_2) {
609 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
610 decode_flmstr(fmba->flmstr5);
611 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700612}
613
Bill XIEfa5f9942017-09-12 11:22:29 +0800614static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700615{
Bill XIE612ec0e2017-08-30 16:10:27 +0800616 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700617 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800618 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
619 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800620
621 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
622 printf("MCH_MeDisable bit is %sset\n",
623 fmsba->data[0] & 1 ? "" : "not ");
624 printf("MCH_AltMeDisable bit is %sset\n",
625 fmsba->data[0] & (1 << 7) ? "" : "not ");
626 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700627}
628
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700629static void dump_jid(uint32_t jid)
630{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100631 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700632 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100633 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200634 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100635 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200636 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700637}
638
639static void dump_vscc(uint32_t vscc)
640{
641 printf(" Lower Erase Opcode: 0x%02x\n",
642 vscc >> 24);
643 printf(" Lower Write Enable on Write Status: 0x%02x\n",
644 vscc & (1 << 20) ? 0x06 : 0x50);
645 printf(" Lower Write Status Required: %s\n",
646 vscc & (1 << 19) ? "Yes" : "No");
647 printf(" Lower Write Granularity: %d bytes\n",
648 vscc & (1 << 18) ? 64 : 1);
649 printf(" Lower Block / Sector Erase Size: ");
650 switch ((vscc >> 16) & 0x3) {
651 case 0:
652 printf("256 Byte\n");
653 break;
654 case 1:
655 printf("4KB\n");
656 break;
657 case 2:
658 printf("8KB\n");
659 break;
660 case 3:
661 printf("64KB\n");
662 break;
663 }
664
665 printf(" Upper Erase Opcode: 0x%02x\n",
666 (vscc >> 8) & 0xff);
667 printf(" Upper Write Enable on Write Status: 0x%02x\n",
668 vscc & (1 << 4) ? 0x06 : 0x50);
669 printf(" Upper Write Status Required: %s\n",
670 vscc & (1 << 3) ? "Yes" : "No");
671 printf(" Upper Write Granularity: %d bytes\n",
672 vscc & (1 << 2) ? 64 : 1);
673 printf(" Upper Block / Sector Erase Size: ");
674 switch (vscc & 0x3) {
675 case 0:
676 printf("256 Byte\n");
677 break;
678 case 1:
679 printf("4KB\n");
680 break;
681 case 2:
682 printf("8KB\n");
683 break;
684 case 3:
685 printf("64KB\n");
686 break;
687 }
688}
689
Bill XIEfa5f9942017-09-12 11:22:29 +0800690static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700691{
692 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200693 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
694 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700695
696 printf("ME VSCC table:\n");
697 for (i = 0; i < num; i++) {
698 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
699 dump_jid(vtba->entry[i].jid);
700 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
701 dump_vscc(vtba->entry[i].vscc);
702 }
703 printf("\n");
704}
705
Bill XIEfa5f9942017-09-12 11:22:29 +0800706static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700707{
708 int i, j;
709 printf("OEM Section:\n");
710 for (i = 0; i < 4; i++) {
711 printf("%02x:", i << 4);
712 for (j = 0; j < 16; j++)
713 printf(" %02x", oem[(i<<4)+j]);
714 printf ("\n");
715 }
716 printf ("\n");
717}
718
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700719static void dump_fd(char *image, int size)
720{
Bill XIE612ec0e2017-08-30 16:10:27 +0800721 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700722 if (!fdb)
723 exit(EXIT_FAILURE);
724
Bill XIEb3e15a22017-09-07 18:34:50 +0800725 printf("ICH Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700726 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
727 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
728 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
729 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
730 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
731
732 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
733 printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
734 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
735 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
736 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
737
738 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
739 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
740 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
741
Stefan Tauner0d226142018-08-05 18:56:53 +0200742 char *flumap = find_flumap(image, size);
743 uint32_t flumap1 = *(uint32_t *)flumap;
744 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700745 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200746 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700747 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200748 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700749 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200750 (image + ((flumap1 & 0xff) << 4)),
751 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800752 dump_oem((const uint8_t *)image + 0xf00);
753
754 const frba_t *frba = find_frba(image, size);
755 const fcba_t *fcba = find_fcba(image, size);
756 const fpsba_t *fpsba = find_fpsba(image, size);
757 const fmba_t *fmba = find_fmba(image, size);
758 const fmsba_t *fmsba = find_fmsba(image, size);
759
760 if (frba && fcba && fpsba && fmba && fmsba) {
761 dump_frba(frba);
762 dump_fcba(fcba);
763 dump_fpsba(fpsba);
764 dump_fmba(fmba);
765 dump_fmsba(fmsba);
766 } else {
767 printf("FD is corrupted!\n");
768 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700769}
770
Bill XIEfa5f9942017-09-12 11:22:29 +0800771static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500772{
Bill XIE612ec0e2017-08-30 16:10:27 +0800773 const frba_t *frba = find_frba(image, size);
774 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500775 exit(EXIT_FAILURE);
776
Bill XIE612ec0e2017-08-30 16:10:27 +0800777 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500778}
779
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700780static void write_regions(char *image, int size)
781{
Bill XIEfa5f9942017-09-12 11:22:29 +0800782 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800783 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700784
Bill XIE612ec0e2017-08-30 16:10:27 +0800785 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700786 exit(EXIT_FAILURE);
787
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700788 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700789 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700790 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700791 if (region.size > 0) {
792 int region_fd;
793 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600794 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700795 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200796 if (region_fd < 0) {
797 perror("Error while trying to open file");
798 exit(EXIT_FAILURE);
799 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700800 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700801 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700802 close(region_fd);
803 }
804 }
805}
806
Mathew Kingc7ddc992019-08-08 14:59:25 -0600807static void validate_layout(char *image, int size)
808{
809 uint i, errors = 0;
810 struct fmap *fmap;
811 long int fmap_loc = fmap_find((uint8_t *)image, size);
812 const frba_t *frba = find_frba(image, size);
813
814 if (fmap_loc < 0 || !frba)
815 exit(EXIT_FAILURE);
816
817 fmap = (struct fmap *)(image + fmap_loc);
818
819 for (i = 0; i < max_regions; i++) {
820 if (region_names[i].fmapname == NULL)
821 continue;
822
823 region_t region = get_region(frba, i);
824
825 if (region.size == 0)
826 continue;
827
828 const struct fmap_area *area =
829 fmap_find_area(fmap, region_names[i].fmapname);
830
831 if (!area)
832 continue;
833
834 if ((uint)region.base != area->offset ||
835 (uint)region.size != area->size) {
836 printf("Region mismatch between %s and %s\n",
837 region_names[i].terse, area->name);
838 printf(" Descriptor region %s:\n", region_names[i].terse);
839 printf(" offset: 0x%08x\n", region.base);
840 printf(" length: 0x%08x\n", region.size);
841 printf(" FMAP area %s:\n", area->name);
842 printf(" offset: 0x%08x\n", area->offset);
843 printf(" length: 0x%08x\n", area->size);
844 errors++;
845 }
846 }
847
848 if (errors > 0)
849 exit(EXIT_FAILURE);
850}
851
Bill XIEfa5f9942017-09-12 11:22:29 +0800852static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700853{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700854 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100855 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700856
857 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100858 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600859 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700860 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200861 if (new_fd < 0) {
862 perror("Error while trying to open file");
863 exit(EXIT_FAILURE);
864 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700865 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700866 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700867 close(new_fd);
868}
869
Bill XIEfa5f9942017-09-12 11:22:29 +0800870static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700871 enum spi_frequency freq)
872{
Bill XIE612ec0e2017-08-30 16:10:27 +0800873 fcba_t *fcba = find_fcba(image, size);
874 if (!fcba)
875 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700876
877 /* clear bits 21-29 */
878 fcba->flcomp &= ~0x3fe00000;
879 /* Read ID and Read Status Clock Frequency */
880 fcba->flcomp |= freq << 27;
881 /* Write and Erase Clock Frequency */
882 fcba->flcomp |= freq << 24;
883 /* Fast Read Clock Frequency */
884 fcba->flcomp |= freq << 21;
885
886 write_image(filename, image, size);
887}
888
Bill XIEfa5f9942017-09-12 11:22:29 +0800889static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700890{
Bill XIE612ec0e2017-08-30 16:10:27 +0800891 fcba_t *fcba = find_fcba(image, size);
892 if (!fcba)
893 exit(EXIT_FAILURE);
894
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700895 int freq;
896
897 switch (ifd_version) {
898 case IFD_VERSION_1:
899 freq = SPI_FREQUENCY_20MHZ;
900 break;
901 case IFD_VERSION_2:
902 freq = SPI_FREQUENCY_17MHZ;
903 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -0700904 default:
905 freq = SPI_FREQUENCY_17MHZ;
906 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700907 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700908
909 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700910 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700911}
912
Bill XIEfa5f9942017-09-12 11:22:29 +0800913static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +0100914 unsigned int density)
915{
Bill XIE612ec0e2017-08-30 16:10:27 +0800916 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200917 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +0800918 if (!fcba)
919 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +0100920
921 printf("Setting chip density to ");
922 decode_component_density(density);
923 printf("\n");
924
925 switch (ifd_version) {
926 case IFD_VERSION_1:
927 /* fail if selected density is not supported by this version */
928 if ( (density == COMPONENT_DENSITY_32MB) ||
929 (density == COMPONENT_DENSITY_64MB) ||
930 (density == COMPONENT_DENSITY_UNUSED) ) {
931 printf("error: Selected density not supported in IFD version 1.\n");
932 exit(EXIT_FAILURE);
933 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200934 mask = 0x7;
935 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +0100936 break;
937 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200938 mask = 0xf;
939 chip2_offset = 4;
940 break;
Jan Tatjefa317512016-03-11 00:52:07 +0100941 default:
942 printf("error: Unknown IFD version\n");
943 exit(EXIT_FAILURE);
944 break;
945 }
946
947 /* clear chip density for corresponding chip */
948 switch (selected_chip) {
949 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200950 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +0100951 break;
952 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200953 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +0100954 break;
955 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200956 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +0100957 break;
958 }
959
960 /* set the new density */
961 if (selected_chip == 1 || selected_chip == 0)
962 fcba->flcomp |= (density); /* first chip */
963 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200964 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +0100965
966 write_image(filename, image, size);
967}
968
Duncan Laurie7775d672019-06-06 13:39:26 -0700969static int check_region(const frba_t *frba, unsigned int region_type)
970{
971 region_t region;
972
973 if (!frba)
974 return 0;
975
976 region = get_region(frba, region_type);
977 return !!((region.base < region.limit) && (region.size > 0));
978}
979
Bill XIEfa5f9942017-09-12 11:22:29 +0800980static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700981{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700982 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +0800983 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -0700984 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800985 if (!fmba)
986 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700987
988 if (ifd_version >= IFD_VERSION_2) {
989 wr_shift = FLMSTR_WR_SHIFT_V2;
990 rd_shift = FLMSTR_RD_SHIFT_V2;
991
992 /* Clear non-reserved bits */
993 fmba->flmstr1 &= 0xff;
994 fmba->flmstr2 &= 0xff;
995 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -0800996 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700997 } else {
998 wr_shift = FLMSTR_WR_SHIFT_V1;
999 rd_shift = FLMSTR_RD_SHIFT_V1;
1000
1001 fmba->flmstr1 = 0;
1002 fmba->flmstr2 = 0;
1003 /* Requestor ID */
1004 fmba->flmstr3 = 0x118;
1005 }
1006
Andrey Petrov96ecb772016-10-31 19:31:54 -07001007 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001008 case PLATFORM_APL:
1009 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001010 /* CPU/BIOS can read descriptor and BIOS */
1011 fmba->flmstr1 |= 0x3 << rd_shift;
1012 /* CPU/BIOS can write BIOS */
1013 fmba->flmstr1 |= 0x2 << wr_shift;
1014 /* TXE can read descriptor, BIOS and Device Expansion */
1015 fmba->flmstr2 |= 0x23 << rd_shift;
1016 /* TXE can only write Device Expansion */
1017 fmba->flmstr2 |= 0x20 << wr_shift;
1018 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001019 case PLATFORM_CNL:
1020 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001021 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001022 case PLATFORM_TGL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001023 /* CPU/BIOS can read descriptor and BIOS. */
1024 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1025 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1026 /* CPU/BIOS can write BIOS. */
1027 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1028 /* ME can read descriptor and ME. */
1029 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1030 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001031 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001032 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1033 if (check_region(frba, REGION_GBE)) {
1034 /* BIOS can read/write GbE. */
1035 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1036 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1037 /* ME can read GbE. */
1038 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1039 /* GbE can read descriptor and read/write GbE.. */
1040 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1041 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1042 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1043 }
1044 if (check_region(frba, REGION_PDR)) {
1045 /* BIOS can read/write PDR. */
1046 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1047 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1048 }
1049 if (check_region(frba, REGION_EC)) {
1050 /* BIOS can read EC. */
1051 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1052 /* EC can read descriptor and read/write EC. */
1053 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1054 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1055 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1056 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001057 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001058 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001059 /* CPU/BIOS can read descriptor and BIOS. */
1060 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1061 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1062 /* CPU/BIOS can write BIOS. */
1063 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1064 /* ME can read descriptor and ME. */
1065 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1066 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1067 /* ME can write ME. */
1068 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1069 if (check_region(frba, REGION_GBE)) {
1070 /* BIOS can read GbE. */
1071 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1072 /* BIOS can write GbE. */
1073 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1074 /* ME can read GbE. */
1075 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1076 /* ME can write GbE. */
1077 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1078 /* GbE can write GbE. */
1079 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1080 /* GbE can read GbE. */
1081 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1082 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001083 break;
1084 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001085
1086 write_image(filename, image, size);
1087}
1088
Bill XIEfa5f9942017-09-12 11:22:29 +08001089static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001090{
Bill XIE612ec0e2017-08-30 16:10:27 +08001091 fmba_t *fmba = find_fmba(image, size);
1092 if (!fmba)
1093 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001094
1095 if (ifd_version >= IFD_VERSION_2) {
1096 /* Access bits for each region are read: 19:8 write: 31:20 */
1097 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1098 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1099 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001100 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001101 } else {
1102 fmba->flmstr1 = 0xffff0000;
1103 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001104 /* Keep chipset specific Requester ID */
1105 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001106 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001107
1108 write_image(filename, image, size);
1109}
1110
Bill XIEb3e15a22017-09-07 18:34:50 +08001111/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001112static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001113{
1114 if (ifd_version >= IFD_VERSION_2) {
1115 printf("%sting the HAP bit to %s Intel ME...\n",
1116 altmedisable?"Set":"Unset",
1117 altmedisable?"disable":"enable");
1118 if (altmedisable)
1119 fpsba->pchstrp[0] |= (1 << 16);
1120 else
1121 fpsba->pchstrp[0] &= ~(1 << 16);
1122 } else {
1123 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1124 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1125 "and MCH_AltMeDisable to %s Intel ME...\n",
1126 altmedisable?"Set":"Unset",
1127 altmedisable?"disable":"enable");
1128 if (altmedisable) {
1129 /* MCH_MeDisable */
1130 fmsba->data[0] |= 1;
1131 /* MCH_AltMeDisable */
1132 fmsba->data[0] |= (1 << 7);
1133 /* ICH_MeDisable */
1134 fpsba->pchstrp[0] |= 1;
1135 } else {
1136 fmsba->data[0] &= ~1;
1137 fmsba->data[0] &= ~(1 << 7);
1138 fpsba->pchstrp[0] &= ~1;
1139 }
1140 } else {
1141 printf("%sting the AltMeDisable to %s Intel ME...\n",
1142 altmedisable?"Set":"Unset",
1143 altmedisable?"disable":"enable");
1144 if (altmedisable)
1145 fpsba->pchstrp[10] |= (1 << 7);
1146 else
1147 fpsba->pchstrp[10] &= ~(1 << 7);
1148 }
1149 }
1150}
1151
Jacob Garber595d9262019-06-27 17:33:10 -06001152static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001153 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001154{
Bill XIE612ec0e2017-08-30 16:10:27 +08001155 frba_t *frba = find_frba(image, size);
1156 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001157 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001158
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001159 region_t region = get_region(frba, region_type);
1160 if (region.size <= 0xfff) {
1161 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1162 region_name(region_type));
1163 exit(EXIT_FAILURE);
1164 }
1165
Scott Duplichanf2c98372014-12-12 21:03:06 -06001166 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001167 if (region_fd == -1) {
1168 perror("Could not open file");
1169 exit(EXIT_FAILURE);
1170 }
1171 struct stat buf;
1172 if (fstat(region_fd, &buf) == -1) {
1173 perror("Could not stat file");
1174 exit(EXIT_FAILURE);
1175 }
1176 int region_size = buf.st_size;
1177
1178 printf("File %s is %d bytes\n", region_fname, region_size);
1179
1180 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001181 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001182 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1183 " bytes. Not injecting.\n",
1184 region_name(region_type), region.size,
1185 region.size, region_size, region_size);
1186 exit(EXIT_FAILURE);
1187 }
1188
1189 int offset = 0;
1190 if ((region_type == 1) && (region_size < region.size)) {
1191 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1192 " bytes. Padding before injecting.\n",
1193 region_name(region_type), region.size,
1194 region.size, region_size, region_size);
1195 offset = region.size - region_size;
1196 memset(image + region.base, 0xff, offset);
1197 }
1198
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001199 if (size < region.base + offset + region_size) {
1200 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1201 size, region.base + offset + region_size);
1202 exit(EXIT_FAILURE);
1203 }
1204
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001205 if (read(region_fd, image + region.base + offset, region_size)
1206 != region_size) {
1207 perror("Could not read file");
1208 exit(EXIT_FAILURE);
1209 }
1210
1211 close(region_fd);
1212
1213 printf("Adding %s as the %s section of %s\n",
1214 region_fname, region_name(region_type), filename);
1215 write_image(filename, image, size);
1216}
1217
Jacob Garber595d9262019-06-27 17:33:10 -06001218static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001219{
1220 unsigned int y = 1;
1221 if (x == 0)
1222 return 0;
1223 while (y <= x)
1224 y = y << 1;
1225
1226 return y;
1227}
1228
1229/**
1230 * Determine if two memory regions overlap.
1231 *
1232 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001233 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001234 * @return 1 if the two regions overlap
1235 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001236static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001237{
Bill XIEfa5f9942017-09-12 11:22:29 +08001238 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001239 return 0;
1240
Nico Huber844eda02019-01-05 00:06:19 +01001241 /* r1 should be either completely below or completely above r2 */
1242 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001243}
1244
Jacob Garber595d9262019-06-27 17:33:10 -06001245static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001246 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001247{
1248 FILE *romlayout;
1249 char tempstr[256];
1250 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001251 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001252 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001253 region_t current_regions[MAX_REGIONS];
1254 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001255 int new_extent = 0;
1256 char *new_image;
1257
1258 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001259 frba_t *frba = find_frba(image, size);
1260 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001261 exit(EXIT_FAILURE);
1262
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001263 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001264 current_regions[i] = get_region(frba, i);
1265 new_regions[i] = get_region(frba, i);
1266 }
1267
1268 /* read new layout */
1269 romlayout = fopen(layout_fname, "r");
1270
1271 if (!romlayout) {
1272 perror("Could not read layout file.\n");
1273 exit(EXIT_FAILURE);
1274 }
1275
1276 while (!feof(romlayout)) {
1277 char *tstr1, *tstr2;
1278
Patrick Georgi802ad522014-08-09 17:12:23 +02001279 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001280 layout_region_name))
1281 continue;
1282
1283 region_number = region_num(layout_region_name);
1284 if (region_number < 0)
1285 continue;
1286
1287 tstr1 = strtok(tempstr, ":");
1288 tstr2 = strtok(NULL, ":");
1289 if (!tstr1 || !tstr2) {
1290 fprintf(stderr, "Could not parse layout file.\n");
1291 exit(EXIT_FAILURE);
1292 }
1293 new_regions[region_number].base = strtol(tstr1,
1294 (char **)NULL, 16);
1295 new_regions[region_number].limit = strtol(tstr2,
1296 (char **)NULL, 16);
1297 new_regions[region_number].size =
1298 new_regions[region_number].limit -
1299 new_regions[region_number].base + 1;
1300
1301 if (new_regions[region_number].size < 0)
1302 new_regions[region_number].size = 0;
1303 }
1304 fclose(romlayout);
1305
1306 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001307 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001308 if (new_regions[i].size == 0)
1309 continue;
1310
1311 if (new_regions[i].size < current_regions[i].size) {
1312 printf("DANGER: Region %s is shrinking.\n",
1313 region_name(i));
1314 printf(" The region will be truncated to fit.\n");
1315 printf(" This may result in an unusable image.\n");
1316 }
1317
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001318 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001319 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001320 fprintf(stderr, "Regions would overlap.\n");
1321 exit(EXIT_FAILURE);
1322 }
1323 }
1324
1325 /* detect if the image size should grow */
1326 if (new_extent < new_regions[i].limit)
1327 new_extent = new_regions[i].limit;
1328 }
1329
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001330 /* check if the image is actually a Flash Descriptor region */
1331 if (size == new_regions[0].size) {
1332 printf("The image is a single Flash Descriptor:\n");
1333 printf(" Only the descriptor will be modified\n");
1334 new_extent = size;
1335 } else {
1336 new_extent = next_pow2(new_extent - 1);
1337 if (new_extent != size) {
1338 printf("The image has changed in size.\n");
1339 printf("The old image is %d bytes.\n", size);
1340 printf("The new image is %d bytes.\n", new_extent);
1341 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001342 }
1343
1344 /* copy regions to a new image */
1345 new_image = malloc(new_extent);
1346 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001347 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001348 int copy_size = new_regions[i].size;
1349 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001350 const region_t *current = &current_regions[i];
1351 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001352
Bill XIEfa5f9942017-09-12 11:22:29 +08001353 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001354 continue;
1355
Bill XIEfa5f9942017-09-12 11:22:29 +08001356 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001357 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001358 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001359 if (i == REGION_BIOS)
1360 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001361 }
1362
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001363 if ((i == REGION_BIOS) && (new->size < current->size)) {
1364 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001365 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001366 }
1367
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001368 if (size < current->base + offset_current + copy_size) {
1369 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1370 region_name(i));
1371 continue;
1372 };
1373
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001374 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1375 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001376 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1377 offset_current, current->limit, current->size);
1378 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1379 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001380
Bill XIEfa5f9942017-09-12 11:22:29 +08001381 memcpy(new_image + new->base + offset_new,
1382 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001383 copy_size);
1384 }
1385
1386 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001387 frba = find_frba(new_image, new_extent);
1388 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001389 exit(EXIT_FAILURE);
1390
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001391 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001392 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001393 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001394
1395 write_image(filename, new_image, new_extent);
1396 free(new_image);
1397}
1398
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001399static void print_version(void)
1400{
1401 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1402 printf("Copyright (C) 2011 Google Inc.\n\n");
1403 printf
1404 ("This program is free software: you can redistribute it and/or modify\n"
1405 "it under the terms of the GNU General Public License as published by\n"
1406 "the Free Software Foundation, version 2 of the License.\n\n"
1407 "This program is distributed in the hope that it will be useful,\n"
1408 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1409 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001410 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001411}
1412
1413static void print_usage(const char *name)
1414{
1415 printf("usage: %s [-vhdix?] <filename>\n", name);
1416 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001417 " -d | --dump: dump intel firmware descriptor\n"
1418 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1419 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1420 " -x | --extract: extract intel fd modules\n"
1421 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1422 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001423 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001424 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1425 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1426 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1427 " can only be used once per run:\n"
1428 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1429 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1430 " Dual Output Fast Read Support\n"
1431 " -l | --lock Lock firmware descriptor and ME region\n"
1432 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001433 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1434 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001435 " -p | --platform Add platform-specific quirks\n"
1436 " aplk - Apollo Lake\n"
1437 " cnl - Cannon Lake\n"
1438 " glk - Gemini Lake\n"
1439 " sklkbl - Skylake/Kaby Lake\n"
1440 " -v | --version: print the version\n"
1441 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001442 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1443 "\n");
1444}
1445
1446int main(int argc, char *argv[])
1447{
1448 int opt, option_index = 0;
1449 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001450 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001451 int mode_layout = 0, mode_newlayout = 0, mode_density = 0;
Bill XIEb3e15a22017-09-07 18:34:50 +08001452 int mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001453 char *region_type_string = NULL, *region_fname = NULL;
1454 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001455 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001456 int region_type = -1, inputfreq = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001457 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001458 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1459
Bill XIEfa5f9942017-09-12 11:22:29 +08001460 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001461 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001462 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001463 {"extract", 0, NULL, 'x'},
1464 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001465 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001466 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001467 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001468 {"density", 1, NULL, 'D'},
1469 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001470 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001471 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001472 {"lock", 0, NULL, 'l'},
1473 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001474 {"version", 0, NULL, 'v'},
1475 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001476 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001477 {"validate", 0, NULL, 't'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001478 {0, 0, 0, 0}
1479 };
1480
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001481 while ((opt = getopt_long(argc, argv, "df:D:C:M:xi:n:O:s:p:eluvth?",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001482 long_options, &option_index)) != EOF) {
1483 switch (opt) {
1484 case 'd':
1485 mode_dump = 1;
1486 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001487 case 'f':
1488 mode_layout = 1;
1489 layout_fname = strdup(optarg);
1490 if (!layout_fname) {
1491 fprintf(stderr, "No layout file specified\n");
1492 print_usage(argv[0]);
1493 exit(EXIT_FAILURE);
1494 }
1495 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001496 case 'x':
1497 mode_extract = 1;
1498 break;
1499 case 'i':
1500 // separate type and file name
1501 region_type_string = strdup(optarg);
1502 region_fname = strchr(region_type_string, ':');
1503 if (!region_fname) {
1504 print_usage(argv[0]);
1505 exit(EXIT_FAILURE);
1506 }
1507 region_fname[0] = '\0';
1508 region_fname++;
1509 // Descriptor, BIOS, ME, GbE, Platform
1510 // valid type?
1511 if (!strcasecmp("Descriptor", region_type_string))
1512 region_type = 0;
1513 else if (!strcasecmp("BIOS", region_type_string))
1514 region_type = 1;
1515 else if (!strcasecmp("ME", region_type_string))
1516 region_type = 2;
1517 else if (!strcasecmp("GbE", region_type_string))
1518 region_type = 3;
1519 else if (!strcasecmp("Platform", region_type_string))
1520 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001521 else if (!strcasecmp("EC", region_type_string))
1522 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001523 if (region_type == -1) {
1524 fprintf(stderr, "No such region type: '%s'\n\n",
1525 region_type_string);
1526 print_usage(argv[0]);
1527 exit(EXIT_FAILURE);
1528 }
1529 mode_inject = 1;
1530 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001531 case 'n':
1532 mode_newlayout = 1;
1533 layout_fname = strdup(optarg);
1534 if (!layout_fname) {
1535 fprintf(stderr, "No layout file specified\n");
1536 print_usage(argv[0]);
1537 exit(EXIT_FAILURE);
1538 }
1539 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001540 case 'O':
1541 new_filename = strdup(optarg);
1542 if (!new_filename) {
1543 fprintf(stderr, "No output filename specified\n");
1544 print_usage(argv[0]);
1545 exit(EXIT_FAILURE);
1546 }
1547 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001548 case 'D':
1549 mode_density = 1;
1550 new_density = strtoul(optarg, NULL, 0);
1551 switch (new_density) {
1552 case 512:
1553 new_density = COMPONENT_DENSITY_512KB;
1554 break;
1555 case 1:
1556 new_density = COMPONENT_DENSITY_1MB;
1557 break;
1558 case 2:
1559 new_density = COMPONENT_DENSITY_2MB;
1560 break;
1561 case 4:
1562 new_density = COMPONENT_DENSITY_4MB;
1563 break;
1564 case 8:
1565 new_density = COMPONENT_DENSITY_8MB;
1566 break;
1567 case 16:
1568 new_density = COMPONENT_DENSITY_16MB;
1569 break;
1570 case 32:
1571 new_density = COMPONENT_DENSITY_32MB;
1572 break;
1573 case 64:
1574 new_density = COMPONENT_DENSITY_64MB;
1575 break;
1576 case 0:
1577 new_density = COMPONENT_DENSITY_UNUSED;
1578 break;
1579 default:
1580 printf("error: Unknown density\n");
1581 print_usage(argv[0]);
1582 exit(EXIT_FAILURE);
1583 }
1584 break;
1585 case 'C':
1586 selected_chip = strtol(optarg, NULL, 0);
1587 if (selected_chip > 2) {
1588 fprintf(stderr, "error: Invalid chip selection\n");
1589 print_usage(argv[0]);
1590 exit(EXIT_FAILURE);
1591 }
1592 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001593 case 'M':
1594 mode_altmedisable = 1;
1595 altmedisable = strtol(optarg, NULL, 0);
1596 if (altmedisable > 1) {
1597 fprintf(stderr, "error: Illegal value\n");
1598 print_usage(argv[0]);
1599 exit(EXIT_FAILURE);
1600 }
1601 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001602 case 's':
1603 // Parse the requested SPI frequency
1604 inputfreq = strtol(optarg, NULL, 0);
1605 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001606 case 17:
1607 spifreq = SPI_FREQUENCY_17MHZ;
1608 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001609 case 20:
1610 spifreq = SPI_FREQUENCY_20MHZ;
1611 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001612 case 30:
1613 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1614 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001615 case 33:
1616 spifreq = SPI_FREQUENCY_33MHZ;
1617 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001618 case 48:
1619 spifreq = SPI_FREQUENCY_48MHZ;
1620 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001621 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001622 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001623 break;
1624 default:
1625 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1626 inputfreq);
1627 print_usage(argv[0]);
1628 exit(EXIT_FAILURE);
1629 }
1630 mode_spifreq = 1;
1631 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001632 case 'e':
1633 mode_em100 = 1;
1634 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001635 case 'l':
1636 mode_locked = 1;
1637 if (mode_unlocked == 1) {
1638 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1639 exit(EXIT_FAILURE);
1640 }
1641 break;
1642 case 'u':
1643 mode_unlocked = 1;
1644 if (mode_locked == 1) {
1645 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1646 exit(EXIT_FAILURE);
1647 }
1648 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001649 case 'p':
1650 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001651 platform = PLATFORM_APL;
1652 } else if (!strcmp(optarg, "cnl")) {
1653 platform = PLATFORM_CNL;
1654 } else if (!strcmp(optarg, "glk")) {
1655 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301656 } else if (!strcmp(optarg, "icl")) {
1657 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301658 } else if (!strcmp(optarg, "jsl")) {
1659 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001660 } else if (!strcmp(optarg, "sklkbl")) {
1661 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001662 } else if (!strcmp(optarg, "tgl")) {
1663 platform = PLATFORM_TGL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001664 } else {
1665 fprintf(stderr, "Unknown platform: %s\n", optarg);
1666 exit(EXIT_FAILURE);
1667 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001668 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001669 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001670 case 't':
1671 mode_validate = 1;
1672 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001673 case 'v':
1674 print_version();
1675 exit(EXIT_SUCCESS);
1676 break;
1677 case 'h':
1678 case '?':
1679 default:
1680 print_usage(argv[0]);
1681 exit(EXIT_SUCCESS);
1682 break;
1683 }
1684 }
1685
Chris Douglass03ce0142014-02-26 13:30:13 -05001686 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001687 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001688 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001689 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001690 print_usage(argv[0]);
1691 exit(EXIT_FAILURE);
1692 }
1693
Chris Douglass03ce0142014-02-26 13:30:13 -05001694 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001695 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001696 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001697 fprintf(stderr, "You need to specify a mode.\n\n");
1698 print_usage(argv[0]);
1699 exit(EXIT_FAILURE);
1700 }
1701
1702 if (optind + 1 != argc) {
1703 fprintf(stderr, "You need to specify a file.\n\n");
1704 print_usage(argv[0]);
1705 exit(EXIT_FAILURE);
1706 }
1707
1708 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001709 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001710 if (bios_fd == -1) {
1711 perror("Could not open file");
1712 exit(EXIT_FAILURE);
1713 }
1714 struct stat buf;
1715 if (fstat(bios_fd, &buf) == -1) {
1716 perror("Could not stat file");
1717 exit(EXIT_FAILURE);
1718 }
1719 int size = buf.st_size;
1720
1721 printf("File %s is %d bytes\n", filename, size);
1722
1723 char *image = malloc(size);
1724 if (!image) {
1725 printf("Out of memory.\n");
1726 exit(EXIT_FAILURE);
1727 }
1728
1729 if (read(bios_fd, image, size) != size) {
1730 perror("Could not read file");
1731 exit(EXIT_FAILURE);
1732 }
1733
1734 close(bios_fd);
1735
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001736 // generate new filename
1737 if (new_filename == NULL) {
1738 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1739 if (!new_filename) {
1740 printf("Out of memory.\n");
1741 exit(EXIT_FAILURE);
1742 }
1743 // - 5: leave room for ".new\0"
1744 strcpy(new_filename, filename);
1745 strcat(new_filename, ".new");
1746 }
1747
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001748 check_ifd_version(image, size);
1749
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001750 if (mode_dump)
1751 dump_fd(image, size);
1752
Chris Douglass03ce0142014-02-26 13:30:13 -05001753 if (mode_layout)
1754 dump_layout(image, size, layout_fname);
1755
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001756 if (mode_extract)
1757 write_regions(image, size);
1758
Mathew Kingc7ddc992019-08-08 14:59:25 -06001759 if (mode_validate)
1760 validate_layout(image, size);
1761
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001762 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001763 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001764 region_fname);
1765
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001766 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001767 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001768
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001769 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001770 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001771
Jan Tatjefa317512016-03-11 00:52:07 +01001772 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001773 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01001774
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001775 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001776 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001777
Alexander Couzensd12ea112016-09-10 13:33:05 +02001778 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001779 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001780
1781 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001782 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001783
Bill XIEb3e15a22017-09-07 18:34:50 +08001784 if (mode_altmedisable) {
1785 fpsba_t *fpsba = find_fpsba(image, size);
1786 fmsba_t *fmsba = find_fmsba(image, size);
1787 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001788 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08001789 }
1790
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001791 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001792 free(image);
1793
1794 return 0;
1795}