blob: 0b6b2106478e8a726951218b4480ffc6fb00c587 [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{
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700634 printf(" SPI Componend Vendor ID: 0x%02x\n",
635 jid & 0xff);
Stefan Tauner27bb0662018-08-06 00:40:15 +0200636 printf(" SPI Componend Device ID 0: 0x%02x\n",
637 (jid >> 8) & 0xff);
638 printf(" SPI Componend Device ID 1: 0x%02x\n",
639 (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{
857 char new_filename[FILENAME_MAX]; // allow long file names
858 int new_fd;
859
Patrick Georgi440daf72014-08-03 12:14:25 +0200860 // - 5: leave room for ".new\0"
861 strncpy(new_filename, filename, FILENAME_MAX - 5);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700862 strncat(new_filename, ".new", FILENAME_MAX - strlen(filename));
863
864 printf("Writing new image to %s\n", new_filename);
865
866 // Now write out new image
867 new_fd = open(new_filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600868 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700869 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200870 if (new_fd < 0) {
871 perror("Error while trying to open file");
872 exit(EXIT_FAILURE);
873 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700874 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700875 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700876 close(new_fd);
877}
878
Bill XIEfa5f9942017-09-12 11:22:29 +0800879static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700880 enum spi_frequency freq)
881{
Bill XIE612ec0e2017-08-30 16:10:27 +0800882 fcba_t *fcba = find_fcba(image, size);
883 if (!fcba)
884 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700885
886 /* clear bits 21-29 */
887 fcba->flcomp &= ~0x3fe00000;
888 /* Read ID and Read Status Clock Frequency */
889 fcba->flcomp |= freq << 27;
890 /* Write and Erase Clock Frequency */
891 fcba->flcomp |= freq << 24;
892 /* Fast Read Clock Frequency */
893 fcba->flcomp |= freq << 21;
894
895 write_image(filename, image, size);
896}
897
Bill XIEfa5f9942017-09-12 11:22:29 +0800898static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700899{
Bill XIE612ec0e2017-08-30 16:10:27 +0800900 fcba_t *fcba = find_fcba(image, size);
901 if (!fcba)
902 exit(EXIT_FAILURE);
903
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700904 int freq;
905
906 switch (ifd_version) {
907 case IFD_VERSION_1:
908 freq = SPI_FREQUENCY_20MHZ;
909 break;
910 case IFD_VERSION_2:
911 freq = SPI_FREQUENCY_17MHZ;
912 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -0700913 default:
914 freq = SPI_FREQUENCY_17MHZ;
915 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700916 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700917
918 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700919 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700920}
921
Bill XIEfa5f9942017-09-12 11:22:29 +0800922static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +0100923 unsigned int density)
924{
Bill XIE612ec0e2017-08-30 16:10:27 +0800925 fcba_t *fcba = find_fcba(image, size);
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200926 uint8_t mask, chip2_offset;
Bill XIE612ec0e2017-08-30 16:10:27 +0800927 if (!fcba)
928 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +0100929
930 printf("Setting chip density to ");
931 decode_component_density(density);
932 printf("\n");
933
934 switch (ifd_version) {
935 case IFD_VERSION_1:
936 /* fail if selected density is not supported by this version */
937 if ( (density == COMPONENT_DENSITY_32MB) ||
938 (density == COMPONENT_DENSITY_64MB) ||
939 (density == COMPONENT_DENSITY_UNUSED) ) {
940 printf("error: Selected density not supported in IFD version 1.\n");
941 exit(EXIT_FAILURE);
942 }
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200943 mask = 0x7;
944 chip2_offset = 3;
Jan Tatjefa317512016-03-11 00:52:07 +0100945 break;
946 case IFD_VERSION_2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200947 mask = 0xf;
948 chip2_offset = 4;
949 break;
Jan Tatjefa317512016-03-11 00:52:07 +0100950 default:
951 printf("error: Unknown IFD version\n");
952 exit(EXIT_FAILURE);
953 break;
954 }
955
956 /* clear chip density for corresponding chip */
957 switch (selected_chip) {
958 case 1:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200959 fcba->flcomp &= ~mask;
Jan Tatjefa317512016-03-11 00:52:07 +0100960 break;
961 case 2:
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200962 fcba->flcomp &= ~(mask << chip2_offset);
Jan Tatjefa317512016-03-11 00:52:07 +0100963 break;
964 default: /*both chips*/
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200965 fcba->flcomp &= ~(mask | (mask << chip2_offset));
Jan Tatjefa317512016-03-11 00:52:07 +0100966 break;
967 }
968
969 /* set the new density */
970 if (selected_chip == 1 || selected_chip == 0)
971 fcba->flcomp |= (density); /* first chip */
972 if (selected_chip == 2 || selected_chip == 0)
Arthur Heymans4cb888e2019-10-17 19:37:45 +0200973 fcba->flcomp |= (density << chip2_offset); /* second chip */
Jan Tatjefa317512016-03-11 00:52:07 +0100974
975 write_image(filename, image, size);
976}
977
Duncan Laurie7775d672019-06-06 13:39:26 -0700978static int check_region(const frba_t *frba, unsigned int region_type)
979{
980 region_t region;
981
982 if (!frba)
983 return 0;
984
985 region = get_region(frba, region_type);
986 return !!((region.base < region.limit) && (region.size > 0));
987}
988
Bill XIEfa5f9942017-09-12 11:22:29 +0800989static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700990{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700991 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +0800992 fmba_t *fmba = find_fmba(image, size);
Duncan Laurie7775d672019-06-06 13:39:26 -0700993 const frba_t *frba = find_frba(image, size);
Bill XIE612ec0e2017-08-30 16:10:27 +0800994 if (!fmba)
995 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700996
997 if (ifd_version >= IFD_VERSION_2) {
998 wr_shift = FLMSTR_WR_SHIFT_V2;
999 rd_shift = FLMSTR_RD_SHIFT_V2;
1000
1001 /* Clear non-reserved bits */
1002 fmba->flmstr1 &= 0xff;
1003 fmba->flmstr2 &= 0xff;
1004 fmba->flmstr3 &= 0xff;
Lijian Zhao9871b042019-01-26 16:48:38 -08001005 fmba->flmstr5 &= 0xff;
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001006 } else {
1007 wr_shift = FLMSTR_WR_SHIFT_V1;
1008 rd_shift = FLMSTR_RD_SHIFT_V1;
1009
1010 fmba->flmstr1 = 0;
1011 fmba->flmstr2 = 0;
1012 /* Requestor ID */
1013 fmba->flmstr3 = 0x118;
1014 }
1015
Andrey Petrov96ecb772016-10-31 19:31:54 -07001016 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001017 case PLATFORM_APL:
1018 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -07001019 /* CPU/BIOS can read descriptor and BIOS */
1020 fmba->flmstr1 |= 0x3 << rd_shift;
1021 /* CPU/BIOS can write BIOS */
1022 fmba->flmstr1 |= 0x2 << wr_shift;
1023 /* TXE can read descriptor, BIOS and Device Expansion */
1024 fmba->flmstr2 |= 0x23 << rd_shift;
1025 /* TXE can only write Device Expansion */
1026 fmba->flmstr2 |= 0x20 << wr_shift;
1027 break;
Lijian Zhao3e88b182019-01-25 23:20:16 -08001028 case PLATFORM_CNL:
1029 case PLATFORM_ICL:
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001030 case PLATFORM_SKLKBL:
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001031 case PLATFORM_TGL:
Duncan Laurie7775d672019-06-06 13:39:26 -07001032 /* CPU/BIOS can read descriptor and BIOS. */
1033 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1034 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1035 /* CPU/BIOS can write BIOS. */
1036 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1037 /* ME can read descriptor and ME. */
1038 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1039 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001040 /* ME can write ME. */
Duncan Laurie7775d672019-06-06 13:39:26 -07001041 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1042 if (check_region(frba, REGION_GBE)) {
1043 /* BIOS can read/write GbE. */
1044 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1045 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1046 /* ME can read GbE. */
1047 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1048 /* GbE can read descriptor and read/write GbE.. */
1049 fmba->flmstr3 |= (1 << REGION_DESC) << rd_shift;
1050 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1051 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1052 }
1053 if (check_region(frba, REGION_PDR)) {
1054 /* BIOS can read/write PDR. */
1055 fmba->flmstr1 |= (1 << REGION_PDR) << rd_shift;
1056 fmba->flmstr1 |= (1 << REGION_PDR) << wr_shift;
1057 }
1058 if (check_region(frba, REGION_EC)) {
1059 /* BIOS can read EC. */
1060 fmba->flmstr1 |= (1 << REGION_EC) << rd_shift;
1061 /* EC can read descriptor and read/write EC. */
1062 fmba->flmstr5 |= (1 << REGION_DESC) << rd_shift;
1063 fmba->flmstr5 |= (1 << REGION_EC) << rd_shift;
1064 fmba->flmstr5 |= (1 << REGION_EC) << wr_shift;
1065 }
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001066 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001067 default:
Duncan Laurie7775d672019-06-06 13:39:26 -07001068 /* CPU/BIOS can read descriptor and BIOS. */
1069 fmba->flmstr1 |= (1 << REGION_DESC) << rd_shift;
1070 fmba->flmstr1 |= (1 << REGION_BIOS) << rd_shift;
1071 /* CPU/BIOS can write BIOS. */
1072 fmba->flmstr1 |= (1 << REGION_BIOS) << wr_shift;
1073 /* ME can read descriptor and ME. */
1074 fmba->flmstr2 |= (1 << REGION_DESC) << rd_shift;
1075 fmba->flmstr2 |= (1 << REGION_ME) << rd_shift;
1076 /* ME can write ME. */
1077 fmba->flmstr2 |= (1 << REGION_ME) << wr_shift;
1078 if (check_region(frba, REGION_GBE)) {
1079 /* BIOS can read GbE. */
1080 fmba->flmstr1 |= (1 << REGION_GBE) << rd_shift;
1081 /* BIOS can write GbE. */
1082 fmba->flmstr1 |= (1 << REGION_GBE) << wr_shift;
1083 /* ME can read GbE. */
1084 fmba->flmstr2 |= (1 << REGION_GBE) << rd_shift;
1085 /* ME can write GbE. */
1086 fmba->flmstr2 |= (1 << REGION_GBE) << wr_shift;
1087 /* GbE can write GbE. */
1088 fmba->flmstr3 |= (1 << REGION_GBE) << rd_shift;
1089 /* GbE can read GbE. */
1090 fmba->flmstr3 |= (1 << REGION_GBE) << wr_shift;
1091 }
Andrey Petrov96ecb772016-10-31 19:31:54 -07001092 break;
1093 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001094
1095 write_image(filename, image, size);
1096}
1097
Bill XIEfa5f9942017-09-12 11:22:29 +08001098static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001099{
Bill XIE612ec0e2017-08-30 16:10:27 +08001100 fmba_t *fmba = find_fmba(image, size);
1101 if (!fmba)
1102 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001103
1104 if (ifd_version >= IFD_VERSION_2) {
1105 /* Access bits for each region are read: 19:8 write: 31:20 */
1106 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
1107 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
1108 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
Lijian Zhao9871b042019-01-26 16:48:38 -08001109 fmba->flmstr5 = 0xffffff00 | (fmba->flmstr5 & 0xff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001110 } else {
1111 fmba->flmstr1 = 0xffff0000;
1112 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +01001113 /* Keep chipset specific Requester ID */
1114 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -07001115 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001116
1117 write_image(filename, image, size);
1118}
1119
Bill XIEb3e15a22017-09-07 18:34:50 +08001120/* Set the AltMeDisable (or HAP for >= IFD_VERSION_2) */
Jacob Garber595d9262019-06-27 17:33:10 -06001121static void fpsba_set_altmedisable(fpsba_t *fpsba, fmsba_t *fmsba, bool altmedisable)
Bill XIEb3e15a22017-09-07 18:34:50 +08001122{
1123 if (ifd_version >= IFD_VERSION_2) {
1124 printf("%sting the HAP bit to %s Intel ME...\n",
1125 altmedisable?"Set":"Unset",
1126 altmedisable?"disable":"enable");
1127 if (altmedisable)
1128 fpsba->pchstrp[0] |= (1 << 16);
1129 else
1130 fpsba->pchstrp[0] &= ~(1 << 16);
1131 } else {
1132 if (chipset >= CHIPSET_ICH8 && chipset <= CHIPSET_ICH10) {
1133 printf("%sting the ICH_MeDisable, MCH_MeDisable, "
1134 "and MCH_AltMeDisable to %s Intel ME...\n",
1135 altmedisable?"Set":"Unset",
1136 altmedisable?"disable":"enable");
1137 if (altmedisable) {
1138 /* MCH_MeDisable */
1139 fmsba->data[0] |= 1;
1140 /* MCH_AltMeDisable */
1141 fmsba->data[0] |= (1 << 7);
1142 /* ICH_MeDisable */
1143 fpsba->pchstrp[0] |= 1;
1144 } else {
1145 fmsba->data[0] &= ~1;
1146 fmsba->data[0] &= ~(1 << 7);
1147 fpsba->pchstrp[0] &= ~1;
1148 }
1149 } else {
1150 printf("%sting the AltMeDisable to %s Intel ME...\n",
1151 altmedisable?"Set":"Unset",
1152 altmedisable?"disable":"enable");
1153 if (altmedisable)
1154 fpsba->pchstrp[10] |= (1 << 7);
1155 else
1156 fpsba->pchstrp[10] &= ~(1 << 7);
1157 }
1158 }
1159}
1160
Jacob Garber595d9262019-06-27 17:33:10 -06001161static void inject_region(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001162 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001163{
Bill XIE612ec0e2017-08-30 16:10:27 +08001164 frba_t *frba = find_frba(image, size);
1165 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001166 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -07001167
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001168 region_t region = get_region(frba, region_type);
1169 if (region.size <= 0xfff) {
1170 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
1171 region_name(region_type));
1172 exit(EXIT_FAILURE);
1173 }
1174
Scott Duplichanf2c98372014-12-12 21:03:06 -06001175 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001176 if (region_fd == -1) {
1177 perror("Could not open file");
1178 exit(EXIT_FAILURE);
1179 }
1180 struct stat buf;
1181 if (fstat(region_fd, &buf) == -1) {
1182 perror("Could not stat file");
1183 exit(EXIT_FAILURE);
1184 }
1185 int region_size = buf.st_size;
1186
1187 printf("File %s is %d bytes\n", region_fname, region_size);
1188
1189 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -08001190 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001191 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1192 " bytes. Not injecting.\n",
1193 region_name(region_type), region.size,
1194 region.size, region_size, region_size);
1195 exit(EXIT_FAILURE);
1196 }
1197
1198 int offset = 0;
1199 if ((region_type == 1) && (region_size < region.size)) {
1200 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
1201 " bytes. Padding before injecting.\n",
1202 region_name(region_type), region.size,
1203 region.size, region_size, region_size);
1204 offset = region.size - region_size;
1205 memset(image + region.base, 0xff, offset);
1206 }
1207
Stefan Reinauer5e93b372012-09-25 13:30:48 -07001208 if (size < region.base + offset + region_size) {
1209 fprintf(stderr, "Output file is too small. (%d < %d)\n",
1210 size, region.base + offset + region_size);
1211 exit(EXIT_FAILURE);
1212 }
1213
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001214 if (read(region_fd, image + region.base + offset, region_size)
1215 != region_size) {
1216 perror("Could not read file");
1217 exit(EXIT_FAILURE);
1218 }
1219
1220 close(region_fd);
1221
1222 printf("Adding %s as the %s section of %s\n",
1223 region_fname, region_name(region_type), filename);
1224 write_image(filename, image, size);
1225}
1226
Jacob Garber595d9262019-06-27 17:33:10 -06001227static unsigned int next_pow2(unsigned int x)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001228{
1229 unsigned int y = 1;
1230 if (x == 0)
1231 return 0;
1232 while (y <= x)
1233 y = y << 1;
1234
1235 return y;
1236}
1237
1238/**
1239 * Determine if two memory regions overlap.
1240 *
1241 * @param r1, r2 Memory regions to compare.
Elyes HAOUASa1ccaed2018-08-24 07:58:00 +02001242 * @return 0 if the two regions are separate
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001243 * @return 1 if the two regions overlap
1244 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001245static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001246{
Bill XIEfa5f9942017-09-12 11:22:29 +08001247 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001248 return 0;
1249
Nico Huber844eda02019-01-05 00:06:19 +01001250 /* r1 should be either completely below or completely above r2 */
1251 return !(r1->limit < r2->base || r1->base > r2->limit);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001252}
1253
Jacob Garber595d9262019-06-27 17:33:10 -06001254static void new_layout(const char *filename, char *image, int size,
Bill XIEfa5f9942017-09-12 11:22:29 +08001255 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001256{
1257 FILE *romlayout;
1258 char tempstr[256];
1259 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001260 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001261 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001262 region_t current_regions[MAX_REGIONS];
1263 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001264 int new_extent = 0;
1265 char *new_image;
1266
1267 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001268 frba_t *frba = find_frba(image, size);
1269 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001270 exit(EXIT_FAILURE);
1271
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001272 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001273 current_regions[i] = get_region(frba, i);
1274 new_regions[i] = get_region(frba, i);
1275 }
1276
1277 /* read new layout */
1278 romlayout = fopen(layout_fname, "r");
1279
1280 if (!romlayout) {
1281 perror("Could not read layout file.\n");
1282 exit(EXIT_FAILURE);
1283 }
1284
1285 while (!feof(romlayout)) {
1286 char *tstr1, *tstr2;
1287
Patrick Georgi802ad522014-08-09 17:12:23 +02001288 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001289 layout_region_name))
1290 continue;
1291
1292 region_number = region_num(layout_region_name);
1293 if (region_number < 0)
1294 continue;
1295
1296 tstr1 = strtok(tempstr, ":");
1297 tstr2 = strtok(NULL, ":");
1298 if (!tstr1 || !tstr2) {
1299 fprintf(stderr, "Could not parse layout file.\n");
1300 exit(EXIT_FAILURE);
1301 }
1302 new_regions[region_number].base = strtol(tstr1,
1303 (char **)NULL, 16);
1304 new_regions[region_number].limit = strtol(tstr2,
1305 (char **)NULL, 16);
1306 new_regions[region_number].size =
1307 new_regions[region_number].limit -
1308 new_regions[region_number].base + 1;
1309
1310 if (new_regions[region_number].size < 0)
1311 new_regions[region_number].size = 0;
1312 }
1313 fclose(romlayout);
1314
1315 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001316 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001317 if (new_regions[i].size == 0)
1318 continue;
1319
1320 if (new_regions[i].size < current_regions[i].size) {
1321 printf("DANGER: Region %s is shrinking.\n",
1322 region_name(i));
1323 printf(" The region will be truncated to fit.\n");
1324 printf(" This may result in an unusable image.\n");
1325 }
1326
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001327 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001328 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001329 fprintf(stderr, "Regions would overlap.\n");
1330 exit(EXIT_FAILURE);
1331 }
1332 }
1333
1334 /* detect if the image size should grow */
1335 if (new_extent < new_regions[i].limit)
1336 new_extent = new_regions[i].limit;
1337 }
1338
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 }
1345
1346 /* copy regions to a new image */
1347 new_image = malloc(new_extent);
1348 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001349 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001350 int copy_size = new_regions[i].size;
1351 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001352 const region_t *current = &current_regions[i];
1353 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001354
Bill XIEfa5f9942017-09-12 11:22:29 +08001355 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001356 continue;
1357
Bill XIEfa5f9942017-09-12 11:22:29 +08001358 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001359 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001360 copy_size = current->size;
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001361 if (i == REGION_BIOS)
1362 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001363 }
1364
Wim Vervoorn05bc9b32020-01-17 13:48:00 +01001365 if ((i == REGION_BIOS) && (new->size < current->size)) {
1366 /* copy BIOS region to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001367 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001368 }
1369
1370 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1371 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001372 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1373 offset_current, current->limit, current->size);
1374 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1375 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001376
Bill XIEfa5f9942017-09-12 11:22:29 +08001377 memcpy(new_image + new->base + offset_new,
1378 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001379 copy_size);
1380 }
1381
1382 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001383 frba = find_frba(new_image, new_extent);
1384 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001385 exit(EXIT_FAILURE);
1386
Bill XIE612ec0e2017-08-30 16:10:27 +08001387 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001388 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001389
1390 write_image(filename, new_image, new_extent);
1391 free(new_image);
1392}
1393
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001394static void print_version(void)
1395{
1396 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1397 printf("Copyright (C) 2011 Google Inc.\n\n");
1398 printf
1399 ("This program is free software: you can redistribute it and/or modify\n"
1400 "it under the terms of the GNU General Public License as published by\n"
1401 "the Free Software Foundation, version 2 of the License.\n\n"
1402 "This program is distributed in the hope that it will be useful,\n"
1403 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1404 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001405 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001406}
1407
1408static void print_usage(const char *name)
1409{
1410 printf("usage: %s [-vhdix?] <filename>\n", name);
1411 printf("\n"
Arthur Heymans4cb888e2019-10-17 19:37:45 +02001412 " -d | --dump: dump intel firmware descriptor\n"
1413 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1414 " -t | --validate Validate that the firmware descriptor layout matches the fmap layout\n"
1415 " -x | --extract: extract intel fd modules\n"
1416 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1417 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
1418 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1419 " -D | --density <512|1|2|4|8|16|32|64> set chip density (512 in KByte, others in MByte)\n"
1420 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1421 " can only be used once per run:\n"
1422 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
1423 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1424 " Dual Output Fast Read Support\n"
1425 " -l | --lock Lock firmware descriptor and ME region\n"
1426 " -u | --unlock Unlock firmware descriptor and ME region\n"
1427 " -M | --altmedisable <0|1> Set the AltMeDisable (or HAP for skylake or newer platform)\n"
1428 " bit to disable ME\n"
1429 " -p | --platform Add platform-specific quirks\n"
1430 " aplk - Apollo Lake\n"
1431 " cnl - Cannon Lake\n"
1432 " glk - Gemini Lake\n"
1433 " sklkbl - Skylake/Kaby Lake\n"
1434 " -v | --version: print the version\n"
1435 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001436 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1437 "\n");
1438}
1439
1440int main(int argc, char *argv[])
1441{
1442 int opt, option_index = 0;
1443 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001444 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001445 int mode_layout = 0, mode_newlayout = 0, mode_density = 0;
Bill XIEb3e15a22017-09-07 18:34:50 +08001446 int mode_altmedisable = 0, altmedisable = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001447 char *region_type_string = NULL, *region_fname = NULL;
1448 const char *layout_fname = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001449 int region_type = -1, inputfreq = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001450 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001451 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1452
Bill XIEfa5f9942017-09-12 11:22:29 +08001453 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001454 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001455 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001456 {"extract", 0, NULL, 'x'},
1457 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001458 {"newlayout", 1, NULL, 'n'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001459 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001460 {"density", 1, NULL, 'D'},
1461 {"chip", 1, NULL, 'C'},
Bill XIEb3e15a22017-09-07 18:34:50 +08001462 {"altmedisable", 1, NULL, 'M'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001463 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001464 {"lock", 0, NULL, 'l'},
1465 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001466 {"version", 0, NULL, 'v'},
1467 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001468 {"platform", 0, NULL, 'p'},
Mathew Kingc7ddc992019-08-08 14:59:25 -06001469 {"validate", 0, NULL, 't'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001470 {0, 0, 0, 0}
1471 };
1472
Mathew Kingc7ddc992019-08-08 14:59:25 -06001473 while ((opt = getopt_long(argc, argv, "df:D:C:M:xi:n:s:p:eluvth?",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001474 long_options, &option_index)) != EOF) {
1475 switch (opt) {
1476 case 'd':
1477 mode_dump = 1;
1478 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001479 case 'f':
1480 mode_layout = 1;
1481 layout_fname = strdup(optarg);
1482 if (!layout_fname) {
1483 fprintf(stderr, "No layout file specified\n");
1484 print_usage(argv[0]);
1485 exit(EXIT_FAILURE);
1486 }
1487 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001488 case 'x':
1489 mode_extract = 1;
1490 break;
1491 case 'i':
1492 // separate type and file name
1493 region_type_string = strdup(optarg);
1494 region_fname = strchr(region_type_string, ':');
1495 if (!region_fname) {
1496 print_usage(argv[0]);
1497 exit(EXIT_FAILURE);
1498 }
1499 region_fname[0] = '\0';
1500 region_fname++;
1501 // Descriptor, BIOS, ME, GbE, Platform
1502 // valid type?
1503 if (!strcasecmp("Descriptor", region_type_string))
1504 region_type = 0;
1505 else if (!strcasecmp("BIOS", region_type_string))
1506 region_type = 1;
1507 else if (!strcasecmp("ME", region_type_string))
1508 region_type = 2;
1509 else if (!strcasecmp("GbE", region_type_string))
1510 region_type = 3;
1511 else if (!strcasecmp("Platform", region_type_string))
1512 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001513 else if (!strcasecmp("EC", region_type_string))
1514 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001515 if (region_type == -1) {
1516 fprintf(stderr, "No such region type: '%s'\n\n",
1517 region_type_string);
1518 print_usage(argv[0]);
1519 exit(EXIT_FAILURE);
1520 }
1521 mode_inject = 1;
1522 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001523 case 'n':
1524 mode_newlayout = 1;
1525 layout_fname = strdup(optarg);
1526 if (!layout_fname) {
1527 fprintf(stderr, "No layout file specified\n");
1528 print_usage(argv[0]);
1529 exit(EXIT_FAILURE);
1530 }
1531 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001532 case 'D':
1533 mode_density = 1;
1534 new_density = strtoul(optarg, NULL, 0);
1535 switch (new_density) {
1536 case 512:
1537 new_density = COMPONENT_DENSITY_512KB;
1538 break;
1539 case 1:
1540 new_density = COMPONENT_DENSITY_1MB;
1541 break;
1542 case 2:
1543 new_density = COMPONENT_DENSITY_2MB;
1544 break;
1545 case 4:
1546 new_density = COMPONENT_DENSITY_4MB;
1547 break;
1548 case 8:
1549 new_density = COMPONENT_DENSITY_8MB;
1550 break;
1551 case 16:
1552 new_density = COMPONENT_DENSITY_16MB;
1553 break;
1554 case 32:
1555 new_density = COMPONENT_DENSITY_32MB;
1556 break;
1557 case 64:
1558 new_density = COMPONENT_DENSITY_64MB;
1559 break;
1560 case 0:
1561 new_density = COMPONENT_DENSITY_UNUSED;
1562 break;
1563 default:
1564 printf("error: Unknown density\n");
1565 print_usage(argv[0]);
1566 exit(EXIT_FAILURE);
1567 }
1568 break;
1569 case 'C':
1570 selected_chip = strtol(optarg, NULL, 0);
1571 if (selected_chip > 2) {
1572 fprintf(stderr, "error: Invalid chip selection\n");
1573 print_usage(argv[0]);
1574 exit(EXIT_FAILURE);
1575 }
1576 break;
Bill XIEb3e15a22017-09-07 18:34:50 +08001577 case 'M':
1578 mode_altmedisable = 1;
1579 altmedisable = strtol(optarg, NULL, 0);
1580 if (altmedisable > 1) {
1581 fprintf(stderr, "error: Illegal value\n");
1582 print_usage(argv[0]);
1583 exit(EXIT_FAILURE);
1584 }
1585 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001586 case 's':
1587 // Parse the requested SPI frequency
1588 inputfreq = strtol(optarg, NULL, 0);
1589 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001590 case 17:
1591 spifreq = SPI_FREQUENCY_17MHZ;
1592 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001593 case 20:
1594 spifreq = SPI_FREQUENCY_20MHZ;
1595 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001596 case 30:
1597 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1598 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001599 case 33:
1600 spifreq = SPI_FREQUENCY_33MHZ;
1601 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001602 case 48:
1603 spifreq = SPI_FREQUENCY_48MHZ;
1604 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001605 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001606 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001607 break;
1608 default:
1609 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1610 inputfreq);
1611 print_usage(argv[0]);
1612 exit(EXIT_FAILURE);
1613 }
1614 mode_spifreq = 1;
1615 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001616 case 'e':
1617 mode_em100 = 1;
1618 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001619 case 'l':
1620 mode_locked = 1;
1621 if (mode_unlocked == 1) {
1622 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1623 exit(EXIT_FAILURE);
1624 }
1625 break;
1626 case 'u':
1627 mode_unlocked = 1;
1628 if (mode_locked == 1) {
1629 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1630 exit(EXIT_FAILURE);
1631 }
1632 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001633 case 'p':
1634 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001635 platform = PLATFORM_APL;
1636 } else if (!strcmp(optarg, "cnl")) {
1637 platform = PLATFORM_CNL;
1638 } else if (!strcmp(optarg, "glk")) {
1639 platform = PLATFORM_GLK;
Aamir Bohra1018be22018-06-29 15:08:50 +05301640 } else if (!strcmp(optarg, "icl")) {
1641 platform = PLATFORM_ICL;
rkanabard64b0462019-08-30 11:40:08 +05301642 } else if (!strcmp(optarg, "jsl")) {
1643 platform = PLATFORM_JSL;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001644 } else if (!strcmp(optarg, "sklkbl")) {
1645 platform = PLATFORM_SKLKBL;
Ravi Sarawadi7d9d63b2019-10-22 13:45:36 -07001646 } else if (!strcmp(optarg, "tgl")) {
1647 platform = PLATFORM_TGL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001648 } else {
1649 fprintf(stderr, "Unknown platform: %s\n", optarg);
1650 exit(EXIT_FAILURE);
1651 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001652 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001653 break;
Mathew Kingc7ddc992019-08-08 14:59:25 -06001654 case 't':
1655 mode_validate = 1;
1656 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001657 case 'v':
1658 print_version();
1659 exit(EXIT_SUCCESS);
1660 break;
1661 case 'h':
1662 case '?':
1663 default:
1664 print_usage(argv[0]);
1665 exit(EXIT_SUCCESS);
1666 break;
1667 }
1668 }
1669
Chris Douglass03ce0142014-02-26 13:30:13 -05001670 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001671 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Samuel Hollanddc9025c2019-10-14 20:28:37 -05001672 mode_locked) + mode_altmedisable + mode_validate) > 1) {
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001673 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001674 print_usage(argv[0]);
1675 exit(EXIT_FAILURE);
1676 }
1677
Chris Douglass03ce0142014-02-26 13:30:13 -05001678 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001679 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Mathew Kingc7ddc992019-08-08 14:59:25 -06001680 mode_unlocked + mode_density + mode_altmedisable + mode_validate) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001681 fprintf(stderr, "You need to specify a mode.\n\n");
1682 print_usage(argv[0]);
1683 exit(EXIT_FAILURE);
1684 }
1685
1686 if (optind + 1 != argc) {
1687 fprintf(stderr, "You need to specify a file.\n\n");
1688 print_usage(argv[0]);
1689 exit(EXIT_FAILURE);
1690 }
1691
1692 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001693 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001694 if (bios_fd == -1) {
1695 perror("Could not open file");
1696 exit(EXIT_FAILURE);
1697 }
1698 struct stat buf;
1699 if (fstat(bios_fd, &buf) == -1) {
1700 perror("Could not stat file");
1701 exit(EXIT_FAILURE);
1702 }
1703 int size = buf.st_size;
1704
1705 printf("File %s is %d bytes\n", filename, size);
1706
1707 char *image = malloc(size);
1708 if (!image) {
1709 printf("Out of memory.\n");
1710 exit(EXIT_FAILURE);
1711 }
1712
1713 if (read(bios_fd, image, size) != size) {
1714 perror("Could not read file");
1715 exit(EXIT_FAILURE);
1716 }
1717
1718 close(bios_fd);
1719
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001720 check_ifd_version(image, size);
1721
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001722 if (mode_dump)
1723 dump_fd(image, size);
1724
Chris Douglass03ce0142014-02-26 13:30:13 -05001725 if (mode_layout)
1726 dump_layout(image, size, layout_fname);
1727
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001728 if (mode_extract)
1729 write_regions(image, size);
1730
Mathew Kingc7ddc992019-08-08 14:59:25 -06001731 if (mode_validate)
1732 validate_layout(image, size);
1733
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001734 if (mode_inject)
1735 inject_region(filename, image, size, region_type,
1736 region_fname);
1737
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001738 if (mode_newlayout)
1739 new_layout(filename, image, size, layout_fname);
1740
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001741 if (mode_spifreq)
1742 set_spi_frequency(filename, image, size, spifreq);
1743
Jan Tatjefa317512016-03-11 00:52:07 +01001744 if (mode_density)
1745 set_chipdensity(filename, image, size, new_density);
1746
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001747 if (mode_em100)
1748 set_em100_mode(filename, image, size);
1749
Alexander Couzensd12ea112016-09-10 13:33:05 +02001750 if (mode_locked)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001751 lock_descriptor(filename, image, size);
1752
1753 if (mode_unlocked)
1754 unlock_descriptor(filename, image, size);
1755
Bill XIEb3e15a22017-09-07 18:34:50 +08001756 if (mode_altmedisable) {
1757 fpsba_t *fpsba = find_fpsba(image, size);
1758 fmsba_t *fmsba = find_fmsba(image, size);
1759 fpsba_set_altmedisable(fpsba, fmsba, altmedisable);
1760 write_image(filename, image, size);
1761 }
1762
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001763 free(image);
1764
1765 return 0;
1766}