blob: fcc760e807f11212173c269c9897512a217b69c8 [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
Duncan Laurie1f7fd722015-06-22 11:14:48 -070031static int ifd_version;
Bill XIEb3e15a22017-09-07 18:34:50 +080032static int chipset;
Bill XIEfa5f9942017-09-12 11:22:29 +080033static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010034static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070035static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050036
Duncan Laurie1f7fd722015-06-22 11:14:48 -070037static const struct region_name region_names[MAX_REGIONS] = {
Mathew Kingc7ddc992019-08-08 14:59:25 -060038 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin", "SI_DESC" },
39 { "BIOS", "bios", "flashregion_1_bios.bin", "SI_BIOS" },
40 { "Intel ME", "me", "flashregion_2_intel_me.bin", "SI_ME" },
41 { "GbE", "gbe", "flashregion_3_gbe.bin", "SI_GBE" },
42 { "Platform Data", "pd", "flashregion_4_platform_data.bin", "SI_PDR" },
43 { "Reserved", "res1", "flashregion_5_reserved.bin", NULL },
44 { "Reserved", "res2", "flashregion_6_reserved.bin", NULL },
45 { "Reserved", "res3", "flashregion_7_reserved.bin", NULL },
46 { "EC", "ec", "flashregion_8_ec.bin", "SI_EC" },
Chris Douglass03ce0142014-02-26 13:30:13 -050047};
48
Bill XIEb3e15a22017-09-07 18:34:50 +080049/* port from flashrom */
50static const char *const ich_chipset_names[] = {
51 "Unknown ICH",
52 "ICH",
53 "ICH2345",
54 "ICH6",
55 "SCH U",
56 "Atom E6xx",
57 "Atom S1220 S1240 S1260",
58 "ICH7",
59 "ICH8",
60 "ICH9",
61 "ICH10",
62 "5 series Ibex Peak",
63 "6 series Cougar Point",
64 "7 series Panther Point",
65 "8 series Lynx Point",
66 "Baytrail",
67 "8 series Lynx Point LP",
68 "8 series Wellsburg",
69 "9 series Wildcat Point",
70 "9 series Wildcat Point LP",
71 "100 series Sunrise Point",
72 "C620 series Lewisburg",
73 NULL
74};
75
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070076static fdbar_t *find_fd(char *image, int size)
77{
78 int i, found = 0;
79
80 /* Scan for FD signature */
81 for (i = 0; i < (size - 4); i += 4) {
82 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
83 found = 1;
84 break; // signature found.
85 }
86 }
87
88 if (!found) {
89 printf("No Flash Descriptor found in this image\n");
90 return NULL;
91 }
92
Bill XIE612ec0e2017-08-30 16:10:27 +080093 fdbar_t *fdb = (fdbar_t *) (image + i);
94 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
95}
96
Stefan Tauner0d226142018-08-05 18:56:53 +020097static char *find_flumap(char *image, int size)
98{
99 /* The upper map is located in the word before the 256B-long OEM section
100 * at the end of the 4kB-long flash descriptor. In the official
101 * documentation this is defined as FDBAR + 0xEFC. However, starting
102 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
103 * has moved 16 bytes back to offset 0x10 of the image. Although
104 * official documentation still maintains the offset relative to FDBAR
105 * this is wrong and a simple fixed offset from the start of the image
106 * works.
107 */
108 char *flumap = image + 4096 - 256 - 4;
109 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
110}
111
Bill XIE612ec0e2017-08-30 16:10:27 +0800112static fcba_t *find_fcba(char *image, int size)
113{
114 fdbar_t *fdb = find_fd(image, size);
115 if (!fdb)
116 return NULL;
117 fcba_t *fcba = (fcba_t *) (image + ((fdb->flmap0 & 0xff) << 4));
118 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
119
120}
121
122static fmba_t *find_fmba(char *image, int size)
123{
124 fdbar_t *fdb = find_fd(image, size);
125 if (!fdb)
126 return NULL;
127 fmba_t *fmba = (fmba_t *) (image + ((fdb->flmap1 & 0xff) << 4));
128 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
129}
130
131static frba_t *find_frba(char *image, int size)
132{
133 fdbar_t *fdb = find_fd(image, size);
134 if (!fdb)
135 return NULL;
136 frba_t *frba =
137 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
138 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
139}
140
141static fpsba_t *find_fpsba(char *image, int size)
142{
143 fdbar_t *fdb = find_fd(image, size);
144 if (!fdb)
145 return NULL;
146 fpsba_t *fpsba =
147 (fpsba_t *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
148 return PTR_IN_RANGE(fpsba, image, size) ? fpsba : NULL;
149}
150
151static fmsba_t *find_fmsba(char *image, int size)
152{
153 fdbar_t *fdb = find_fd(image, size);
154 if (!fdb)
155 return NULL;
156 fmsba_t *fmsba = (fmsba_t *) (image + ((fdb->flmap2 & 0xff) << 4));
157 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700158}
159
Bill XIEb3e15a22017-09-07 18:34:50 +0800160/* port from flashrom */
161static enum ich_chipset guess_ich_chipset(const fdbar_t *fdb)
162{
163 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
164 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
165 uint32_t isl = (fdb->flmap1 >> 24);
166 uint32_t nm = (fdb->flmap1 >> 8) & 0x7;
167
168 if (iccriba == 0x00) {
169 if (msl == 0 && isl <= 2)
170 return CHIPSET_ICH8;
171 else if (isl <= 2)
172 return CHIPSET_ICH9;
173 else if (isl <= 10)
174 return CHIPSET_ICH10;
175 else if (isl <= 16)
176 return CHIPSET_5_SERIES_IBEX_PEAK;
177 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
178 return CHIPSET_5_SERIES_IBEX_PEAK;
179 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
180 if (msl == 0 && isl <= 17)
181 return CHIPSET_BAYTRAIL;
182 else if (msl <= 1 && isl <= 18)
183 return CHIPSET_6_SERIES_COUGAR_POINT;
184 else if (msl <= 1 && isl <= 21)
185 return CHIPSET_8_SERIES_LYNX_POINT;
186 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
187 return CHIPSET_9_SERIES_WILDCAT_POINT;
188 } else if (nm == 6) {
189 return CHIPSET_C620_SERIES_LEWISBURG;
190 } else {
191 return CHIPSET_100_SERIES_SUNRISE_POINT;
192 }
193}
194
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700195/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700196 * Some newer platforms have re-defined the FCBA field that was used to
197 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
198 * have the required FCBA field, but are IFD v2 and return true if current
199 * platform is one of them.
200 */
201static int is_platform_ifd_2(void)
202{
203 static const int ifd_2_platforms[] = {
204 PLATFORM_GLK,
205 PLATFORM_CNL,
Aamir Bohra1018be22018-06-29 15:08:50 +0530206 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700207 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530208 PLATFORM_JSL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700209 };
210 unsigned int i;
211
212 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
213 if (platform == ifd_2_platforms[i])
214 return 1;
215 }
216
217 return 0;
218}
219
220/*
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700221 * There is no version field in the descriptor so to determine
222 * if this is a new descriptor format we check the hardcoded SPI
223 * read frequency to see if it is fixed at 20MHz or 17MHz.
224 */
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700225static int get_ifd_version_from_fcba(char *image, int size)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700226{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700227 int read_freq;
Bill XIE612ec0e2017-08-30 16:10:27 +0800228 const fcba_t *fcba = find_fcba(image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +0800229 const fdbar_t *fdb = find_fd(image, size);
Jacob Garber9bb04612019-05-08 13:40:45 -0600230 if (!fcba || !fdb)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700231 exit(EXIT_FAILURE);
232
Bill XIEb3e15a22017-09-07 18:34:50 +0800233 chipset = guess_ich_chipset(fdb);
234 /* TODO: port ifd_version and max_regions
235 * against guess_ich_chipset()
236 */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700237 read_freq = (fcba->flcomp >> 17) & 7;
238
239 switch (read_freq) {
240 case SPI_FREQUENCY_20MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700241 return IFD_VERSION_1;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700242 case SPI_FREQUENCY_17MHZ:
Hannah Williams589fc342016-10-06 14:29:48 -0700243 case SPI_FREQUENCY_50MHZ_30MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700244 return IFD_VERSION_2;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700245 default:
246 fprintf(stderr, "Unknown descriptor version: %d\n",
247 read_freq);
248 exit(EXIT_FAILURE);
249 }
250}
251
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700252static void check_ifd_version(char *image, int size)
253{
254 if (is_platform_ifd_2())
255 ifd_version = IFD_VERSION_2;
256 else
257 ifd_version = get_ifd_version_from_fcba(image, size);
258
259 if (ifd_version == IFD_VERSION_1)
260 max_regions = MAX_REGIONS_OLD;
261 else
262 max_regions = MAX_REGIONS;
263}
264
Bill XIEfa5f9942017-09-12 11:22:29 +0800265static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700266{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500267 int base_mask;
268 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700269 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700270 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500271
272 if (ifd_version >= IFD_VERSION_2)
273 base_mask = 0x7fff;
274 else
275 base_mask = 0xfff;
276
277 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700278
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400279 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800280 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700281 exit (EXIT_FAILURE);
282 }
283
Bill XIE4651d452017-09-12 11:54:48 +0800284 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700285 region.base = (flreg & base_mask) << 12;
286 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700287 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500288
Chris Douglass03ce0142014-02-26 13:30:13 -0500289 if (region.size < 0)
290 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700291
292 return region;
293}
294
Bill XIEfa5f9942017-09-12 11:22:29 +0800295static void set_region(frba_t *frba, unsigned int region_type,
296 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500297{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400298 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800299 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500300 exit (EXIT_FAILURE);
301 }
Bill XIE4651d452017-09-12 11:54:48 +0800302
303 frba->flreg[region_type] =
304 (((region->limit >> 12) & 0x7fff) << 16) |
305 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500306}
307
Bill XIEfa5f9942017-09-12 11:22:29 +0800308static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700309{
Bill XIEfa5f9942017-09-12 11:22:29 +0800310 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700311 fprintf(stderr, "Invalid region type.\n");
312 exit (EXIT_FAILURE);
313 }
314
Chris Douglass03ce0142014-02-26 13:30:13 -0500315 return region_names[region_type].pretty;
316}
317
Bill XIEfa5f9942017-09-12 11:22:29 +0800318static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500319{
Bill XIEfa5f9942017-09-12 11:22:29 +0800320 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500321 fprintf(stderr, "Invalid region type.\n");
322 exit (EXIT_FAILURE);
323 }
324
325 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700326}
327
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500328static int region_num(const char *name)
329{
Bill XIEfa5f9942017-09-12 11:22:29 +0800330 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500331
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200332 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500333 if (strcasecmp(name, region_names[i].pretty) == 0)
334 return i;
335 if (strcasecmp(name, region_names[i].terse) == 0)
336 return i;
337 }
338
339 return -1;
340}
341
Bill XIEfa5f9942017-09-12 11:22:29 +0800342static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700343{
Bill XIEfa5f9942017-09-12 11:22:29 +0800344 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700345 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700346 exit (EXIT_FAILURE);
347 }
348
Bill XIE1bf65062017-09-12 11:31:37 +0800349 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700350}
351
Bill XIEfa5f9942017-09-12 11:22:29 +0800352static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700353{
354 region_t region = get_region(frba, num);
355 printf(" Flash Region %d (%s): %08x - %08x %s\n",
356 num, region_name(num), region.base, region.limit,
357 region.size < 1 ? "(unused)" : "");
358}
359
Bill XIEfa5f9942017-09-12 11:22:29 +0800360static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
361 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500362{
363 region_t region = get_region(frba, num);
364 snprintf(buf, bufsize, "%08x:%08x %s\n",
365 region.base, region.limit, region_name_short(num));
366}
367
Bill XIEfa5f9942017-09-12 11:22:29 +0800368static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700369{
Bill XIE4651d452017-09-12 11:54:48 +0800370 unsigned int i;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700371 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800372 for (i = 0; i < max_regions; i++) {
373 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
374 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700375 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700376}
377
Bill XIEfa5f9942017-09-12 11:22:29 +0800378static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500379{
380 char buf[LAYOUT_LINELEN];
381 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800382 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500383
384 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
385 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
386 if (layout_fd == -1) {
387 perror("Could not open file");
388 exit(EXIT_FAILURE);
389 }
390
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200391 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200392 region_t region = get_region(frba, i);
393 /* is region invalid? */
394 if (region.size < 1)
395 continue;
396
Chris Douglass03ce0142014-02-26 13:30:13 -0500397 dump_region_layout(buf, bufsize, i, frba);
398 if (write(layout_fd, buf, strlen(buf)) < 0) {
399 perror("Could not write to file");
400 exit(EXIT_FAILURE);
401 }
402 }
403 close(layout_fd);
404 printf("Wrote layout to %s\n", layout_fname);
405}
406
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700407static void decode_spi_frequency(unsigned int freq)
408{
409 switch (freq) {
410 case SPI_FREQUENCY_20MHZ:
411 printf("20MHz");
412 break;
413 case SPI_FREQUENCY_33MHZ:
414 printf("33MHz");
415 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700416 case SPI_FREQUENCY_48MHZ:
417 printf("48MHz");
418 break;
419 case SPI_FREQUENCY_50MHZ_30MHZ:
420 switch (ifd_version) {
421 case IFD_VERSION_1:
422 printf("50MHz");
423 break;
424 case IFD_VERSION_2:
425 printf("30MHz");
426 break;
427 }
428 break;
429 case SPI_FREQUENCY_17MHZ:
430 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700431 break;
432 default:
433 printf("unknown<%x>MHz", freq);
434 }
435}
436
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700437static void decode_component_density(unsigned int density)
438{
439 switch (density) {
440 case COMPONENT_DENSITY_512KB:
441 printf("512KB");
442 break;
443 case COMPONENT_DENSITY_1MB:
444 printf("1MB");
445 break;
446 case COMPONENT_DENSITY_2MB:
447 printf("2MB");
448 break;
449 case COMPONENT_DENSITY_4MB:
450 printf("4MB");
451 break;
452 case COMPONENT_DENSITY_8MB:
453 printf("8MB");
454 break;
455 case COMPONENT_DENSITY_16MB:
456 printf("16MB");
457 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700458 case COMPONENT_DENSITY_32MB:
459 printf("32MB");
460 break;
461 case COMPONENT_DENSITY_64MB:
462 printf("64MB");
463 break;
464 case COMPONENT_DENSITY_UNUSED:
465 printf("UNUSED");
466 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700467 default:
468 printf("unknown<%x>MB", density);
469 }
470}
471
Bill XIEfa5f9942017-09-12 11:22:29 +0800472static void dump_fcba(const fcba_t *fcba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700473{
474 printf("\nFound Component Section\n");
475 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700476 printf(" Dual Output Fast Read Support: %ssupported\n",
477 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700478 printf(" Read ID/Read Status Clock Frequency: ");
479 decode_spi_frequency((fcba->flcomp >> 27) & 7);
480 printf("\n Write/Erase Clock Frequency: ");
481 decode_spi_frequency((fcba->flcomp >> 24) & 7);
482 printf("\n Fast Read Clock Frequency: ");
483 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700484 printf("\n Fast Read Support: %ssupported",
485 (fcba->flcomp & (1 << 20))?"":"not ");
486 printf("\n Read Clock Frequency: ");
487 decode_spi_frequency((fcba->flcomp >> 17) & 7);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700488
489 switch (ifd_version) {
490 case IFD_VERSION_1:
491 printf("\n Component 2 Density: ");
492 decode_component_density((fcba->flcomp >> 3) & 7);
493 printf("\n Component 1 Density: ");
494 decode_component_density(fcba->flcomp & 7);
495 break;
496 case IFD_VERSION_2:
497 printf("\n Component 2 Density: ");
498 decode_component_density((fcba->flcomp >> 4) & 0xf);
499 printf("\n Component 1 Density: ");
500 decode_component_density(fcba->flcomp & 0xf);
501 break;
502 }
503
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700504 printf("\n");
505 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700506 printf(" Invalid Instruction 3: 0x%02x\n",
507 (fcba->flill >> 24) & 0xff);
508 printf(" Invalid Instruction 2: 0x%02x\n",
509 (fcba->flill >> 16) & 0xff);
510 printf(" Invalid Instruction 1: 0x%02x\n",
511 (fcba->flill >> 8) & 0xff);
512 printf(" Invalid Instruction 0: 0x%02x\n",
513 fcba->flill & 0xff);
514 printf("FLPB 0x%08x\n", fcba->flpb);
515 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
516 (fcba->flpb & 0xfff) << 12);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700517}
518
Bill XIEfa5f9942017-09-12 11:22:29 +0800519static void dump_fpsba(const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700520{
Bill XIE4651d452017-09-12 11:54:48 +0800521 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700522 printf("Found PCH Strap Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800523 for (i = 0; i < ARRAY_SIZE(fpsba->pchstrp); i++)
524 printf("PCHSTRP%u:%s 0x%08x\n", i,
525 i < 10 ? " " : "", fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800526
527 if (ifd_version >= IFD_VERSION_2) {
528 printf("HAP bit is %sset\n",
529 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
530 } else if (chipset >= CHIPSET_ICH8
531 && chipset <= CHIPSET_ICH10) {
532 printf("ICH_MeDisable bit is %sset\n",
533 fpsba->pchstrp[0] & 1 ? "" : "not ");
534 } else {
535 printf("AltMeDisable bit is %sset\n",
536 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
537 }
538
Bill XIE4651d452017-09-12 11:54:48 +0800539 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700540}
541
542static void decode_flmstr(uint32_t flmstr)
543{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700544 int wr_shift, rd_shift;
545 if (ifd_version >= IFD_VERSION_2) {
546 wr_shift = FLMSTR_WR_SHIFT_V2;
547 rd_shift = FLMSTR_RD_SHIFT_V2;
548 } else {
549 wr_shift = FLMSTR_WR_SHIFT_V1;
550 rd_shift = FLMSTR_RD_SHIFT_V1;
551 }
552
553 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700554 if (ifd_version >= IFD_VERSION_2)
555 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700556 (flmstr & (1 << (wr_shift + 8))) ?
557 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700558 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700559 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700560 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700561 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700562 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700563 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700564 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700565 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700566 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700567 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700568
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700569 if (ifd_version >= IFD_VERSION_2)
570 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700571 (flmstr & (1 << (rd_shift + 8))) ?
572 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700573 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700574 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700575 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700576 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700577 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700578 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700579 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700580 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700581 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700582 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700583
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700584 /* Requestor ID doesn't exist for ifd 2 */
585 if (ifd_version < IFD_VERSION_2)
586 printf(" Requester ID: 0x%04x\n\n",
587 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700588}
589
Bill XIEfa5f9942017-09-12 11:22:29 +0800590static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700591{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700592 printf("Found Master Section\n");
593 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
594 decode_flmstr(fmba->flmstr1);
595 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
596 decode_flmstr(fmba->flmstr2);
597 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
598 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700599 if (ifd_version >= IFD_VERSION_2) {
600 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
601 decode_flmstr(fmba->flmstr5);
602 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700603}
604
Bill XIEfa5f9942017-09-12 11:22:29 +0800605static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700606{
Bill XIE612ec0e2017-08-30 16:10:27 +0800607 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700608 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800609 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
610 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800611
612 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
613 printf("MCH_MeDisable bit is %sset\n",
614 fmsba->data[0] & 1 ? "" : "not ");
615 printf("MCH_AltMeDisable bit is %sset\n",
616 fmsba->data[0] & (1 << 7) ? "" : "not ");
617 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700618}
619
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700620static void dump_jid(uint32_t jid)
621{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100622 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700623 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100624 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200625 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100626 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200627 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700628}
629
630static void dump_vscc(uint32_t vscc)
631{
632 printf(" Lower Erase Opcode: 0x%02x\n",
633 vscc >> 24);
634 printf(" Lower Write Enable on Write Status: 0x%02x\n",
635 vscc & (1 << 20) ? 0x06 : 0x50);
636 printf(" Lower Write Status Required: %s\n",
637 vscc & (1 << 19) ? "Yes" : "No");
638 printf(" Lower Write Granularity: %d bytes\n",
639 vscc & (1 << 18) ? 64 : 1);
640 printf(" Lower Block / Sector Erase Size: ");
641 switch ((vscc >> 16) & 0x3) {
642 case 0:
643 printf("256 Byte\n");
644 break;
645 case 1:
646 printf("4KB\n");
647 break;
648 case 2:
649 printf("8KB\n");
650 break;
651 case 3:
652 printf("64KB\n");
653 break;
654 }
655
656 printf(" Upper Erase Opcode: 0x%02x\n",
657 (vscc >> 8) & 0xff);
658 printf(" Upper Write Enable on Write Status: 0x%02x\n",
659 vscc & (1 << 4) ? 0x06 : 0x50);
660 printf(" Upper Write Status Required: %s\n",
661 vscc & (1 << 3) ? "Yes" : "No");
662 printf(" Upper Write Granularity: %d bytes\n",
663 vscc & (1 << 2) ? 64 : 1);
664 printf(" Upper Block / Sector Erase Size: ");
665 switch (vscc & 0x3) {
666 case 0:
667 printf("256 Byte\n");
668 break;
669 case 1:
670 printf("4KB\n");
671 break;
672 case 2:
673 printf("8KB\n");
674 break;
675 case 3:
676 printf("64KB\n");
677 break;
678 }
679}
680
Bill XIEfa5f9942017-09-12 11:22:29 +0800681static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700682{
683 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200684 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
685 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700686
687 printf("ME VSCC table:\n");
688 for (i = 0; i < num; i++) {
689 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
690 dump_jid(vtba->entry[i].jid);
691 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
692 dump_vscc(vtba->entry[i].vscc);
693 }
694 printf("\n");
695}
696
Bill XIEfa5f9942017-09-12 11:22:29 +0800697static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700698{
699 int i, j;
700 printf("OEM Section:\n");
701 for (i = 0; i < 4; i++) {
702 printf("%02x:", i << 4);
703 for (j = 0; j < 16; j++)
704 printf(" %02x", oem[(i<<4)+j]);
705 printf ("\n");
706 }
707 printf ("\n");
708}
709
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700710static void dump_fd(char *image, int size)
711{
Bill XIE612ec0e2017-08-30 16:10:27 +0800712 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700713 if (!fdb)
714 exit(EXIT_FAILURE);
715
Bill XIEb3e15a22017-09-07 18:34:50 +0800716 printf("ICH Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700717 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
718 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
719 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
720 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
721 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
722
723 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
724 printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
725 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
726 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
727 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
728
729 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
730 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
731 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
732
Stefan Tauner0d226142018-08-05 18:56:53 +0200733 char *flumap = find_flumap(image, size);
734 uint32_t flumap1 = *(uint32_t *)flumap;
735 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700736 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200737 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700738 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200739 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700740 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200741 (image + ((flumap1 & 0xff) << 4)),
742 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800743 dump_oem((const uint8_t *)image + 0xf00);
744
745 const frba_t *frba = find_frba(image, size);
746 const fcba_t *fcba = find_fcba(image, size);
747 const fpsba_t *fpsba = find_fpsba(image, size);
748 const fmba_t *fmba = find_fmba(image, size);
749 const fmsba_t *fmsba = find_fmsba(image, size);
750
751 if (frba && fcba && fpsba && fmba && fmsba) {
752 dump_frba(frba);
753 dump_fcba(fcba);
754 dump_fpsba(fpsba);
755 dump_fmba(fmba);
756 dump_fmsba(fmsba);
757 } else {
758 printf("FD is corrupted!\n");
759 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700760}
761
Bill XIEfa5f9942017-09-12 11:22:29 +0800762static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500763{
Bill XIE612ec0e2017-08-30 16:10:27 +0800764 const frba_t *frba = find_frba(image, size);
765 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500766 exit(EXIT_FAILURE);
767
Bill XIE612ec0e2017-08-30 16:10:27 +0800768 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500769}
770
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700771static void write_regions(char *image, int size)
772{
Bill XIEfa5f9942017-09-12 11:22:29 +0800773 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800774 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700775
Bill XIE612ec0e2017-08-30 16:10:27 +0800776 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700777 exit(EXIT_FAILURE);
778
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700779 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700780 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700781 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700782 if (region.size > 0) {
783 int region_fd;
784 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600785 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700786 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200787 if (region_fd < 0) {
788 perror("Error while trying to open file");
789 exit(EXIT_FAILURE);
790 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700791 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700792 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700793 close(region_fd);
794 }
795 }
796}
797
Mathew Kingc7ddc992019-08-08 14:59:25 -0600798static void validate_layout(char *image, int size)
799{
800 uint i, errors = 0;
801 struct fmap *fmap;
802 long int fmap_loc = fmap_find((uint8_t *)image, size);
803 const frba_t *frba = find_frba(image, size);
804
805 if (fmap_loc < 0 || !frba)
806 exit(EXIT_FAILURE);
807
808 fmap = (struct fmap *)(image + fmap_loc);
809
810 for (i = 0; i < max_regions; i++) {
811 if (region_names[i].fmapname == NULL)
812 continue;
813
814 region_t region = get_region(frba, i);
815
816 if (region.size == 0)
817 continue;
818
819 const struct fmap_area *area =
820 fmap_find_area(fmap, region_names[i].fmapname);
821
822 if (!area)
823 continue;
824
825 if ((uint)region.base != area->offset ||
826 (uint)region.size != area->size) {
827 printf("Region mismatch between %s and %s\n",
828 region_names[i].terse, area->name);
829 printf(" Descriptor region %s:\n", region_names[i].terse);
830 printf(" offset: 0x%08x\n", region.base);
831 printf(" length: 0x%08x\n", region.size);
832 printf(" FMAP area %s:\n", area->name);
833 printf(" offset: 0x%08x\n", area->offset);
834 printf(" length: 0x%08x\n", area->size);
835 errors++;
836 }
837 }
838
839 if (errors > 0)
840 exit(EXIT_FAILURE);
841}
842
Bill XIEfa5f9942017-09-12 11:22:29 +0800843static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700844{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700845 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100846 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700847
848 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100849 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600850 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700851 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200852 if (new_fd < 0) {
853 perror("Error while trying to open file");
854 exit(EXIT_FAILURE);
855 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700856 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700857 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700858 close(new_fd);
859}
860
Bill XIEfa5f9942017-09-12 11:22:29 +0800861static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700862 enum spi_frequency freq)
863{
Bill XIE612ec0e2017-08-30 16:10:27 +0800864 fcba_t *fcba = find_fcba(image, size);
865 if (!fcba)
866 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700867
868 /* clear bits 21-29 */
869 fcba->flcomp &= ~0x3fe00000;
870 /* Read ID and Read Status Clock Frequency */
871 fcba->flcomp |= freq << 27;
872 /* Write and Erase Clock Frequency */
873 fcba->flcomp |= freq << 24;
874 /* Fast Read Clock Frequency */
875 fcba->flcomp |= freq << 21;
876
877 write_image(filename, image, size);
878}
879
Bill XIEfa5f9942017-09-12 11:22:29 +0800880static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700881{
Bill XIE612ec0e2017-08-30 16:10:27 +0800882 fcba_t *fcba = find_fcba(image, size);
883 if (!fcba)
884 exit(EXIT_FAILURE);
885
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700886 int freq;
887
888 switch (ifd_version) {
889 case IFD_VERSION_1:
890 freq = SPI_FREQUENCY_20MHZ;
891 break;
892 case IFD_VERSION_2:
893 freq = SPI_FREQUENCY_17MHZ;
894 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -0700895 default:
896 freq = SPI_FREQUENCY_17MHZ;
897 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700898 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700899
900 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700901 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700902}
903
Bill XIEfa5f9942017-09-12 11:22:29 +0800904static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +0100905 unsigned int density)
906{
Bill XIE612ec0e2017-08-30 16:10:27 +0800907 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200908 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +0800909 if (!fcba)
910 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +0100911
912 printf("Setting chip density to ");
913 decode_component_density(density);
914 printf("\n");
915
916 switch (ifd_version) {
917 case IFD_VERSION_1:
918 /* fail if selected density is not supported by this version */
919 if ( (density == COMPONENT_DENSITY_32MB) ||
920 (density == COMPONENT_DENSITY_64MB) ||
921 (density == COMPONENT_DENSITY_UNUSED) ) {
922 printf("error: Selected density not supported in IFD version 1.\n");
923 exit(EXIT_FAILURE);
924 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200925 mask = 0x7;
926 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +0100927 break;
928 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200929 mask = 0xf;
930 chip2_offset = 4;
931 break;
Jan Tatjefa317512016-03-11 00:52:07 +0100932 default:
933 printf("error: Unknown IFD version\n");
934 exit(EXIT_FAILURE);
935 break;
936 }
937
938 /* clear chip density for corresponding chip */
939 switch (selected_chip) {
940 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200941 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +0100942 break;
943 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200944 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +0100945 break;
946 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200947 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +0100948 break;
949 }
950
951 /* set the new density */
952 if (selected_chip == 1 || selected_chip == 0)
953 fcba->flcomp |= (density); /* first chip */
954 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200955 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +0100956
957 write_image(filename, image, size);
958}
959
Duncan Laurie7775d672019-06-06 13:39:26 -0700960static int check_region(const frba_t *frba, unsigned int region_type)
961{
962 region_t region;
963
964 if (!frba)
965 return 0;
966
967 region = get_region(frba, region_type);
968 return !!((region.base < region.limit) && (region.size > 0));
969}
970
Bill XIEfa5f9942017-09-12 11:22:29 +0800971static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700972{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700973 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +0800974 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -0700975 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800976 if (!fmba)
977 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700978
979 if (ifd_version >= IFD_VERSION_2) {
980 wr_shift = FLMSTR_WR_SHIFT_V2;
981 rd_shift = FLMSTR_RD_SHIFT_V2;
982
983 /* Clear non-reserved bits */
984 fmba->flmstr1 &= 0xff;
985 fmba->flmstr2 &= 0xff;
986 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -0800987 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700988 } else {
989 wr_shift = FLMSTR_WR_SHIFT_V1;
990 rd_shift = FLMSTR_RD_SHIFT_V1;
991
992 fmba->flmstr1 = 0;
993 fmba->flmstr2 = 0;
994 /* Requestor ID */
995 fmba->flmstr3 = 0x118;
996 }
997
Andrey Petrov96ecb772016-10-31 19:31:54 -0700998 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700999 case PLATFORM_APL:
1000 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001001 /* CPU/BIOS can read descriptor and BIOS */
1002 fmba->flmstr1 |= 0x3 << rd_shift;
1003 /* CPU/BIOS can write BIOS */
1004 fmba->flmstr1 |= 0x2 << wr_shift;
1005 /* TXE can read descriptor, BIOS and Device Expansion */
1006 fmba->flmstr2 |= 0x23 << rd_shift;
1007 /* TXE can only write Device Expansion */
1008 fmba->flmstr2 |= 0x20 << wr_shift;
1009 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001010 case PLATFORM_CNL:
1011 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001012 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001013 case PLATFORM_TGL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001014 /* CPU/BIOS can read descriptor and BIOS. */
1015 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1016 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1017 /* CPU/BIOS can write BIOS. */
1018 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1019 /* ME can read descriptor and ME. */
1020 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1021 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001022 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001023 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1024 if (check_region(frba, REGION_GBE)) {
1025 /* BIOS can read/write GbE. */
1026 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1027 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1028 /* ME can read GbE. */
1029 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1030 /* GbE can read descriptor and read/write GbE.. */
1031 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1032 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1033 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1034 }
1035 if (check_region(frba, REGION_PDR)) {
1036 /* BIOS can read/write PDR. */
1037 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1038 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1039 }
1040 if (check_region(frba, REGION_EC)) {
1041 /* BIOS can read EC. */
1042 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1043 /* EC can read descriptor and read/write EC. */
1044 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1045 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1046 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1047 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001048 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001049 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001050 /* CPU/BIOS can read descriptor and BIOS. */
1051 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1052 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1053 /* CPU/BIOS can write BIOS. */
1054 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1055 /* ME can read descriptor and ME. */
1056 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1057 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1058 /* ME can write ME. */
1059 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1060 if (check_region(frba, REGION_GBE)) {
1061 /* BIOS can read GbE. */
1062 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1063 /* BIOS can write GbE. */
1064 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1065 /* ME can read GbE. */
1066 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1067 /* ME can write GbE. */
1068 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1069 /* GbE can write GbE. */
1070 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1071 /* GbE can read GbE. */
1072 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1073 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001074 break;
1075 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001076
1077 write_image(filename, image, size);
1078}
1079
Bill XIEfa5f9942017-09-12 11:22:29 +08001080static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001081{
Bill XIE612ec0e2017-08-30 16:10:27 +08001082 fmba_t *fmba = find_fmba(image, size);
1083 if (!fmba)
1084 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001085
1086 if (ifd_version >= IFD_VERSION_2) {
1087 /* Access bits for each region are read: 19:8 write: 31:20 */
1088 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1089 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1090 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001091 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001092 } else {
1093 fmba->flmstr1 = 0xffff0000;
1094 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001095 /* Keep chipset specific Requester ID */
1096 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001097 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001098
1099 write_image(filename, image, size);
1100}
1101
Bill XIEb3e15a22017-09-07 18:34:50 +08001102/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001103static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001104{
1105 if (ifd_version >= IFD_VERSION_2) {
1106 printf("%sting the HAP bit to %s Intel ME...\n",
1107 altmedisable?"Set":"Unset",
1108 altmedisable?"disable":"enable");
1109 if (altmedisable)
1110 fpsba->pchstrp[0] |= (1 << 16);
1111 else
1112 fpsba->pchstrp[0] &= ~(1 << 16);
1113 } else {
1114 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1115 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1116 "and MCH_AltMeDisable to %s Intel ME...\n",
1117 altmedisable?"Set":"Unset",
1118 altmedisable?"disable":"enable");
1119 if (altmedisable) {
1120 /* MCH_MeDisable */
1121 fmsba->data[0] |= 1;
1122 /* MCH_AltMeDisable */
1123 fmsba->data[0] |= (1 << 7);
1124 /* ICH_MeDisable */
1125 fpsba->pchstrp[0] |= 1;
1126 } else {
1127 fmsba->data[0] &= ~1;
1128 fmsba->data[0] &= ~(1 << 7);
1129 fpsba->pchstrp[0] &= ~1;
1130 }
1131 } else {
1132 printf("%sting the AltMeDisable to %s Intel ME...\n",
1133 altmedisable?"Set":"Unset",
1134 altmedisable?"disable":"enable");
1135 if (altmedisable)
1136 fpsba->pchstrp[10] |= (1 << 7);
1137 else
1138 fpsba->pchstrp[10] &= ~(1 << 7);
1139 }
1140 }
1141}
1142
Jacob Garber595d9262019-06-27 17:33:10 -06001143static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001144 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001145{
Bill XIE612ec0e2017-08-30 16:10:27 +08001146 frba_t *frba = find_frba(image, size);
1147 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001148 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001149
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001150 region_t region = get_region(frba, region_type);
1151 if (region.size <= 0xfff) {
1152 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1153 region_name(region_type));
1154 exit(EXIT_FAILURE);
1155 }
1156
Scott Duplichanf2c98372014-12-12 21:03:06 -06001157 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001158 if (region_fd == -1) {
1159 perror("Could not open file");
1160 exit(EXIT_FAILURE);
1161 }
1162 struct stat buf;
1163 if (fstat(region_fd, &buf) == -1) {
1164 perror("Could not stat file");
1165 exit(EXIT_FAILURE);
1166 }
1167 int region_size = buf.st_size;
1168
1169 printf("File %s is %d bytes\n", region_fname, region_size);
1170
1171 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001172 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001173 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1174 " bytes. Not injecting.\n",
1175 region_name(region_type), region.size,
1176 region.size, region_size, region_size);
1177 exit(EXIT_FAILURE);
1178 }
1179
1180 int offset = 0;
1181 if ((region_type == 1) && (region_size < region.size)) {
1182 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1183 " bytes. Padding before injecting.\n",
1184 region_name(region_type), region.size,
1185 region.size, region_size, region_size);
1186 offset = region.size - region_size;
1187 memset(image + region.base, 0xff, offset);
1188 }
1189
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001190 if (size < region.base + offset + region_size) {
1191 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1192 size, region.base + offset + region_size);
1193 exit(EXIT_FAILURE);
1194 }
1195
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001196 if (read(region_fd, image + region.base + offset, region_size)
1197 != region_size) {
1198 perror("Could not read file");
1199 exit(EXIT_FAILURE);
1200 }
1201
1202 close(region_fd);
1203
1204 printf("Adding %s as the %s section of %s\n",
1205 region_fname, region_name(region_type), filename);
1206 write_image(filename, image, size);
1207}
1208
Jacob Garber595d9262019-06-27 17:33:10 -06001209static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001210{
1211 unsigned int y = 1;
1212 if (x == 0)
1213 return 0;
1214 while (y <= x)
1215 y = y << 1;
1216
1217 return y;
1218}
1219
1220/**
1221 * Determine if two memory regions overlap.
1222 *
1223 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001224 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001225 * @return 1 if the two regions overlap
1226 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001227static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001228{
Bill XIEfa5f9942017-09-12 11:22:29 +08001229 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001230 return 0;
1231
Nico Huber844eda02019-01-05 00:06:19 +01001232 /* r1 should be either completely below or completely above r2 */
1233 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001234}
1235
Jacob Garber595d9262019-06-27 17:33:10 -06001236static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001237 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001238{
1239 FILE *romlayout;
1240 char tempstr[256];
1241 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001242 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001243 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001244 region_t current_regions[MAX_REGIONS];
1245 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001246 int new_extent = 0;
1247 char *new_image;
1248
1249 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001250 frba_t *frba = find_frba(image, size);
1251 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001252 exit(EXIT_FAILURE);
1253
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001254 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001255 current_regions[i] = get_region(frba, i);
1256 new_regions[i] = get_region(frba, i);
1257 }
1258
1259 /* read new layout */
1260 romlayout = fopen(layout_fname, "r");
1261
1262 if (!romlayout) {
1263 perror("Could not read layout file.\n");
1264 exit(EXIT_FAILURE);
1265 }
1266
1267 while (!feof(romlayout)) {
1268 char *tstr1, *tstr2;
1269
Patrick Georgi802ad522014-08-09 17:12:23 +02001270 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001271 layout_region_name))
1272 continue;
1273
1274 region_number = region_num(layout_region_name);
1275 if (region_number < 0)
1276 continue;
1277
1278 tstr1 = strtok(tempstr, ":");
1279 tstr2 = strtok(NULL, ":");
1280 if (!tstr1 || !tstr2) {
1281 fprintf(stderr, "Could not parse layout file.\n");
1282 exit(EXIT_FAILURE);
1283 }
1284 new_regions[region_number].base = strtol(tstr1,
1285 (char **)NULL, 16);
1286 new_regions[region_number].limit = strtol(tstr2,
1287 (char **)NULL, 16);
1288 new_regions[region_number].size =
1289 new_regions[region_number].limit -
1290 new_regions[region_number].base + 1;
1291
1292 if (new_regions[region_number].size < 0)
1293 new_regions[region_number].size = 0;
1294 }
1295 fclose(romlayout);
1296
1297 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001298 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001299 if (new_regions[i].size == 0)
1300 continue;
1301
1302 if (new_regions[i].size < current_regions[i].size) {
1303 printf("DANGER: Region %s is shrinking.\n",
1304 region_name(i));
1305 printf(" The region will be truncated to fit.\n");
1306 printf(" This may result in an unusable image.\n");
1307 }
1308
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001309 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001310 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001311 fprintf(stderr, "Regions would overlap.\n");
1312 exit(EXIT_FAILURE);
1313 }
1314 }
1315
1316 /* detect if the image size should grow */
1317 if (new_extent < new_regions[i].limit)
1318 new_extent = new_regions[i].limit;
1319 }
1320
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001321 /* check if the image is actually a Flash Descriptor region */
1322 if (size == new_regions[0].size) {
1323 printf("The image is a single Flash Descriptor:\n");
1324 printf(" Only the descriptor will be modified\n");
1325 new_extent = size;
1326 } else {
1327 new_extent = next_pow2(new_extent - 1);
1328 if (new_extent != size) {
1329 printf("The image has changed in size.\n");
1330 printf("The old image is %d bytes.\n", size);
1331 printf("The new image is %d bytes.\n", new_extent);
1332 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001333 }
1334
1335 /* copy regions to a new image */
1336 new_image = malloc(new_extent);
1337 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001338 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001339 int copy_size = new_regions[i].size;
1340 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001341 const region_t *current = &current_regions[i];
1342 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001343
Bill XIEfa5f9942017-09-12 11:22:29 +08001344 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001345 continue;
1346
Bill XIEfa5f9942017-09-12 11:22:29 +08001347 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001348 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001349 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001350 if (i == REGION_BIOS)
1351 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001352 }
1353
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001354 if ((i == REGION_BIOS) && (new->size < current->size)) {
1355 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001356 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001357 }
1358
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001359 if (size < current->base + offset_current + copy_size) {
1360 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1361 region_name(i));
1362 continue;
1363 };
1364
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001365 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1366 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001367 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1368 offset_current, current->limit, current->size);
1369 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1370 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001371
Bill XIEfa5f9942017-09-12 11:22:29 +08001372 memcpy(new_image + new->base + offset_new,
1373 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001374 copy_size);
1375 }
1376
1377 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001378 frba = find_frba(new_image, new_extent);
1379 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001380 exit(EXIT_FAILURE);
1381
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001382 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001383 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001384 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001385
1386 write_image(filename, new_image, new_extent);
1387 free(new_image);
1388}
1389
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001390static void print_version(void)
1391{
1392 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1393 printf("Copyright (C) 2011 Google Inc.\n\n");
1394 printf
1395 ("This program is free software: you can redistribute it and/or modify\n"
1396 "it under the terms of the GNU General Public License as published by\n"
1397 "the Free Software Foundation, version 2 of the License.\n\n"
1398 "This program is distributed in the hope that it will be useful,\n"
1399 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1400 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001401 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001402}
1403
1404static void print_usage(const char *name)
1405{
1406 printf("usage: %s [-vhdix?] <filename>\n", name);
1407 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001408 " -d | --dump: dump intel firmware descriptor\n"
1409 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1410 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1411 " -x | --extract: extract intel fd modules\n"
1412 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1413 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001414 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001415 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1416 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1417 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1418 " can only be used once per run:\n"
1419 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1420 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1421 " Dual Output Fast Read Support\n"
1422 " -l | --lock Lock firmware descriptor and ME region\n"
1423 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001424 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1425 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001426 " -p | --platform Add platform-specific quirks\n"
1427 " aplk - Apollo Lake\n"
1428 " cnl - Cannon Lake\n"
1429 " glk - Gemini Lake\n"
1430 " sklkbl - Skylake/Kaby Lake\n"
1431 " -v | --version: print the version\n"
1432 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001433 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1434 "\n");
1435}
1436
1437int main(int argc, char *argv[])
1438{
1439 int opt, option_index = 0;
1440 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001441 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001442 int mode_layout = 0, mode_newlayout = 0, mode_density = 0;
Bill XIEb3e15a22017-09-07 18:34:50 +08001443 int mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001444 char *region_type_string = NULL, *region_fname = NULL;
1445 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001446 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001447 int region_type = -1, inputfreq = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001448 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001449 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1450
Bill XIEfa5f9942017-09-12 11:22:29 +08001451 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001452 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001453 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001454 {"extract", 0, NULL, 'x'},
1455 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001456 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001457 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001458 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001459 {"density", 1, NULL, 'D'},
1460 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001461 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001462 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001463 {"lock", 0, NULL, 'l'},
1464 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001465 {"version", 0, NULL, 'v'},
1466 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001467 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001468 {"validate", 0, NULL, 't'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001469 {0, 0, 0, 0}
1470 };
1471
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001472 while ((opt = getopt_long(argc, argv, "df:D:C:M:xi:n:O:s:p:eluvth?",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001473 long_options, &option_index)) != EOF) {
1474 switch (opt) {
1475 case 'd':
1476 mode_dump = 1;
1477 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001478 case 'f':
1479 mode_layout = 1;
1480 layout_fname = strdup(optarg);
1481 if (!layout_fname) {
1482 fprintf(stderr, "No layout file specified\n");
1483 print_usage(argv[0]);
1484 exit(EXIT_FAILURE);
1485 }
1486 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001487 case 'x':
1488 mode_extract = 1;
1489 break;
1490 case 'i':
1491 // separate type and file name
1492 region_type_string = strdup(optarg);
1493 region_fname = strchr(region_type_string, ':');
1494 if (!region_fname) {
1495 print_usage(argv[0]);
1496 exit(EXIT_FAILURE);
1497 }
1498 region_fname[0] = '\0';
1499 region_fname++;
1500 // Descriptor, BIOS, ME, GbE, Platform
1501 // valid type?
1502 if (!strcasecmp("Descriptor", region_type_string))
1503 region_type = 0;
1504 else if (!strcasecmp("BIOS", region_type_string))
1505 region_type = 1;
1506 else if (!strcasecmp("ME", region_type_string))
1507 region_type = 2;
1508 else if (!strcasecmp("GbE", region_type_string))
1509 region_type = 3;
1510 else if (!strcasecmp("Platform", region_type_string))
1511 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001512 else if (!strcasecmp("EC", region_type_string))
1513 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001514 if (region_type == -1) {
1515 fprintf(stderr, "No such region type: '%s'\n\n",
1516 region_type_string);
1517 print_usage(argv[0]);
1518 exit(EXIT_FAILURE);
1519 }
1520 mode_inject = 1;
1521 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001522 case 'n':
1523 mode_newlayout = 1;
1524 layout_fname = strdup(optarg);
1525 if (!layout_fname) {
1526 fprintf(stderr, "No layout file specified\n");
1527 print_usage(argv[0]);
1528 exit(EXIT_FAILURE);
1529 }
1530 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001531 case 'O':
1532 new_filename = strdup(optarg);
1533 if (!new_filename) {
1534 fprintf(stderr, "No output filename specified\n");
1535 print_usage(argv[0]);
1536 exit(EXIT_FAILURE);
1537 }
1538 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001539 case 'D':
1540 mode_density = 1;
1541 new_density = strtoul(optarg, NULL, 0);
1542 switch (new_density) {
1543 case 512:
1544 new_density = COMPONENT_DENSITY_512KB;
1545 break;
1546 case 1:
1547 new_density = COMPONENT_DENSITY_1MB;
1548 break;
1549 case 2:
1550 new_density = COMPONENT_DENSITY_2MB;
1551 break;
1552 case 4:
1553 new_density = COMPONENT_DENSITY_4MB;
1554 break;
1555 case 8:
1556 new_density = COMPONENT_DENSITY_8MB;
1557 break;
1558 case 16:
1559 new_density = COMPONENT_DENSITY_16MB;
1560 break;
1561 case 32:
1562 new_density = COMPONENT_DENSITY_32MB;
1563 break;
1564 case 64:
1565 new_density = COMPONENT_DENSITY_64MB;
1566 break;
1567 case 0:
1568 new_density = COMPONENT_DENSITY_UNUSED;
1569 break;
1570 default:
1571 printf("error: Unknown density\n");
1572 print_usage(argv[0]);
1573 exit(EXIT_FAILURE);
1574 }
1575 break;
1576 case 'C':
1577 selected_chip = strtol(optarg, NULL, 0);
1578 if (selected_chip > 2) {
1579 fprintf(stderr, "error: Invalid chip selection\n");
1580 print_usage(argv[0]);
1581 exit(EXIT_FAILURE);
1582 }
1583 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001584 case 'M':
1585 mode_altmedisable = 1;
1586 altmedisable = strtol(optarg, NULL, 0);
1587 if (altmedisable > 1) {
1588 fprintf(stderr, "error: Illegal value\n");
1589 print_usage(argv[0]);
1590 exit(EXIT_FAILURE);
1591 }
1592 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001593 case 's':
1594 // Parse the requested SPI frequency
1595 inputfreq = strtol(optarg, NULL, 0);
1596 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001597 case 17:
1598 spifreq = SPI_FREQUENCY_17MHZ;
1599 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001600 case 20:
1601 spifreq = SPI_FREQUENCY_20MHZ;
1602 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001603 case 30:
1604 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1605 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001606 case 33:
1607 spifreq = SPI_FREQUENCY_33MHZ;
1608 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001609 case 48:
1610 spifreq = SPI_FREQUENCY_48MHZ;
1611 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001612 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001613 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001614 break;
1615 default:
1616 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1617 inputfreq);
1618 print_usage(argv[0]);
1619 exit(EXIT_FAILURE);
1620 }
1621 mode_spifreq = 1;
1622 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001623 case 'e':
1624 mode_em100 = 1;
1625 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001626 case 'l':
1627 mode_locked = 1;
1628 if (mode_unlocked == 1) {
1629 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1630 exit(EXIT_FAILURE);
1631 }
1632 break;
1633 case 'u':
1634 mode_unlocked = 1;
1635 if (mode_locked == 1) {
1636 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1637 exit(EXIT_FAILURE);
1638 }
1639 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001640 case 'p':
1641 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001642 platform = PLATFORM_APL;
1643 } else if (!strcmp(optarg, "cnl")) {
1644 platform = PLATFORM_CNL;
1645 } else if (!strcmp(optarg, "glk")) {
1646 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301647 } else if (!strcmp(optarg, "icl")) {
1648 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301649 } else if (!strcmp(optarg, "jsl")) {
1650 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001651 } else if (!strcmp(optarg, "sklkbl")) {
1652 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001653 } else if (!strcmp(optarg, "tgl")) {
1654 platform = PLATFORM_TGL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001655 } else {
1656 fprintf(stderr, "Unknown platform: %s\n", optarg);
1657 exit(EXIT_FAILURE);
1658 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001659 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001660 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001661 case 't':
1662 mode_validate = 1;
1663 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001664 case 'v':
1665 print_version();
1666 exit(EXIT_SUCCESS);
1667 break;
1668 case 'h':
1669 case '?':
1670 default:
1671 print_usage(argv[0]);
1672 exit(EXIT_SUCCESS);
1673 break;
1674 }
1675 }
1676
Chris Douglass03ce0142014-02-26 13:30:13 -05001677 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001678 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001679 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001680 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001681 print_usage(argv[0]);
1682 exit(EXIT_FAILURE);
1683 }
1684
Chris Douglass03ce0142014-02-26 13:30:13 -05001685 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001686 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001687 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001688 fprintf(stderr, "You need to specify a mode.\n\n");
1689 print_usage(argv[0]);
1690 exit(EXIT_FAILURE);
1691 }
1692
1693 if (optind + 1 != argc) {
1694 fprintf(stderr, "You need to specify a file.\n\n");
1695 print_usage(argv[0]);
1696 exit(EXIT_FAILURE);
1697 }
1698
1699 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001700 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001701 if (bios_fd == -1) {
1702 perror("Could not open file");
1703 exit(EXIT_FAILURE);
1704 }
1705 struct stat buf;
1706 if (fstat(bios_fd, &buf) == -1) {
1707 perror("Could not stat file");
1708 exit(EXIT_FAILURE);
1709 }
1710 int size = buf.st_size;
1711
1712 printf("File %s is %d bytes\n", filename, size);
1713
1714 char *image = malloc(size);
1715 if (!image) {
1716 printf("Out of memory.\n");
1717 exit(EXIT_FAILURE);
1718 }
1719
1720 if (read(bios_fd, image, size) != size) {
1721 perror("Could not read file");
1722 exit(EXIT_FAILURE);
1723 }
1724
1725 close(bios_fd);
1726
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001727 // generate new filename
1728 if (new_filename == NULL) {
1729 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1730 if (!new_filename) {
1731 printf("Out of memory.\n");
1732 exit(EXIT_FAILURE);
1733 }
1734 // - 5: leave room for ".new\0"
1735 strcpy(new_filename, filename);
1736 strcat(new_filename, ".new");
1737 }
1738
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001739 check_ifd_version(image, size);
1740
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001741 if (mode_dump)
1742 dump_fd(image, size);
1743
Chris Douglass03ce0142014-02-26 13:30:13 -05001744 if (mode_layout)
1745 dump_layout(image, size, layout_fname);
1746
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001747 if (mode_extract)
1748 write_regions(image, size);
1749
Mathew Kingc7ddc992019-08-08 14:59:25 -06001750 if (mode_validate)
1751 validate_layout(image, size);
1752
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001753 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001754 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001755 region_fname);
1756
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001757 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001758 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001759
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001760 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001761 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001762
Jan Tatjefa317512016-03-11 00:52:07 +01001763 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001764 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01001765
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001766 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001767 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001768
Alexander Couzensd12ea112016-09-10 13:33:05 +02001769 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001770 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001771
1772 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001773 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001774
Bill XIEb3e15a22017-09-07 18:34:50 +08001775 if (mode_altmedisable) {
1776 fpsba_t *fpsba = find_fpsba(image, size);
1777 fmsba_t *fmsba = find_fmsba(image, size);
1778 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001779 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08001780 }
1781
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001782 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001783 free(image);
1784
1785 return 0;
1786}