blob: 97b9cd1fe865e70fdbfc62f434ad6758b02575e7 [file] [log] [blame]
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001/*
2 * ifdtool - dump Intel Firmware Descriptor information
3 *
4 * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070014 */
15
16#include <unistd.h>
17#include <stdlib.h>
18#include <stdio.h>
19#include <string.h>
20#include <getopt.h>
21#include <fcntl.h>
22#include <sys/types.h>
23#include <sys/stat.h>
Bill XIE4651d452017-09-12 11:54:48 +080024#include <commonlib/helpers.h>
Mathew Kingc7ddc992019-08-08 14:59:25 -060025#include <fmap.h>
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070026#include "ifdtool.h"
27
Scott Duplichanf2c98372014-12-12 21:03:06 -060028#ifndef O_BINARY
29#define O_BINARY 0
30#endif
31
Bill XIE612ec0e2017-08-30 16:10:27 +080032/**
33 * PTR_IN_RANGE - examine whether a pointer falls in [base, base + limit)
34 * @param ptr: the non-void* pointer to a single arbitrary-sized object.
35 * @param base: base address represented with char* type.
36 * @param limit: upper limit of the legal address.
37 *
38 */
39#define PTR_IN_RANGE(ptr, base, limit) \
40 ((const char *)(ptr) >= (base) && \
41 (const char *)&(ptr)[1] <= (base) + (limit))
42
Duncan Laurie1f7fd722015-06-22 11:14:48 -070043static int ifd_version;
Bill XIEb3e15a22017-09-07 18:34:50 +080044static int chipset;
Bill XIEfa5f9942017-09-12 11:22:29 +080045static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010046static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070047static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050048
Duncan Laurie1f7fd722015-06-22 11:14:48 -070049static const struct region_name region_names[MAX_REGIONS] = {
Mathew Kingc7ddc992019-08-08 14:59:25 -060050 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin", "SI_DESC" },
51 { "BIOS", "bios", "flashregion_1_bios.bin", "SI_BIOS" },
52 { "Intel ME", "me", "flashregion_2_intel_me.bin", "SI_ME" },
53 { "GbE", "gbe", "flashregion_3_gbe.bin", "SI_GBE" },
54 { "Platform Data", "pd", "flashregion_4_platform_data.bin", "SI_PDR" },
55 { "Reserved", "res1", "flashregion_5_reserved.bin", NULL },
56 { "Reserved", "res2", "flashregion_6_reserved.bin", NULL },
57 { "Reserved", "res3", "flashregion_7_reserved.bin", NULL },
58 { "EC", "ec", "flashregion_8_ec.bin", "SI_EC" },
Chris Douglass03ce0142014-02-26 13:30:13 -050059};
60
Bill XIEb3e15a22017-09-07 18:34:50 +080061/* port from flashrom */
62static const char *const ich_chipset_names[] = {
63 "Unknown ICH",
64 "ICH",
65 "ICH2345",
66 "ICH6",
67 "SCH U",
68 "Atom E6xx",
69 "Atom S1220 S1240 S1260",
70 "ICH7",
71 "ICH8",
72 "ICH9",
73 "ICH10",
74 "5 series Ibex Peak",
75 "6 series Cougar Point",
76 "7 series Panther Point",
77 "8 series Lynx Point",
78 "Baytrail",
79 "8 series Lynx Point LP",
80 "8 series Wellsburg",
81 "9 series Wildcat Point",
82 "9 series Wildcat Point LP",
83 "100 series Sunrise Point",
84 "C620 series Lewisburg",
85 NULL
86};
87
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070088static fdbar_t *find_fd(char *image, int size)
89{
90 int i, found = 0;
91
92 /* Scan for FD signature */
93 for (i = 0; i < (size - 4); i += 4) {
94 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
95 found = 1;
96 break; // signature found.
97 }
98 }
99
100 if (!found) {
101 printf("No Flash Descriptor found in this image\n");
102 return NULL;
103 }
104
Bill XIE612ec0e2017-08-30 16:10:27 +0800105 fdbar_t *fdb = (fdbar_t *) (image + i);
106 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
107}
108
Stefan Tauner0d226142018-08-05 18:56:53 +0200109static char *find_flumap(char *image, int size)
110{
111 /* The upper map is located in the word before the 256B-long OEM section
112 * at the end of the 4kB-long flash descriptor. In the official
113 * documentation this is defined as FDBAR + 0xEFC. However, starting
114 * with B-Step of Ibex Peak (5 series) the signature (and thus FDBAR)
115 * has moved 16 bytes back to offset 0x10 of the image. Although
116 * official documentation still maintains the offset relative to FDBAR
117 * this is wrong and a simple fixed offset from the start of the image
118 * works.
119 */
120 char *flumap = image + 4096 - 256 - 4;
121 return PTR_IN_RANGE(flumap, image, size) ? flumap : NULL;
122}
123
Bill XIE612ec0e2017-08-30 16:10:27 +0800124static fcba_t *find_fcba(char *image, int size)
125{
126 fdbar_t *fdb = find_fd(image, size);
127 if (!fdb)
128 return NULL;
129 fcba_t *fcba = (fcba_t *) (image + ((fdb->flmap0 & 0xff) << 4));
130 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
131
132}
133
134static fmba_t *find_fmba(char *image, int size)
135{
136 fdbar_t *fdb = find_fd(image, size);
137 if (!fdb)
138 return NULL;
139 fmba_t *fmba = (fmba_t *) (image + ((fdb->flmap1 & 0xff) << 4));
140 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
141}
142
143static frba_t *find_frba(char *image, int size)
144{
145 fdbar_t *fdb = find_fd(image, size);
146 if (!fdb)
147 return NULL;
148 frba_t *frba =
149 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
150 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
151}
152
153static fpsba_t *find_fpsba(char *image, int size)
154{
155 fdbar_t *fdb = find_fd(image, size);
156 if (!fdb)
157 return NULL;
158 fpsba_t *fpsba =
159 (fpsba_t *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
160 return PTR_IN_RANGE(fpsba, image, size) ? fpsba : NULL;
161}
162
163static fmsba_t *find_fmsba(char *image, int size)
164{
165 fdbar_t *fdb = find_fd(image, size);
166 if (!fdb)
167 return NULL;
168 fmsba_t *fmsba = (fmsba_t *) (image + ((fdb->flmap2 & 0xff) << 4));
169 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700170}
171
Bill XIEb3e15a22017-09-07 18:34:50 +0800172/* port from flashrom */
173static enum ich_chipset guess_ich_chipset(const fdbar_t *fdb)
174{
175 uint32_t iccriba = (fdb->flmap2 >> 16) & 0xff;
176 uint32_t msl = (fdb->flmap2 >> 8) & 0xff;
177 uint32_t isl = (fdb->flmap1 >> 24);
178 uint32_t nm = (fdb->flmap1 >> 8) & 0x7;
179
180 if (iccriba == 0x00) {
181 if (msl == 0 && isl <= 2)
182 return CHIPSET_ICH8;
183 else if (isl <= 2)
184 return CHIPSET_ICH9;
185 else if (isl <= 10)
186 return CHIPSET_ICH10;
187 else if (isl <= 16)
188 return CHIPSET_5_SERIES_IBEX_PEAK;
189 printf("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
190 return CHIPSET_5_SERIES_IBEX_PEAK;
191 } else if (iccriba < 0x31 && (fdb->flmap2 & 0xff) < 0x30) {
192 if (msl == 0 && isl <= 17)
193 return CHIPSET_BAYTRAIL;
194 else if (msl <= 1 && isl <= 18)
195 return CHIPSET_6_SERIES_COUGAR_POINT;
196 else if (msl <= 1 && isl <= 21)
197 return CHIPSET_8_SERIES_LYNX_POINT;
198 printf("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
199 return CHIPSET_9_SERIES_WILDCAT_POINT;
200 } else if (nm == 6) {
201 return CHIPSET_C620_SERIES_LEWISBURG;
202 } else {
203 return CHIPSET_100_SERIES_SUNRISE_POINT;
204 }
205}
206
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700207/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700208 * Some newer platforms have re-defined the FCBA field that was used to
209 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
210 * have the required FCBA field, but are IFD v2 and return true if current
211 * platform is one of them.
212 */
213static int is_platform_ifd_2(void)
214{
215 static const int ifd_2_platforms[] = {
216 PLATFORM_GLK,
217 PLATFORM_CNL,
Aamir Bohra1018be22018-06-29 15:08:50 +0530218 PLATFORM_ICL,
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -0700219 PLATFORM_TGL,
rkanabard64b0462019-08-30 11:40:08 +0530220 PLATFORM_JSL,
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700221 };
222 unsigned int i;
223
224 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
225 if (platform == ifd_2_platforms[i])
226 return 1;
227 }
228
229 return 0;
230}
231
232/*
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700233 * There is no version field in the descriptor so to determine
234 * if this is a new descriptor format we check the hardcoded SPI
235 * read frequency to see if it is fixed at 20MHz or 17MHz.
236 */
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700237static int get_ifd_version_from_fcba(char *image, int size)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700238{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700239 int read_freq;
Bill XIE612ec0e2017-08-30 16:10:27 +0800240 const fcba_t *fcba = find_fcba(image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +0800241 const fdbar_t *fdb = find_fd(image, size);
Jacob Garber9bb04612019-05-08 13:40:45 -0600242 if (!fcba || !fdb)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700243 exit(EXIT_FAILURE);
244
Bill XIEb3e15a22017-09-07 18:34:50 +0800245 chipset = guess_ich_chipset(fdb);
246 /* TODO: port ifd_version and max_regions
247 * against guess_ich_chipset()
248 */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700249 read_freq = (fcba->flcomp >> 17) & 7;
250
251 switch (read_freq) {
252 case SPI_FREQUENCY_20MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700253 return IFD_VERSION_1;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700254 case SPI_FREQUENCY_17MHZ:
Hannah Williams589fc342016-10-06 14:29:48 -0700255 case SPI_FREQUENCY_50MHZ_30MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700256 return IFD_VERSION_2;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700257 default:
258 fprintf(stderr, "Unknown descriptor version: %d\n",
259 read_freq);
260 exit(EXIT_FAILURE);
261 }
262}
263
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700264static void check_ifd_version(char *image, int size)
265{
266 if (is_platform_ifd_2())
267 ifd_version = IFD_VERSION_2;
268 else
269 ifd_version = get_ifd_version_from_fcba(image, size);
270
271 if (ifd_version == IFD_VERSION_1)
272 max_regions = MAX_REGIONS_OLD;
273 else
274 max_regions = MAX_REGIONS;
275}
276
Bill XIEfa5f9942017-09-12 11:22:29 +0800277static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700278{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500279 int base_mask;
280 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700281 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700282 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500283
284 if (ifd_version >= IFD_VERSION_2)
285 base_mask = 0x7fff;
286 else
287 base_mask = 0xfff;
288
289 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700290
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400291 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800292 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700293 exit (EXIT_FAILURE);
294 }
295
Bill XIE4651d452017-09-12 11:54:48 +0800296 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700297 region.base = (flreg & base_mask) << 12;
298 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700299 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500300
Chris Douglass03ce0142014-02-26 13:30:13 -0500301 if (region.size < 0)
302 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700303
304 return region;
305}
306
Bill XIEfa5f9942017-09-12 11:22:29 +0800307static void set_region(frba_t *frba, unsigned int region_type,
308 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500309{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400310 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800311 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500312 exit (EXIT_FAILURE);
313 }
Bill XIE4651d452017-09-12 11:54:48 +0800314
315 frba->flreg[region_type] =
316 (((region->limit >> 12) & 0x7fff) << 16) |
317 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500318}
319
Bill XIEfa5f9942017-09-12 11:22:29 +0800320static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700321{
Bill XIEfa5f9942017-09-12 11:22:29 +0800322 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700323 fprintf(stderr, "Invalid region type.\n");
324 exit (EXIT_FAILURE);
325 }
326
Chris Douglass03ce0142014-02-26 13:30:13 -0500327 return region_names[region_type].pretty;
328}
329
Bill XIEfa5f9942017-09-12 11:22:29 +0800330static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500331{
Bill XIEfa5f9942017-09-12 11:22:29 +0800332 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500333 fprintf(stderr, "Invalid region type.\n");
334 exit (EXIT_FAILURE);
335 }
336
337 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700338}
339
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500340static int region_num(const char *name)
341{
Bill XIEfa5f9942017-09-12 11:22:29 +0800342 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500343
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200344 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500345 if (strcasecmp(name, region_names[i].pretty) == 0)
346 return i;
347 if (strcasecmp(name, region_names[i].terse) == 0)
348 return i;
349 }
350
351 return -1;
352}
353
Bill XIEfa5f9942017-09-12 11:22:29 +0800354static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700355{
Bill XIEfa5f9942017-09-12 11:22:29 +0800356 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700357 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700358 exit (EXIT_FAILURE);
359 }
360
Bill XIE1bf65062017-09-12 11:31:37 +0800361 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700362}
363
Bill XIEfa5f9942017-09-12 11:22:29 +0800364static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700365{
366 region_t region = get_region(frba, num);
367 printf(" Flash Region %d (%s): %08x - %08x %s\n",
368 num, region_name(num), region.base, region.limit,
369 region.size < 1 ? "(unused)" : "");
370}
371
Bill XIEfa5f9942017-09-12 11:22:29 +0800372static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
373 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500374{
375 region_t region = get_region(frba, num);
376 snprintf(buf, bufsize, "%08x:%08x %s\n",
377 region.base, region.limit, region_name_short(num));
378}
379
Bill XIEfa5f9942017-09-12 11:22:29 +0800380static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700381{
Bill XIE4651d452017-09-12 11:54:48 +0800382 unsigned int i;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700383 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800384 for (i = 0; i < max_regions; i++) {
385 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
386 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700387 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700388}
389
Bill XIEfa5f9942017-09-12 11:22:29 +0800390static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500391{
392 char buf[LAYOUT_LINELEN];
393 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800394 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500395
396 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
397 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
398 if (layout_fd == -1) {
399 perror("Could not open file");
400 exit(EXIT_FAILURE);
401 }
402
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200403 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200404 region_t region = get_region(frba, i);
405 /* is region invalid? */
406 if (region.size < 1)
407 continue;
408
Chris Douglass03ce0142014-02-26 13:30:13 -0500409 dump_region_layout(buf, bufsize, i, frba);
410 if (write(layout_fd, buf, strlen(buf)) < 0) {
411 perror("Could not write to file");
412 exit(EXIT_FAILURE);
413 }
414 }
415 close(layout_fd);
416 printf("Wrote layout to %s\n", layout_fname);
417}
418
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700419static void decode_spi_frequency(unsigned int freq)
420{
421 switch (freq) {
422 case SPI_FREQUENCY_20MHZ:
423 printf("20MHz");
424 break;
425 case SPI_FREQUENCY_33MHZ:
426 printf("33MHz");
427 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700428 case SPI_FREQUENCY_48MHZ:
429 printf("48MHz");
430 break;
431 case SPI_FREQUENCY_50MHZ_30MHZ:
432 switch (ifd_version) {
433 case IFD_VERSION_1:
434 printf("50MHz");
435 break;
436 case IFD_VERSION_2:
437 printf("30MHz");
438 break;
439 }
440 break;
441 case SPI_FREQUENCY_17MHZ:
442 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700443 break;
444 default:
445 printf("unknown<%x>MHz", freq);
446 }
447}
448
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700449static void decode_component_density(unsigned int density)
450{
451 switch (density) {
452 case COMPONENT_DENSITY_512KB:
453 printf("512KB");
454 break;
455 case COMPONENT_DENSITY_1MB:
456 printf("1MB");
457 break;
458 case COMPONENT_DENSITY_2MB:
459 printf("2MB");
460 break;
461 case COMPONENT_DENSITY_4MB:
462 printf("4MB");
463 break;
464 case COMPONENT_DENSITY_8MB:
465 printf("8MB");
466 break;
467 case COMPONENT_DENSITY_16MB:
468 printf("16MB");
469 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700470 case COMPONENT_DENSITY_32MB:
471 printf("32MB");
472 break;
473 case COMPONENT_DENSITY_64MB:
474 printf("64MB");
475 break;
476 case COMPONENT_DENSITY_UNUSED:
477 printf("UNUSED");
478 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700479 default:
480 printf("unknown<%x>MB", density);
481 }
482}
483
Bill XIEfa5f9942017-09-12 11:22:29 +0800484static void dump_fcba(const fcba_t *fcba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700485{
486 printf("\nFound Component Section\n");
487 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700488 printf(" Dual Output Fast Read Support: %ssupported\n",
489 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700490 printf(" Read ID/Read Status Clock Frequency: ");
491 decode_spi_frequency((fcba->flcomp >> 27) & 7);
492 printf("\n Write/Erase Clock Frequency: ");
493 decode_spi_frequency((fcba->flcomp >> 24) & 7);
494 printf("\n Fast Read Clock Frequency: ");
495 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700496 printf("\n Fast Read Support: %ssupported",
497 (fcba->flcomp & (1 << 20))?"":"not ");
498 printf("\n Read Clock Frequency: ");
499 decode_spi_frequency((fcba->flcomp >> 17) & 7);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700500
501 switch (ifd_version) {
502 case IFD_VERSION_1:
503 printf("\n Component 2 Density: ");
504 decode_component_density((fcba->flcomp >> 3) & 7);
505 printf("\n Component 1 Density: ");
506 decode_component_density(fcba->flcomp & 7);
507 break;
508 case IFD_VERSION_2:
509 printf("\n Component 2 Density: ");
510 decode_component_density((fcba->flcomp >> 4) & 0xf);
511 printf("\n Component 1 Density: ");
512 decode_component_density(fcba->flcomp & 0xf);
513 break;
514 }
515
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700516 printf("\n");
517 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700518 printf(" Invalid Instruction 3: 0x%02x\n",
519 (fcba->flill >> 24) & 0xff);
520 printf(" Invalid Instruction 2: 0x%02x\n",
521 (fcba->flill >> 16) & 0xff);
522 printf(" Invalid Instruction 1: 0x%02x\n",
523 (fcba->flill >> 8) & 0xff);
524 printf(" Invalid Instruction 0: 0x%02x\n",
525 fcba->flill & 0xff);
526 printf("FLPB 0x%08x\n", fcba->flpb);
527 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
528 (fcba->flpb & 0xfff) << 12);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700529}
530
Bill XIEfa5f9942017-09-12 11:22:29 +0800531static void dump_fpsba(const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700532{
Bill XIE4651d452017-09-12 11:54:48 +0800533 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700534 printf("Found PCH Strap Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800535 for (i = 0; i < ARRAY_SIZE(fpsba->pchstrp); i++)
536 printf("PCHSTRP%u:%s 0x%08x\n", i,
537 i < 10 ? " " : "", fpsba->pchstrp[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800538
539 if (ifd_version >= IFD_VERSION_2) {
540 printf("HAP bit is %sset\n",
541 fpsba->pchstrp[0] & (1 << 16) ? "" : "not ");
542 } else if (chipset >= CHIPSET_ICH8
543 && chipset <= CHIPSET_ICH10) {
544 printf("ICH_MeDisable bit is %sset\n",
545 fpsba->pchstrp[0] & 1 ? "" : "not ");
546 } else {
547 printf("AltMeDisable bit is %sset\n",
548 fpsba->pchstrp[10] & (1 << 7) ? "" : "not ");
549 }
550
Bill XIE4651d452017-09-12 11:54:48 +0800551 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700552}
553
554static void decode_flmstr(uint32_t flmstr)
555{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700556 int wr_shift, rd_shift;
557 if (ifd_version >= IFD_VERSION_2) {
558 wr_shift = FLMSTR_WR_SHIFT_V2;
559 rd_shift = FLMSTR_RD_SHIFT_V2;
560 } else {
561 wr_shift = FLMSTR_WR_SHIFT_V1;
562 rd_shift = FLMSTR_RD_SHIFT_V1;
563 }
564
565 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700566 if (ifd_version >= IFD_VERSION_2)
567 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700568 (flmstr & (1 << (wr_shift + 8))) ?
569 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700570 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700571 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700572 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700573 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700574 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700575 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700576 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700577 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700578 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700579 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700580
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700581 if (ifd_version >= IFD_VERSION_2)
582 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700583 (flmstr & (1 << (rd_shift + 8))) ?
584 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700585 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700586 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700587 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700588 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700589 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700590 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700591 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700592 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700593 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700594 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700595
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700596 /* Requestor ID doesn't exist for ifd 2 */
597 if (ifd_version < IFD_VERSION_2)
598 printf(" Requester ID: 0x%04x\n\n",
599 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700600}
601
Bill XIEfa5f9942017-09-12 11:22:29 +0800602static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700603{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700604 printf("Found Master Section\n");
605 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
606 decode_flmstr(fmba->flmstr1);
607 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
608 decode_flmstr(fmba->flmstr2);
609 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
610 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700611 if (ifd_version >= IFD_VERSION_2) {
612 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
613 decode_flmstr(fmba->flmstr5);
614 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700615}
616
Bill XIEfa5f9942017-09-12 11:22:29 +0800617static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700618{
Bill XIE612ec0e2017-08-30 16:10:27 +0800619 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700620 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800621 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
622 printf("????: 0x%08x\n", fmsba->data[i]);
Bill XIEb3e15a22017-09-07 18:34:50 +0800623
624 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
625 printf("MCH_MeDisable bit is %sset\n",
626 fmsba->data[0] & 1 ? "" : "not ");
627 printf("MCH_AltMeDisable bit is %sset\n",
628 fmsba->data[0] & (1 << 7) ? "" : "not ");
629 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700630}
631
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700632static void dump_jid(uint32_t jid)
633{
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100634 printf(" SPI Component Vendor ID: 0x%02x\n",
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700635 jid & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100636 printf(" SPI Component Device ID 0: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200637 (jid >> 8) & 0xff);
Elyes HAOUAS99e54fe2020-01-30 15:08:03 +0100638 printf(" SPI Component Device ID 1: 0x%02x\n",
Stefan Tauner27bb0662018-08-06 00:40:15 +0200639 (jid >> 16) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700640}
641
642static void dump_vscc(uint32_t vscc)
643{
644 printf(" Lower Erase Opcode: 0x%02x\n",
645 vscc >> 24);
646 printf(" Lower Write Enable on Write Status: 0x%02x\n",
647 vscc & (1 << 20) ? 0x06 : 0x50);
648 printf(" Lower Write Status Required: %s\n",
649 vscc & (1 << 19) ? "Yes" : "No");
650 printf(" Lower Write Granularity: %d bytes\n",
651 vscc & (1 << 18) ? 64 : 1);
652 printf(" Lower Block / Sector Erase Size: ");
653 switch ((vscc >> 16) & 0x3) {
654 case 0:
655 printf("256 Byte\n");
656 break;
657 case 1:
658 printf("4KB\n");
659 break;
660 case 2:
661 printf("8KB\n");
662 break;
663 case 3:
664 printf("64KB\n");
665 break;
666 }
667
668 printf(" Upper Erase Opcode: 0x%02x\n",
669 (vscc >> 8) & 0xff);
670 printf(" Upper Write Enable on Write Status: 0x%02x\n",
671 vscc & (1 << 4) ? 0x06 : 0x50);
672 printf(" Upper Write Status Required: %s\n",
673 vscc & (1 << 3) ? "Yes" : "No");
674 printf(" Upper Write Granularity: %d bytes\n",
675 vscc & (1 << 2) ? 64 : 1);
676 printf(" Upper Block / Sector Erase Size: ");
677 switch (vscc & 0x3) {
678 case 0:
679 printf("256 Byte\n");
680 break;
681 case 1:
682 printf("4KB\n");
683 break;
684 case 2:
685 printf("8KB\n");
686 break;
687 case 3:
688 printf("64KB\n");
689 break;
690 }
691}
692
Bill XIEfa5f9942017-09-12 11:22:29 +0800693static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700694{
695 int i;
Stefan Tauner0d226142018-08-05 18:56:53 +0200696 int max_len = sizeof(vtba_t)/sizeof(vscc_t);
697 int num = (vtl >> 1) < max_len ? (vtl >> 1) : max_len;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700698
699 printf("ME VSCC table:\n");
700 for (i = 0; i < num; i++) {
701 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
702 dump_jid(vtba->entry[i].jid);
703 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
704 dump_vscc(vtba->entry[i].vscc);
705 }
706 printf("\n");
707}
708
Bill XIEfa5f9942017-09-12 11:22:29 +0800709static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700710{
711 int i, j;
712 printf("OEM Section:\n");
713 for (i = 0; i < 4; i++) {
714 printf("%02x:", i << 4);
715 for (j = 0; j < 16; j++)
716 printf(" %02x", oem[(i<<4)+j]);
717 printf ("\n");
718 }
719 printf ("\n");
720}
721
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700722static void dump_fd(char *image, int size)
723{
Bill XIE612ec0e2017-08-30 16:10:27 +0800724 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700725 if (!fdb)
726 exit(EXIT_FAILURE);
727
Bill XIEb3e15a22017-09-07 18:34:50 +0800728 printf("ICH Revision: %s\n", ich_chipset_names[chipset]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700729 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
730 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
731 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
732 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
733 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
734
735 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
736 printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
737 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
738 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
739 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
740
741 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
742 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
743 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
744
Stefan Tauner0d226142018-08-05 18:56:53 +0200745 char *flumap = find_flumap(image, size);
746 uint32_t flumap1 = *(uint32_t *)flumap;
747 printf("FLUMAP1: 0x%08x\n", flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700748 printf(" Intel ME VSCC Table Length (VTL): %d\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200749 (flumap1 >> 8) & 0xff);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700750 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
Stefan Tauner0d226142018-08-05 18:56:53 +0200751 (flumap1 & 0xff) << 4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700752 dump_vtba((vtba_t *)
Stefan Tauner0d226142018-08-05 18:56:53 +0200753 (image + ((flumap1 & 0xff) << 4)),
754 (flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800755 dump_oem((const uint8_t *)image + 0xf00);
756
757 const frba_t *frba = find_frba(image, size);
758 const fcba_t *fcba = find_fcba(image, size);
759 const fpsba_t *fpsba = find_fpsba(image, size);
760 const fmba_t *fmba = find_fmba(image, size);
761 const fmsba_t *fmsba = find_fmsba(image, size);
762
763 if (frba && fcba && fpsba && fmba && fmsba) {
764 dump_frba(frba);
765 dump_fcba(fcba);
766 dump_fpsba(fpsba);
767 dump_fmba(fmba);
768 dump_fmsba(fmsba);
769 } else {
770 printf("FD is corrupted!\n");
771 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700772}
773
Bill XIEfa5f9942017-09-12 11:22:29 +0800774static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500775{
Bill XIE612ec0e2017-08-30 16:10:27 +0800776 const frba_t *frba = find_frba(image, size);
777 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500778 exit(EXIT_FAILURE);
779
Bill XIE612ec0e2017-08-30 16:10:27 +0800780 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500781}
782
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700783static void write_regions(char *image, int size)
784{
Bill XIEfa5f9942017-09-12 11:22:29 +0800785 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800786 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700787
Bill XIE612ec0e2017-08-30 16:10:27 +0800788 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700789 exit(EXIT_FAILURE);
790
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700791 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700792 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700793 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700794 if (region.size > 0) {
795 int region_fd;
796 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600797 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700798 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200799 if (region_fd < 0) {
800 perror("Error while trying to open file");
801 exit(EXIT_FAILURE);
802 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700803 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700804 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700805 close(region_fd);
806 }
807 }
808}
809
Mathew Kingc7ddc992019-08-08 14:59:25 -0600810static void validate_layout(char *image, int size)
811{
812 uint i, errors = 0;
813 struct fmap *fmap;
814 long int fmap_loc = fmap_find((uint8_t *)image, size);
815 const frba_t *frba = find_frba(image, size);
816
817 if (fmap_loc < 0 || !frba)
818 exit(EXIT_FAILURE);
819
820 fmap = (struct fmap *)(image + fmap_loc);
821
822 for (i = 0; i < max_regions; i++) {
823 if (region_names[i].fmapname == NULL)
824 continue;
825
826 region_t region = get_region(frba, i);
827
828 if (region.size == 0)
829 continue;
830
831 const struct fmap_area *area =
832 fmap_find_area(fmap, region_names[i].fmapname);
833
834 if (!area)
835 continue;
836
837 if ((uint)region.base != area->offset ||
838 (uint)region.size != area->size) {
839 printf("Region mismatch between %s and %s\n",
840 region_names[i].terse, area->name);
841 printf(" Descriptor region %s:\n", region_names[i].terse);
842 printf(" offset: 0x%08x\n", region.base);
843 printf(" length: 0x%08x\n", region.size);
844 printf(" FMAP area %s:\n", area->name);
845 printf(" offset: 0x%08x\n", area->offset);
846 printf(" length: 0x%08x\n", area->size);
847 errors++;
848 }
849 }
850
851 if (errors > 0)
852 exit(EXIT_FAILURE);
853}
854
Bill XIEfa5f9942017-09-12 11:22:29 +0800855static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700856{
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700857 int new_fd;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100858 printf("Writing new image to %s\n", filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700859
860 // Now write out new image
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +0100861 new_fd = open(filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600862 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700863 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200864 if (new_fd < 0) {
865 perror("Error while trying to open file");
866 exit(EXIT_FAILURE);
867 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700868 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700869 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700870 close(new_fd);
871}
872
Bill XIEfa5f9942017-09-12 11:22:29 +0800873static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700874 enum spi_frequency freq)
875{
Bill XIE612ec0e2017-08-30 16:10:27 +0800876 fcba_t *fcba = find_fcba(image, size);
877 if (!fcba)
878 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700879
880 /* clear bits 21-29 */
881 fcba->flcomp &= ~0x3fe00000;
882 /* Read ID and Read Status Clock Frequency */
883 fcba->flcomp |= freq << 27;
884 /* Write and Erase Clock Frequency */
885 fcba->flcomp |= freq << 24;
886 /* Fast Read Clock Frequency */
887 fcba->flcomp |= freq << 21;
888
889 write_image(filename, image, size);
890}
891
Bill XIEfa5f9942017-09-12 11:22:29 +0800892static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700893{
Bill XIE612ec0e2017-08-30 16:10:27 +0800894 fcba_t *fcba = find_fcba(image, size);
895 if (!fcba)
896 exit(EXIT_FAILURE);
897
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700898 int freq;
899
900 switch (ifd_version) {
901 case IFD_VERSION_1:
902 freq = SPI_FREQUENCY_20MHZ;
903 break;
904 case IFD_VERSION_2:
905 freq = SPI_FREQUENCY_17MHZ;
906 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -0700907 default:
908 freq = SPI_FREQUENCY_17MHZ;
909 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700910 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700911
912 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700913 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700914}
915
Bill XIEfa5f9942017-09-12 11:22:29 +0800916static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +0100917 unsigned int density)
918{
Bill XIE612ec0e2017-08-30 16:10:27 +0800919 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200920 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +0800921 if (!fcba)
922 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +0100923
924 printf("Setting chip density to ");
925 decode_component_density(density);
926 printf("\n");
927
928 switch (ifd_version) {
929 case IFD_VERSION_1:
930 /* fail if selected density is not supported by this version */
931 if ( (density == COMPONENT_DENSITY_32MB) ||
932 (density == COMPONENT_DENSITY_64MB) ||
933 (density == COMPONENT_DENSITY_UNUSED) ) {
934 printf("error: Selected density not supported in IFD version 1.\n");
935 exit(EXIT_FAILURE);
936 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200937 mask = 0x7;
938 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +0100939 break;
940 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200941 mask = 0xf;
942 chip2_offset = 4;
943 break;
Jan Tatjefa317512016-03-11 00:52:07 +0100944 default:
945 printf("error: Unknown IFD version\n");
946 exit(EXIT_FAILURE);
947 break;
948 }
949
950 /* clear chip density for corresponding chip */
951 switch (selected_chip) {
952 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200953 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +0100954 break;
955 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200956 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +0100957 break;
958 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200959 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +0100960 break;
961 }
962
963 /* set the new density */
964 if (selected_chip == 1 || selected_chip == 0)
965 fcba->flcomp |= (density); /* first chip */
966 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200967 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +0100968
969 write_image(filename, image, size);
970}
971
Duncan Laurie7775d672019-06-06 13:39:26 -0700972static int check_region(const frba_t *frba, unsigned int region_type)
973{
974 region_t region;
975
976 if (!frba)
977 return 0;
978
979 region = get_region(frba, region_type);
980 return !!((region.base < region.limit) && (region.size > 0));
981}
982
Bill XIEfa5f9942017-09-12 11:22:29 +0800983static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700984{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700985 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +0800986 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -0700987 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800988 if (!fmba)
989 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700990
991 if (ifd_version >= IFD_VERSION_2) {
992 wr_shift = FLMSTR_WR_SHIFT_V2;
993 rd_shift = FLMSTR_RD_SHIFT_V2;
994
995 /* Clear non-reserved bits */
996 fmba->flmstr1 &= 0xff;
997 fmba->flmstr2 &= 0xff;
998 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -0800999 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001000 } else {
1001 wr_shift = FLMSTR_WR_SHIFT_V1;
1002 rd_shift = FLMSTR_RD_SHIFT_V1;
1003
1004 fmba->flmstr1 = 0;
1005 fmba->flmstr2 = 0;
1006 /* Requestor ID */
1007 fmba->flmstr3 = 0x118;
1008 }
1009
Andrey Petrov96ecb772016-10-31 19:31:54 -07001010 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001011 case PLATFORM_APL:
1012 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001013 /* CPU/BIOS can read descriptor and BIOS */
1014 fmba->flmstr1 |= 0x3 << rd_shift;
1015 /* CPU/BIOS can write BIOS */
1016 fmba->flmstr1 |= 0x2 << wr_shift;
1017 /* TXE can read descriptor, BIOS and Device Expansion */
1018 fmba->flmstr2 |= 0x23 << rd_shift;
1019 /* TXE can only write Device Expansion */
1020 fmba->flmstr2 |= 0x20 << wr_shift;
1021 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001022 case PLATFORM_CNL:
1023 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001024 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001025 case PLATFORM_TGL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001026 /* CPU/BIOS can read descriptor and BIOS. */
1027 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1028 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1029 /* CPU/BIOS can write BIOS. */
1030 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1031 /* ME can read descriptor and ME. */
1032 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1033 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001034 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001035 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1036 if (check_region(frba, REGION_GBE)) {
1037 /* BIOS can read/write GbE. */
1038 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1039 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1040 /* ME can read GbE. */
1041 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1042 /* GbE can read descriptor and read/write GbE.. */
1043 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1044 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1045 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1046 }
1047 if (check_region(frba, REGION_PDR)) {
1048 /* BIOS can read/write PDR. */
1049 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1050 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1051 }
1052 if (check_region(frba, REGION_EC)) {
1053 /* BIOS can read EC. */
1054 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1055 /* EC can read descriptor and read/write EC. */
1056 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1057 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1058 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1059 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001060 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001061 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001062 /* CPU/BIOS can read descriptor and BIOS. */
1063 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1064 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1065 /* CPU/BIOS can write BIOS. */
1066 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1067 /* ME can read descriptor and ME. */
1068 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1069 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1070 /* ME can write ME. */
1071 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1072 if (check_region(frba, REGION_GBE)) {
1073 /* BIOS can read GbE. */
1074 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1075 /* BIOS can write GbE. */
1076 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1077 /* ME can read GbE. */
1078 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1079 /* ME can write GbE. */
1080 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1081 /* GbE can write GbE. */
1082 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1083 /* GbE can read GbE. */
1084 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1085 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001086 break;
1087 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001088
1089 write_image(filename, image, size);
1090}
1091
Bill XIEfa5f9942017-09-12 11:22:29 +08001092static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001093{
Bill XIE612ec0e2017-08-30 16:10:27 +08001094 fmba_t *fmba = find_fmba(image, size);
1095 if (!fmba)
1096 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001097
1098 if (ifd_version >= IFD_VERSION_2) {
1099 /* Access bits for each region are read: 19:8 write: 31:20 */
1100 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1101 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1102 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001103 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001104 } else {
1105 fmba->flmstr1 = 0xffff0000;
1106 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001107 /* Keep chipset specific Requester ID */
1108 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001109 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001110
1111 write_image(filename, image, size);
1112}
1113
Bill XIEb3e15a22017-09-07 18:34:50 +08001114/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001115static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001116{
1117 if (ifd_version >= IFD_VERSION_2) {
1118 printf("%sting the HAP bit to %s Intel ME...\n",
1119 altmedisable?"Set":"Unset",
1120 altmedisable?"disable":"enable");
1121 if (altmedisable)
1122 fpsba->pchstrp[0] |= (1 << 16);
1123 else
1124 fpsba->pchstrp[0] &= ~(1 << 16);
1125 } else {
1126 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1127 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1128 "and MCH_AltMeDisable to %s Intel ME...\n",
1129 altmedisable?"Set":"Unset",
1130 altmedisable?"disable":"enable");
1131 if (altmedisable) {
1132 /* MCH_MeDisable */
1133 fmsba->data[0] |= 1;
1134 /* MCH_AltMeDisable */
1135 fmsba->data[0] |= (1 << 7);
1136 /* ICH_MeDisable */
1137 fpsba->pchstrp[0] |= 1;
1138 } else {
1139 fmsba->data[0] &= ~1;
1140 fmsba->data[0] &= ~(1 << 7);
1141 fpsba->pchstrp[0] &= ~1;
1142 }
1143 } else {
1144 printf("%sting the AltMeDisable to %s Intel ME...\n",
1145 altmedisable?"Set":"Unset",
1146 altmedisable?"disable":"enable");
1147 if (altmedisable)
1148 fpsba->pchstrp[10] |= (1 << 7);
1149 else
1150 fpsba->pchstrp[10] &= ~(1 << 7);
1151 }
1152 }
1153}
1154
Jacob Garber595d9262019-06-27 17:33:10 -06001155static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001156 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001157{
Bill XIE612ec0e2017-08-30 16:10:27 +08001158 frba_t *frba = find_frba(image, size);
1159 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001160 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001161
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001162 region_t region = get_region(frba, region_type);
1163 if (region.size <= 0xfff) {
1164 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1165 region_name(region_type));
1166 exit(EXIT_FAILURE);
1167 }
1168
Scott Duplichanf2c98372014-12-12 21:03:06 -06001169 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001170 if (region_fd == -1) {
1171 perror("Could not open file");
1172 exit(EXIT_FAILURE);
1173 }
1174 struct stat buf;
1175 if (fstat(region_fd, &buf) == -1) {
1176 perror("Could not stat file");
1177 exit(EXIT_FAILURE);
1178 }
1179 int region_size = buf.st_size;
1180
1181 printf("File %s is %d bytes\n", region_fname, region_size);
1182
1183 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001184 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001185 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1186 " bytes. Not injecting.\n",
1187 region_name(region_type), region.size,
1188 region.size, region_size, region_size);
1189 exit(EXIT_FAILURE);
1190 }
1191
1192 int offset = 0;
1193 if ((region_type == 1) && (region_size < region.size)) {
1194 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1195 " bytes. Padding before injecting.\n",
1196 region_name(region_type), region.size,
1197 region.size, region_size, region_size);
1198 offset = region.size - region_size;
1199 memset(image + region.base, 0xff, offset);
1200 }
1201
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001202 if (size < region.base + offset + region_size) {
1203 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1204 size, region.base + offset + region_size);
1205 exit(EXIT_FAILURE);
1206 }
1207
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001208 if (read(region_fd, image + region.base + offset, region_size)
1209 != region_size) {
1210 perror("Could not read file");
1211 exit(EXIT_FAILURE);
1212 }
1213
1214 close(region_fd);
1215
1216 printf("Adding %s as the %s section of %s\n",
1217 region_fname, region_name(region_type), filename);
1218 write_image(filename, image, size);
1219}
1220
Jacob Garber595d9262019-06-27 17:33:10 -06001221static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001222{
1223 unsigned int y = 1;
1224 if (x == 0)
1225 return 0;
1226 while (y <= x)
1227 y = y << 1;
1228
1229 return y;
1230}
1231
1232/**
1233 * Determine if two memory regions overlap.
1234 *
1235 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001236 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001237 * @return 1 if the two regions overlap
1238 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001239static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001240{
Bill XIEfa5f9942017-09-12 11:22:29 +08001241 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001242 return 0;
1243
Nico Huber844eda02019-01-05 00:06:19 +01001244 /* r1 should be either completely below or completely above r2 */
1245 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001246}
1247
Jacob Garber595d9262019-06-27 17:33:10 -06001248static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001249 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001250{
1251 FILE *romlayout;
1252 char tempstr[256];
1253 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001254 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001255 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001256 region_t current_regions[MAX_REGIONS];
1257 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001258 int new_extent = 0;
1259 char *new_image;
1260
1261 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001262 frba_t *frba = find_frba(image, size);
1263 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001264 exit(EXIT_FAILURE);
1265
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001266 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001267 current_regions[i] = get_region(frba, i);
1268 new_regions[i] = get_region(frba, i);
1269 }
1270
1271 /* read new layout */
1272 romlayout = fopen(layout_fname, "r");
1273
1274 if (!romlayout) {
1275 perror("Could not read layout file.\n");
1276 exit(EXIT_FAILURE);
1277 }
1278
1279 while (!feof(romlayout)) {
1280 char *tstr1, *tstr2;
1281
Patrick Georgi802ad522014-08-09 17:12:23 +02001282 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001283 layout_region_name))
1284 continue;
1285
1286 region_number = region_num(layout_region_name);
1287 if (region_number < 0)
1288 continue;
1289
1290 tstr1 = strtok(tempstr, ":");
1291 tstr2 = strtok(NULL, ":");
1292 if (!tstr1 || !tstr2) {
1293 fprintf(stderr, "Could not parse layout file.\n");
1294 exit(EXIT_FAILURE);
1295 }
1296 new_regions[region_number].base = strtol(tstr1,
1297 (char **)NULL, 16);
1298 new_regions[region_number].limit = strtol(tstr2,
1299 (char **)NULL, 16);
1300 new_regions[region_number].size =
1301 new_regions[region_number].limit -
1302 new_regions[region_number].base + 1;
1303
1304 if (new_regions[region_number].size < 0)
1305 new_regions[region_number].size = 0;
1306 }
1307 fclose(romlayout);
1308
1309 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001310 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001311 if (new_regions[i].size == 0)
1312 continue;
1313
1314 if (new_regions[i].size < current_regions[i].size) {
1315 printf("DANGER: Region %s is shrinking.\n",
1316 region_name(i));
1317 printf(" The region will be truncated to fit.\n");
1318 printf(" This may result in an unusable image.\n");
1319 }
1320
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001321 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001322 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001323 fprintf(stderr, "Regions would overlap.\n");
1324 exit(EXIT_FAILURE);
1325 }
1326 }
1327
1328 /* detect if the image size should grow */
1329 if (new_extent < new_regions[i].limit)
1330 new_extent = new_regions[i].limit;
1331 }
1332
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001333 /* check if the image is actually a Flash Descriptor region */
1334 if (size == new_regions[0].size) {
1335 printf("The image is a single Flash Descriptor:\n");
1336 printf(" Only the descriptor will be modified\n");
1337 new_extent = size;
1338 } else {
1339 new_extent = next_pow2(new_extent - 1);
1340 if (new_extent != size) {
1341 printf("The image has changed in size.\n");
1342 printf("The old image is %d bytes.\n", size);
1343 printf("The new image is %d bytes.\n", new_extent);
1344 }
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001345 }
1346
1347 /* copy regions to a new image */
1348 new_image = malloc(new_extent);
1349 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001350 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001351 int copy_size = new_regions[i].size;
1352 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001353 const region_t *current = &current_regions[i];
1354 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001355
Bill XIEfa5f9942017-09-12 11:22:29 +08001356 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001357 continue;
1358
Bill XIEfa5f9942017-09-12 11:22:29 +08001359 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001360 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001361 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001362 if (i == REGION_BIOS)
1363 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001364 }
1365
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001366 if ((i == REGION_BIOS) && (new->size < current->size)) {
1367 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001368 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001369 }
1370
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001371 if (size < current->base + offset_current + copy_size) {
1372 printf("Skip descriptor %d (%s) (region missing in the old image)\n", i,
1373 region_name(i));
1374 continue;
1375 };
1376
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001377 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1378 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001379 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1380 offset_current, current->limit, current->size);
1381 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1382 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001383
Bill XIEfa5f9942017-09-12 11:22:29 +08001384 memcpy(new_image + new->base + offset_new,
1385 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001386 copy_size);
1387 }
1388
1389 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001390 frba = find_frba(new_image, new_extent);
1391 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001392 exit(EXIT_FAILURE);
1393
Marcello Sylvester Bauer6f9a7782020-02-04 17:20:50 +01001394 printf("Modify Flash Descriptor regions\n");
Bill XIE612ec0e2017-08-30 16:10:27 +08001395 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001396 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001397
1398 write_image(filename, new_image, new_extent);
1399 free(new_image);
1400}
1401
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001402static void print_version(void)
1403{
1404 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1405 printf("Copyright (C) 2011 Google Inc.\n\n");
1406 printf
1407 ("This program is free software: you can redistribute it and/or modify\n"
1408 "it under the terms of the GNU General Public License as published by\n"
1409 "the Free Software Foundation, version 2 of the License.\n\n"
1410 "This program is distributed in the hope that it will be useful,\n"
1411 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1412 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001413 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001414}
1415
1416static void print_usage(const char *name)
1417{
1418 printf("usage: %s [-vhdix?] <filename>\n", name);
1419 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001420 " -d | --dump: dump intel firmware descriptor\n"
1421 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1422 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1423 " -x | --extract: extract intel fd modules\n"
1424 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1425 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001426 " -O | --output <filename> output filename\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001427 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1428 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1429 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1430 " can only be used once per run:\n"
1431 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1432 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1433 " Dual Output Fast Read Support\n"
1434 " -l | --lock Lock firmware descriptor and ME region\n"
1435 " -u | --unlock Unlock firmware descriptor and ME region\n"
Evgeny Zinoviev8c4c3702020-02-16 20:34:26 +03001436 " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n"
1437 " bits to disable ME\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001438 " -p | --platform Add platform-specific quirks\n"
1439 " aplk - Apollo Lake\n"
1440 " cnl - Cannon Lake\n"
1441 " glk - Gemini Lake\n"
1442 " sklkbl - Skylake/Kaby Lake\n"
1443 " -v | --version: print the version\n"
1444 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001445 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1446 "\n");
1447}
1448
1449int main(int argc, char *argv[])
1450{
1451 int opt, option_index = 0;
1452 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001453 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001454 int mode_layout = 0, mode_newlayout = 0, mode_density = 0;
Bill XIEb3e15a22017-09-07 18:34:50 +08001455 int mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001456 char *region_type_string = NULL, *region_fname = NULL;
1457 const char *layout_fname = NULL;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001458 char *new_filename = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001459 int region_type = -1, inputfreq = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001460 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001461 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1462
Bill XIEfa5f9942017-09-12 11:22:29 +08001463 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001464 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001465 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001466 {"extract", 0, NULL, 'x'},
1467 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001468 {"newlayout", 1, NULL, 'n'},
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001469 {"output", 1, NULL, 'O'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001470 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001471 {"density", 1, NULL, 'D'},
1472 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001473 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001474 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001475 {"lock", 0, NULL, 'l'},
1476 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001477 {"version", 0, NULL, 'v'},
1478 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001479 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001480 {"validate", 0, NULL, 't'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001481 {0, 0, 0, 0}
1482 };
1483
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001484 while ((opt = getopt_long(argc, argv, "df:D:C:M:xi:n:O:s:p:eluvth?",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001485 long_options, &option_index)) != EOF) {
1486 switch (opt) {
1487 case 'd':
1488 mode_dump = 1;
1489 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001490 case 'f':
1491 mode_layout = 1;
1492 layout_fname = strdup(optarg);
1493 if (!layout_fname) {
1494 fprintf(stderr, "No layout file specified\n");
1495 print_usage(argv[0]);
1496 exit(EXIT_FAILURE);
1497 }
1498 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001499 case 'x':
1500 mode_extract = 1;
1501 break;
1502 case 'i':
1503 // separate type and file name
1504 region_type_string = strdup(optarg);
1505 region_fname = strchr(region_type_string, ':');
1506 if (!region_fname) {
1507 print_usage(argv[0]);
1508 exit(EXIT_FAILURE);
1509 }
1510 region_fname[0] = '\0';
1511 region_fname++;
1512 // Descriptor, BIOS, ME, GbE, Platform
1513 // valid type?
1514 if (!strcasecmp("Descriptor", region_type_string))
1515 region_type = 0;
1516 else if (!strcasecmp("BIOS", region_type_string))
1517 region_type = 1;
1518 else if (!strcasecmp("ME", region_type_string))
1519 region_type = 2;
1520 else if (!strcasecmp("GbE", region_type_string))
1521 region_type = 3;
1522 else if (!strcasecmp("Platform", region_type_string))
1523 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001524 else if (!strcasecmp("EC", region_type_string))
1525 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001526 if (region_type == -1) {
1527 fprintf(stderr, "No such region type: '%s'\n\n",
1528 region_type_string);
1529 print_usage(argv[0]);
1530 exit(EXIT_FAILURE);
1531 }
1532 mode_inject = 1;
1533 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001534 case 'n':
1535 mode_newlayout = 1;
1536 layout_fname = strdup(optarg);
1537 if (!layout_fname) {
1538 fprintf(stderr, "No layout file specified\n");
1539 print_usage(argv[0]);
1540 exit(EXIT_FAILURE);
1541 }
1542 break;
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001543 case 'O':
1544 new_filename = strdup(optarg);
1545 if (!new_filename) {
1546 fprintf(stderr, "No output filename specified\n");
1547 print_usage(argv[0]);
1548 exit(EXIT_FAILURE);
1549 }
1550 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001551 case 'D':
1552 mode_density = 1;
1553 new_density = strtoul(optarg, NULL, 0);
1554 switch (new_density) {
1555 case 512:
1556 new_density = COMPONENT_DENSITY_512KB;
1557 break;
1558 case 1:
1559 new_density = COMPONENT_DENSITY_1MB;
1560 break;
1561 case 2:
1562 new_density = COMPONENT_DENSITY_2MB;
1563 break;
1564 case 4:
1565 new_density = COMPONENT_DENSITY_4MB;
1566 break;
1567 case 8:
1568 new_density = COMPONENT_DENSITY_8MB;
1569 break;
1570 case 16:
1571 new_density = COMPONENT_DENSITY_16MB;
1572 break;
1573 case 32:
1574 new_density = COMPONENT_DENSITY_32MB;
1575 break;
1576 case 64:
1577 new_density = COMPONENT_DENSITY_64MB;
1578 break;
1579 case 0:
1580 new_density = COMPONENT_DENSITY_UNUSED;
1581 break;
1582 default:
1583 printf("error: Unknown density\n");
1584 print_usage(argv[0]);
1585 exit(EXIT_FAILURE);
1586 }
1587 break;
1588 case 'C':
1589 selected_chip = strtol(optarg, NULL, 0);
1590 if (selected_chip > 2) {
1591 fprintf(stderr, "error: Invalid chip selection\n");
1592 print_usage(argv[0]);
1593 exit(EXIT_FAILURE);
1594 }
1595 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001596 case 'M':
1597 mode_altmedisable = 1;
1598 altmedisable = strtol(optarg, NULL, 0);
1599 if (altmedisable > 1) {
1600 fprintf(stderr, "error: Illegal value\n");
1601 print_usage(argv[0]);
1602 exit(EXIT_FAILURE);
1603 }
1604 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001605 case 's':
1606 // Parse the requested SPI frequency
1607 inputfreq = strtol(optarg, NULL, 0);
1608 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001609 case 17:
1610 spifreq = SPI_FREQUENCY_17MHZ;
1611 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001612 case 20:
1613 spifreq = SPI_FREQUENCY_20MHZ;
1614 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001615 case 30:
1616 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1617 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001618 case 33:
1619 spifreq = SPI_FREQUENCY_33MHZ;
1620 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001621 case 48:
1622 spifreq = SPI_FREQUENCY_48MHZ;
1623 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001624 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001625 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001626 break;
1627 default:
1628 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1629 inputfreq);
1630 print_usage(argv[0]);
1631 exit(EXIT_FAILURE);
1632 }
1633 mode_spifreq = 1;
1634 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001635 case 'e':
1636 mode_em100 = 1;
1637 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001638 case 'l':
1639 mode_locked = 1;
1640 if (mode_unlocked == 1) {
1641 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1642 exit(EXIT_FAILURE);
1643 }
1644 break;
1645 case 'u':
1646 mode_unlocked = 1;
1647 if (mode_locked == 1) {
1648 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1649 exit(EXIT_FAILURE);
1650 }
1651 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001652 case 'p':
1653 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001654 platform = PLATFORM_APL;
1655 } else if (!strcmp(optarg, "cnl")) {
1656 platform = PLATFORM_CNL;
1657 } else if (!strcmp(optarg, "glk")) {
1658 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301659 } else if (!strcmp(optarg, "icl")) {
1660 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301661 } else if (!strcmp(optarg, "jsl")) {
1662 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001663 } else if (!strcmp(optarg, "sklkbl")) {
1664 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001665 } else if (!strcmp(optarg, "tgl")) {
1666 platform = PLATFORM_TGL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001667 } else {
1668 fprintf(stderr, "Unknown platform: %s\n", optarg);
1669 exit(EXIT_FAILURE);
1670 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001671 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001672 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001673 case 't':
1674 mode_validate = 1;
1675 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001676 case 'v':
1677 print_version();
1678 exit(EXIT_SUCCESS);
1679 break;
1680 case 'h':
1681 case '?':
1682 default:
1683 print_usage(argv[0]);
1684 exit(EXIT_SUCCESS);
1685 break;
1686 }
1687 }
1688
Chris Douglass03ce0142014-02-26 13:30:13 -05001689 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001690 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001691 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001692 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001693 print_usage(argv[0]);
1694 exit(EXIT_FAILURE);
1695 }
1696
Chris Douglass03ce0142014-02-26 13:30:13 -05001697 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001698 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001699 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001700 fprintf(stderr, "You need to specify a mode.\n\n");
1701 print_usage(argv[0]);
1702 exit(EXIT_FAILURE);
1703 }
1704
1705 if (optind + 1 != argc) {
1706 fprintf(stderr, "You need to specify a file.\n\n");
1707 print_usage(argv[0]);
1708 exit(EXIT_FAILURE);
1709 }
1710
1711 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001712 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001713 if (bios_fd == -1) {
1714 perror("Could not open file");
1715 exit(EXIT_FAILURE);
1716 }
1717 struct stat buf;
1718 if (fstat(bios_fd, &buf) == -1) {
1719 perror("Could not stat file");
1720 exit(EXIT_FAILURE);
1721 }
1722 int size = buf.st_size;
1723
1724 printf("File %s is %d bytes\n", filename, size);
1725
1726 char *image = malloc(size);
1727 if (!image) {
1728 printf("Out of memory.\n");
1729 exit(EXIT_FAILURE);
1730 }
1731
1732 if (read(bios_fd, image, size) != size) {
1733 perror("Could not read file");
1734 exit(EXIT_FAILURE);
1735 }
1736
1737 close(bios_fd);
1738
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001739 // generate new filename
1740 if (new_filename == NULL) {
1741 new_filename = (char *) malloc((strlen(filename) + 5) * sizeof(char));
1742 if (!new_filename) {
1743 printf("Out of memory.\n");
1744 exit(EXIT_FAILURE);
1745 }
1746 // - 5: leave room for ".new\0"
1747 strcpy(new_filename, filename);
1748 strcat(new_filename, ".new");
1749 }
1750
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001751 check_ifd_version(image, size);
1752
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001753 if (mode_dump)
1754 dump_fd(image, size);
1755
Chris Douglass03ce0142014-02-26 13:30:13 -05001756 if (mode_layout)
1757 dump_layout(image, size, layout_fname);
1758
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001759 if (mode_extract)
1760 write_regions(image, size);
1761
Mathew Kingc7ddc992019-08-08 14:59:25 -06001762 if (mode_validate)
1763 validate_layout(image, size);
1764
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001765 if (mode_inject)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001766 inject_region(new_filename, image, size, region_type,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001767 region_fname);
1768
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001769 if (mode_newlayout)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001770 new_layout(new_filename, image, size, layout_fname);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001771
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001772 if (mode_spifreq)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001773 set_spi_frequency(new_filename, image, size, spifreq);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001774
Jan Tatjefa317512016-03-11 00:52:07 +01001775 if (mode_density)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001776 set_chipdensity(new_filename, image, size, new_density);
Jan Tatjefa317512016-03-11 00:52:07 +01001777
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001778 if (mode_em100)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001779 set_em100_mode(new_filename, image, size);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001780
Alexander Couzensd12ea112016-09-10 13:33:05 +02001781 if (mode_locked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001782 lock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001783
1784 if (mode_unlocked)
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001785 unlock_descriptor(new_filename, image, size);
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001786
Bill XIEb3e15a22017-09-07 18:34:50 +08001787 if (mode_altmedisable) {
1788 fpsba_t *fpsba = find_fpsba(image, size);
1789 fmsba_t *fmsba = find_fmsba(image, size);
1790 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001791 write_image(new_filename, image, size);
Bill XIEb3e15a22017-09-07 18:34:50 +08001792 }
1793
Marcello Sylvester Bauerdc1596c2020-02-11 13:31:38 +01001794 free(new_filename);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001795 free(image);
1796
1797 return 0;
1798}