blob: d99bdb9dc8e3f0bd224ae2b19d73c7a43ee81704 [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>
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070025#include "ifdtool.h"
26
Scott Duplichanf2c98372014-12-12 21:03:06 -060027#ifndef O_BINARY
28#define O_BINARY 0
29#endif
30
Bill XIE612ec0e2017-08-30 16:10:27 +080031/**
32 * PTR_IN_RANGE - examine whether a pointer falls in [base, base + limit)
33 * @param ptr: the non-void* pointer to a single arbitrary-sized object.
34 * @param base: base address represented with char* type.
35 * @param limit: upper limit of the legal address.
36 *
37 */
38#define PTR_IN_RANGE(ptr, base, limit) \
39 ((const char *)(ptr) >= (base) && \
40 (const char *)&(ptr)[1] <= (base) + (limit))
41
Duncan Laurie1f7fd722015-06-22 11:14:48 -070042static int ifd_version;
Bill XIEfa5f9942017-09-12 11:22:29 +080043static unsigned int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010044static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070045static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050046
Duncan Laurie1f7fd722015-06-22 11:14:48 -070047static const struct region_name region_names[MAX_REGIONS] = {
Bill XIE1bf65062017-09-12 11:31:37 +080048 { "Flash Descriptor", "fd", "flashregion_0_flashdescriptor.bin" },
49 { "BIOS", "bios", "flashregion_1_bios.bin" },
50 { "Intel ME", "me", "flashregion_2_intel_me.bin" },
51 { "GbE", "gbe", "flashregion_3_gbe.bin" },
52 { "Platform Data", "pd", "flashregion_4_platform_data.bin" },
53 { "Reserved", "res1", "flashregion_5_reserved.bin" },
54 { "Reserved", "res2", "flashregion_6_reserved.bin" },
55 { "Reserved", "res3", "flashregion_7_reserved.bin" },
56 { "EC", "ec", "flashregion_8_ec.bin" },
Chris Douglass03ce0142014-02-26 13:30:13 -050057};
58
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070059static fdbar_t *find_fd(char *image, int size)
60{
61 int i, found = 0;
62
63 /* Scan for FD signature */
64 for (i = 0; i < (size - 4); i += 4) {
65 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
66 found = 1;
67 break; // signature found.
68 }
69 }
70
71 if (!found) {
72 printf("No Flash Descriptor found in this image\n");
73 return NULL;
74 }
75
Bill XIE612ec0e2017-08-30 16:10:27 +080076 fdbar_t *fdb = (fdbar_t *) (image + i);
77 return PTR_IN_RANGE(fdb, image, size) ? fdb : NULL;
78}
79
80static fcba_t *find_fcba(char *image, int size)
81{
82 fdbar_t *fdb = find_fd(image, size);
83 if (!fdb)
84 return NULL;
85 fcba_t *fcba = (fcba_t *) (image + ((fdb->flmap0 & 0xff) << 4));
86 return PTR_IN_RANGE(fcba, image, size) ? fcba : NULL;
87
88}
89
90static fmba_t *find_fmba(char *image, int size)
91{
92 fdbar_t *fdb = find_fd(image, size);
93 if (!fdb)
94 return NULL;
95 fmba_t *fmba = (fmba_t *) (image + ((fdb->flmap1 & 0xff) << 4));
96 return PTR_IN_RANGE(fmba, image, size) ? fmba : NULL;
97}
98
99static frba_t *find_frba(char *image, int size)
100{
101 fdbar_t *fdb = find_fd(image, size);
102 if (!fdb)
103 return NULL;
104 frba_t *frba =
105 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
106 return PTR_IN_RANGE(frba, image, size) ? frba : NULL;
107}
108
109static fpsba_t *find_fpsba(char *image, int size)
110{
111 fdbar_t *fdb = find_fd(image, size);
112 if (!fdb)
113 return NULL;
114 fpsba_t *fpsba =
115 (fpsba_t *) (image + (((fdb->flmap1 >> 16) & 0xff) << 4));
116 return PTR_IN_RANGE(fpsba, image, size) ? fpsba : NULL;
117}
118
119static fmsba_t *find_fmsba(char *image, int size)
120{
121 fdbar_t *fdb = find_fd(image, size);
122 if (!fdb)
123 return NULL;
124 fmsba_t *fmsba = (fmsba_t *) (image + ((fdb->flmap2 & 0xff) << 4));
125 return PTR_IN_RANGE(fmsba, image, size) ? fmsba : NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700126}
127
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700128/*
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700129 * Some newer platforms have re-defined the FCBA field that was used to
130 * distinguish IFD v1 v/s v2. Define a list of platforms that we know do not
131 * have the required FCBA field, but are IFD v2 and return true if current
132 * platform is one of them.
133 */
134static int is_platform_ifd_2(void)
135{
136 static const int ifd_2_platforms[] = {
137 PLATFORM_GLK,
138 PLATFORM_CNL,
139 };
140 unsigned int i;
141
142 for (i = 0; i < ARRAY_SIZE(ifd_2_platforms); i++) {
143 if (platform == ifd_2_platforms[i])
144 return 1;
145 }
146
147 return 0;
148}
149
150/*
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700151 * There is no version field in the descriptor so to determine
152 * if this is a new descriptor format we check the hardcoded SPI
153 * read frequency to see if it is fixed at 20MHz or 17MHz.
154 */
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700155static int get_ifd_version_from_fcba(char *image, int size)
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700156{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700157 int read_freq;
Bill XIE612ec0e2017-08-30 16:10:27 +0800158 const fcba_t *fcba = find_fcba(image, size);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700159 if (!fcba)
160 exit(EXIT_FAILURE);
161
162 read_freq = (fcba->flcomp >> 17) & 7;
163
164 switch (read_freq) {
165 case SPI_FREQUENCY_20MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700166 return IFD_VERSION_1;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700167 case SPI_FREQUENCY_17MHZ:
Hannah Williams589fc342016-10-06 14:29:48 -0700168 case SPI_FREQUENCY_50MHZ_30MHZ:
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700169 return IFD_VERSION_2;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700170 default:
171 fprintf(stderr, "Unknown descriptor version: %d\n",
172 read_freq);
173 exit(EXIT_FAILURE);
174 }
175}
176
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700177static void check_ifd_version(char *image, int size)
178{
179 if (is_platform_ifd_2())
180 ifd_version = IFD_VERSION_2;
181 else
182 ifd_version = get_ifd_version_from_fcba(image, size);
183
184 if (ifd_version == IFD_VERSION_1)
185 max_regions = MAX_REGIONS_OLD;
186 else
187 max_regions = MAX_REGIONS;
188}
189
Bill XIEfa5f9942017-09-12 11:22:29 +0800190static region_t get_region(const frba_t *frba, unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700191{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500192 int base_mask;
193 int limit_mask;
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700194 uint32_t flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700195 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500196
197 if (ifd_version >= IFD_VERSION_2)
198 base_mask = 0x7fff;
199 else
200 base_mask = 0xfff;
201
202 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700203
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400204 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800205 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700206 exit (EXIT_FAILURE);
207 }
208
Bill XIE4651d452017-09-12 11:54:48 +0800209 flreg = frba->flreg[region_type];
Ronald G. Minnich8db3c2a2017-05-25 10:48:57 -0700210 region.base = (flreg & base_mask) << 12;
211 region.limit = ((flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700212 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500213
Chris Douglass03ce0142014-02-26 13:30:13 -0500214 if (region.size < 0)
215 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700216
217 return region;
218}
219
Bill XIEfa5f9942017-09-12 11:22:29 +0800220static void set_region(frba_t *frba, unsigned int region_type,
221 const region_t *region)
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500222{
Youness Alaouif68e3ba2017-10-04 11:35:59 -0400223 if (region_type >= max_regions) {
Bill XIE4651d452017-09-12 11:54:48 +0800224 fprintf(stderr, "Invalid region type %u.\n", region_type);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500225 exit (EXIT_FAILURE);
226 }
Bill XIE4651d452017-09-12 11:54:48 +0800227
228 frba->flreg[region_type] =
229 (((region->limit >> 12) & 0x7fff) << 16) |
230 ((region->base >> 12) & 0x7fff);
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500231}
232
Bill XIEfa5f9942017-09-12 11:22:29 +0800233static const char *region_name(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700234{
Bill XIEfa5f9942017-09-12 11:22:29 +0800235 if (region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700236 fprintf(stderr, "Invalid region type.\n");
237 exit (EXIT_FAILURE);
238 }
239
Chris Douglass03ce0142014-02-26 13:30:13 -0500240 return region_names[region_type].pretty;
241}
242
Bill XIEfa5f9942017-09-12 11:22:29 +0800243static const char *region_name_short(unsigned int region_type)
Chris Douglass03ce0142014-02-26 13:30:13 -0500244{
Bill XIEfa5f9942017-09-12 11:22:29 +0800245 if (region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500246 fprintf(stderr, "Invalid region type.\n");
247 exit (EXIT_FAILURE);
248 }
249
250 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700251}
252
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500253static int region_num(const char *name)
254{
Bill XIEfa5f9942017-09-12 11:22:29 +0800255 unsigned int i;
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500256
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200257 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500258 if (strcasecmp(name, region_names[i].pretty) == 0)
259 return i;
260 if (strcasecmp(name, region_names[i].terse) == 0)
261 return i;
262 }
263
264 return -1;
265}
266
Bill XIEfa5f9942017-09-12 11:22:29 +0800267static const char *region_filename(unsigned int region_type)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700268{
Bill XIEfa5f9942017-09-12 11:22:29 +0800269 if (region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700270 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700271 exit (EXIT_FAILURE);
272 }
273
Bill XIE1bf65062017-09-12 11:31:37 +0800274 return region_names[region_type].filename;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700275}
276
Bill XIEfa5f9942017-09-12 11:22:29 +0800277static void dump_region(unsigned int num, const frba_t *frba)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700278{
279 region_t region = get_region(frba, num);
280 printf(" Flash Region %d (%s): %08x - %08x %s\n",
281 num, region_name(num), region.base, region.limit,
282 region.size < 1 ? "(unused)" : "");
283}
284
Bill XIEfa5f9942017-09-12 11:22:29 +0800285static void dump_region_layout(char *buf, size_t bufsize, unsigned int num,
286 const frba_t *frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500287{
288 region_t region = get_region(frba, num);
289 snprintf(buf, bufsize, "%08x:%08x %s\n",
290 region.base, region.limit, region_name_short(num));
291}
292
Bill XIEfa5f9942017-09-12 11:22:29 +0800293static void dump_frba(const frba_t *frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700294{
Bill XIE4651d452017-09-12 11:54:48 +0800295 unsigned int i;
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700296 printf("Found Region Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800297 for (i = 0; i < max_regions; i++) {
298 printf("FLREG%u: 0x%08x\n", i, frba->flreg[i]);
299 dump_region(i, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700300 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700301}
302
Bill XIEfa5f9942017-09-12 11:22:29 +0800303static void dump_frba_layout(const frba_t *frba, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500304{
305 char buf[LAYOUT_LINELEN];
306 size_t bufsize = LAYOUT_LINELEN;
Bill XIEfa5f9942017-09-12 11:22:29 +0800307 unsigned int i;
Chris Douglass03ce0142014-02-26 13:30:13 -0500308
309 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
310 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
311 if (layout_fd == -1) {
312 perror("Could not open file");
313 exit(EXIT_FAILURE);
314 }
315
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200316 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200317 region_t region = get_region(frba, i);
318 /* is region invalid? */
319 if (region.size < 1)
320 continue;
321
Chris Douglass03ce0142014-02-26 13:30:13 -0500322 dump_region_layout(buf, bufsize, i, frba);
323 if (write(layout_fd, buf, strlen(buf)) < 0) {
324 perror("Could not write to file");
325 exit(EXIT_FAILURE);
326 }
327 }
328 close(layout_fd);
329 printf("Wrote layout to %s\n", layout_fname);
330}
331
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700332static void decode_spi_frequency(unsigned int freq)
333{
334 switch (freq) {
335 case SPI_FREQUENCY_20MHZ:
336 printf("20MHz");
337 break;
338 case SPI_FREQUENCY_33MHZ:
339 printf("33MHz");
340 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700341 case SPI_FREQUENCY_48MHZ:
342 printf("48MHz");
343 break;
344 case SPI_FREQUENCY_50MHZ_30MHZ:
345 switch (ifd_version) {
346 case IFD_VERSION_1:
347 printf("50MHz");
348 break;
349 case IFD_VERSION_2:
350 printf("30MHz");
351 break;
352 }
353 break;
354 case SPI_FREQUENCY_17MHZ:
355 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700356 break;
357 default:
358 printf("unknown<%x>MHz", freq);
359 }
360}
361
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700362static void decode_component_density(unsigned int density)
363{
364 switch (density) {
365 case COMPONENT_DENSITY_512KB:
366 printf("512KB");
367 break;
368 case COMPONENT_DENSITY_1MB:
369 printf("1MB");
370 break;
371 case COMPONENT_DENSITY_2MB:
372 printf("2MB");
373 break;
374 case COMPONENT_DENSITY_4MB:
375 printf("4MB");
376 break;
377 case COMPONENT_DENSITY_8MB:
378 printf("8MB");
379 break;
380 case COMPONENT_DENSITY_16MB:
381 printf("16MB");
382 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700383 case COMPONENT_DENSITY_32MB:
384 printf("32MB");
385 break;
386 case COMPONENT_DENSITY_64MB:
387 printf("64MB");
388 break;
389 case COMPONENT_DENSITY_UNUSED:
390 printf("UNUSED");
391 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700392 default:
393 printf("unknown<%x>MB", density);
394 }
395}
396
Bill XIEfa5f9942017-09-12 11:22:29 +0800397static void dump_fcba(const fcba_t *fcba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700398{
399 printf("\nFound Component Section\n");
400 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700401 printf(" Dual Output Fast Read Support: %ssupported\n",
402 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700403 printf(" Read ID/Read Status Clock Frequency: ");
404 decode_spi_frequency((fcba->flcomp >> 27) & 7);
405 printf("\n Write/Erase Clock Frequency: ");
406 decode_spi_frequency((fcba->flcomp >> 24) & 7);
407 printf("\n Fast Read Clock Frequency: ");
408 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700409 printf("\n Fast Read Support: %ssupported",
410 (fcba->flcomp & (1 << 20))?"":"not ");
411 printf("\n Read Clock Frequency: ");
412 decode_spi_frequency((fcba->flcomp >> 17) & 7);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700413
414 switch (ifd_version) {
415 case IFD_VERSION_1:
416 printf("\n Component 2 Density: ");
417 decode_component_density((fcba->flcomp >> 3) & 7);
418 printf("\n Component 1 Density: ");
419 decode_component_density(fcba->flcomp & 7);
420 break;
421 case IFD_VERSION_2:
422 printf("\n Component 2 Density: ");
423 decode_component_density((fcba->flcomp >> 4) & 0xf);
424 printf("\n Component 1 Density: ");
425 decode_component_density(fcba->flcomp & 0xf);
426 break;
427 }
428
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700429 printf("\n");
430 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700431 printf(" Invalid Instruction 3: 0x%02x\n",
432 (fcba->flill >> 24) & 0xff);
433 printf(" Invalid Instruction 2: 0x%02x\n",
434 (fcba->flill >> 16) & 0xff);
435 printf(" Invalid Instruction 1: 0x%02x\n",
436 (fcba->flill >> 8) & 0xff);
437 printf(" Invalid Instruction 0: 0x%02x\n",
438 fcba->flill & 0xff);
439 printf("FLPB 0x%08x\n", fcba->flpb);
440 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
441 (fcba->flpb & 0xfff) << 12);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700442}
443
Bill XIEfa5f9942017-09-12 11:22:29 +0800444static void dump_fpsba(const fpsba_t *fpsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700445{
Bill XIE4651d452017-09-12 11:54:48 +0800446 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700447 printf("Found PCH Strap Section\n");
Bill XIE4651d452017-09-12 11:54:48 +0800448 for (i = 0; i < ARRAY_SIZE(fpsba->pchstrp); i++)
449 printf("PCHSTRP%u:%s 0x%08x\n", i,
450 i < 10 ? " " : "", fpsba->pchstrp[i]);
451 printf("\n");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700452}
453
454static void decode_flmstr(uint32_t flmstr)
455{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700456 int wr_shift, rd_shift;
457 if (ifd_version >= IFD_VERSION_2) {
458 wr_shift = FLMSTR_WR_SHIFT_V2;
459 rd_shift = FLMSTR_RD_SHIFT_V2;
460 } else {
461 wr_shift = FLMSTR_WR_SHIFT_V1;
462 rd_shift = FLMSTR_RD_SHIFT_V1;
463 }
464
465 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700466 if (ifd_version >= IFD_VERSION_2)
467 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700468 (flmstr & (1 << (wr_shift + 8))) ?
469 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700470 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700471 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700472 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700473 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700474 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700475 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700476 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700477 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700478 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700479 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700480
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700481 if (ifd_version >= IFD_VERSION_2)
482 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700483 (flmstr & (1 << (rd_shift + 8))) ?
484 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700485 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700486 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700487 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700488 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700489 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700490 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700491 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700492 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700493 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700494 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700495
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700496 /* Requestor ID doesn't exist for ifd 2 */
497 if (ifd_version < IFD_VERSION_2)
498 printf(" Requester ID: 0x%04x\n\n",
499 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700500}
501
Bill XIEfa5f9942017-09-12 11:22:29 +0800502static void dump_fmba(const fmba_t *fmba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700503{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700504 printf("Found Master Section\n");
505 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
506 decode_flmstr(fmba->flmstr1);
507 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
508 decode_flmstr(fmba->flmstr2);
509 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
510 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700511 if (ifd_version >= IFD_VERSION_2) {
512 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
513 decode_flmstr(fmba->flmstr5);
514 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700515}
516
Bill XIEfa5f9942017-09-12 11:22:29 +0800517static void dump_fmsba(const fmsba_t *fmsba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700518{
Bill XIE612ec0e2017-08-30 16:10:27 +0800519 unsigned int i;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700520 printf("Found Processor Strap Section\n");
Bill XIE612ec0e2017-08-30 16:10:27 +0800521 for (i = 0; i < ARRAY_SIZE(fmsba->data); i++)
522 printf("????: 0x%08x\n", fmsba->data[i]);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700523}
524
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700525static void dump_jid(uint32_t jid)
526{
527 printf(" SPI Componend Device ID 1: 0x%02x\n",
528 (jid >> 16) & 0xff);
529 printf(" SPI Componend Device ID 0: 0x%02x\n",
530 (jid >> 8) & 0xff);
531 printf(" SPI Componend Vendor ID: 0x%02x\n",
532 jid & 0xff);
533}
534
535static void dump_vscc(uint32_t vscc)
536{
537 printf(" Lower Erase Opcode: 0x%02x\n",
538 vscc >> 24);
539 printf(" Lower Write Enable on Write Status: 0x%02x\n",
540 vscc & (1 << 20) ? 0x06 : 0x50);
541 printf(" Lower Write Status Required: %s\n",
542 vscc & (1 << 19) ? "Yes" : "No");
543 printf(" Lower Write Granularity: %d bytes\n",
544 vscc & (1 << 18) ? 64 : 1);
545 printf(" Lower Block / Sector Erase Size: ");
546 switch ((vscc >> 16) & 0x3) {
547 case 0:
548 printf("256 Byte\n");
549 break;
550 case 1:
551 printf("4KB\n");
552 break;
553 case 2:
554 printf("8KB\n");
555 break;
556 case 3:
557 printf("64KB\n");
558 break;
559 }
560
561 printf(" Upper Erase Opcode: 0x%02x\n",
562 (vscc >> 8) & 0xff);
563 printf(" Upper Write Enable on Write Status: 0x%02x\n",
564 vscc & (1 << 4) ? 0x06 : 0x50);
565 printf(" Upper Write Status Required: %s\n",
566 vscc & (1 << 3) ? "Yes" : "No");
567 printf(" Upper Write Granularity: %d bytes\n",
568 vscc & (1 << 2) ? 64 : 1);
569 printf(" Upper Block / Sector Erase Size: ");
570 switch (vscc & 0x3) {
571 case 0:
572 printf("256 Byte\n");
573 break;
574 case 1:
575 printf("4KB\n");
576 break;
577 case 2:
578 printf("8KB\n");
579 break;
580 case 3:
581 printf("64KB\n");
582 break;
583 }
584}
585
Bill XIEfa5f9942017-09-12 11:22:29 +0800586static void dump_vtba(const vtba_t *vtba, int vtl)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700587{
588 int i;
589 int num = (vtl >> 1) < 8 ? (vtl >> 1) : 8;
590
591 printf("ME VSCC table:\n");
592 for (i = 0; i < num; i++) {
593 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
594 dump_jid(vtba->entry[i].jid);
595 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
596 dump_vscc(vtba->entry[i].vscc);
597 }
598 printf("\n");
599}
600
Bill XIEfa5f9942017-09-12 11:22:29 +0800601static void dump_oem(const uint8_t *oem)
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700602{
603 int i, j;
604 printf("OEM Section:\n");
605 for (i = 0; i < 4; i++) {
606 printf("%02x:", i << 4);
607 for (j = 0; j < 16; j++)
608 printf(" %02x", oem[(i<<4)+j]);
609 printf ("\n");
610 }
611 printf ("\n");
612}
613
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700614static void dump_fd(char *image, int size)
615{
Bill XIE612ec0e2017-08-30 16:10:27 +0800616 const fdbar_t *fdb = find_fd(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700617 if (!fdb)
618 exit(EXIT_FAILURE);
619
620 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
621 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
622 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
623 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
624 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
625
626 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
627 printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
628 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
629 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
630 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
631
632 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
633 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
634 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
635
636 printf("FLUMAP1: 0x%08x\n", fdb->flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700637 printf(" Intel ME VSCC Table Length (VTL): %d\n",
638 (fdb->flumap1 >> 8) & 0xff);
639 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
640 (fdb->flumap1 & 0xff) << 4);
641 dump_vtba((vtba_t *)
642 (image + ((fdb->flumap1 & 0xff) << 4)),
643 (fdb->flumap1 >> 8) & 0xff);
Bill XIE612ec0e2017-08-30 16:10:27 +0800644 dump_oem((const uint8_t *)image + 0xf00);
645
646 const frba_t *frba = find_frba(image, size);
647 const fcba_t *fcba = find_fcba(image, size);
648 const fpsba_t *fpsba = find_fpsba(image, size);
649 const fmba_t *fmba = find_fmba(image, size);
650 const fmsba_t *fmsba = find_fmsba(image, size);
651
652 if (frba && fcba && fpsba && fmba && fmsba) {
653 dump_frba(frba);
654 dump_fcba(fcba);
655 dump_fpsba(fpsba);
656 dump_fmba(fmba);
657 dump_fmsba(fmsba);
658 } else {
659 printf("FD is corrupted!\n");
660 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700661}
662
Bill XIEfa5f9942017-09-12 11:22:29 +0800663static void dump_layout(char *image, int size, const char *layout_fname)
Chris Douglass03ce0142014-02-26 13:30:13 -0500664{
Bill XIE612ec0e2017-08-30 16:10:27 +0800665 const frba_t *frba = find_frba(image, size);
666 if (!frba)
Chris Douglass03ce0142014-02-26 13:30:13 -0500667 exit(EXIT_FAILURE);
668
Bill XIE612ec0e2017-08-30 16:10:27 +0800669 dump_frba_layout(frba, layout_fname);
Chris Douglass03ce0142014-02-26 13:30:13 -0500670}
671
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700672static void write_regions(char *image, int size)
673{
Bill XIEfa5f9942017-09-12 11:22:29 +0800674 unsigned int i;
Bill XIE612ec0e2017-08-30 16:10:27 +0800675 const frba_t *frba = find_frba(image, size);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700676
Bill XIE612ec0e2017-08-30 16:10:27 +0800677 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700678 exit(EXIT_FAILURE);
679
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700680 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700681 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700682 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700683 if (region.size > 0) {
684 int region_fd;
685 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600686 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700687 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200688 if (region_fd < 0) {
689 perror("Error while trying to open file");
690 exit(EXIT_FAILURE);
691 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700692 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700693 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700694 close(region_fd);
695 }
696 }
697}
698
Bill XIEfa5f9942017-09-12 11:22:29 +0800699static void write_image(const char *filename, char *image, int size)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700700{
701 char new_filename[FILENAME_MAX]; // allow long file names
702 int new_fd;
703
Patrick Georgi440daf72014-08-03 12:14:25 +0200704 // - 5: leave room for ".new\0"
705 strncpy(new_filename, filename, FILENAME_MAX - 5);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700706 strncat(new_filename, ".new", FILENAME_MAX - strlen(filename));
707
708 printf("Writing new image to %s\n", new_filename);
709
710 // Now write out new image
711 new_fd = open(new_filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600712 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700713 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200714 if (new_fd < 0) {
715 perror("Error while trying to open file");
716 exit(EXIT_FAILURE);
717 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700718 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700719 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700720 close(new_fd);
721}
722
Bill XIEfa5f9942017-09-12 11:22:29 +0800723static void set_spi_frequency(const char *filename, char *image, int size,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700724 enum spi_frequency freq)
725{
Bill XIE612ec0e2017-08-30 16:10:27 +0800726 fcba_t *fcba = find_fcba(image, size);
727 if (!fcba)
728 exit(EXIT_FAILURE);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700729
730 /* clear bits 21-29 */
731 fcba->flcomp &= ~0x3fe00000;
732 /* Read ID and Read Status Clock Frequency */
733 fcba->flcomp |= freq << 27;
734 /* Write and Erase Clock Frequency */
735 fcba->flcomp |= freq << 24;
736 /* Fast Read Clock Frequency */
737 fcba->flcomp |= freq << 21;
738
739 write_image(filename, image, size);
740}
741
Bill XIEfa5f9942017-09-12 11:22:29 +0800742static void set_em100_mode(const char *filename, char *image, int size)
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700743{
Bill XIE612ec0e2017-08-30 16:10:27 +0800744 fcba_t *fcba = find_fcba(image, size);
745 if (!fcba)
746 exit(EXIT_FAILURE);
747
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700748 int freq;
749
750 switch (ifd_version) {
751 case IFD_VERSION_1:
752 freq = SPI_FREQUENCY_20MHZ;
753 break;
754 case IFD_VERSION_2:
755 freq = SPI_FREQUENCY_17MHZ;
756 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -0700757 default:
758 freq = SPI_FREQUENCY_17MHZ;
759 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700760 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700761
762 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700763 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700764}
765
Bill XIEfa5f9942017-09-12 11:22:29 +0800766static void set_chipdensity(const char *filename, char *image, int size,
Jan Tatjefa317512016-03-11 00:52:07 +0100767 unsigned int density)
768{
Bill XIE612ec0e2017-08-30 16:10:27 +0800769 fcba_t *fcba = find_fcba(image, size);
770 if (!fcba)
771 exit(EXIT_FAILURE);
Jan Tatjefa317512016-03-11 00:52:07 +0100772
773 printf("Setting chip density to ");
774 decode_component_density(density);
775 printf("\n");
776
777 switch (ifd_version) {
778 case IFD_VERSION_1:
779 /* fail if selected density is not supported by this version */
780 if ( (density == COMPONENT_DENSITY_32MB) ||
781 (density == COMPONENT_DENSITY_64MB) ||
782 (density == COMPONENT_DENSITY_UNUSED) ) {
783 printf("error: Selected density not supported in IFD version 1.\n");
784 exit(EXIT_FAILURE);
785 }
786 break;
787 case IFD_VERSION_2:
788 /* I do not have a version 2 IFD nor do i have the docs. */
789 printf("error: Changing the chip density for IFD version 2 has not been"
790 " implemented yet.\n");
791 exit(EXIT_FAILURE);
792 default:
793 printf("error: Unknown IFD version\n");
794 exit(EXIT_FAILURE);
795 break;
796 }
797
798 /* clear chip density for corresponding chip */
799 switch (selected_chip) {
800 case 1:
801 fcba->flcomp &= ~(0x7);
802 break;
803 case 2:
804 fcba->flcomp &= ~(0x7 << 3);
805 break;
806 default: /*both chips*/
807 fcba->flcomp &= ~(0x3F);
808 break;
809 }
810
811 /* set the new density */
812 if (selected_chip == 1 || selected_chip == 0)
813 fcba->flcomp |= (density); /* first chip */
814 if (selected_chip == 2 || selected_chip == 0)
815 fcba->flcomp |= (density << 3); /* second chip */
816
817 write_image(filename, image, size);
818}
819
Bill XIEfa5f9942017-09-12 11:22:29 +0800820static void lock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700821{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700822 int wr_shift, rd_shift;
Bill XIE612ec0e2017-08-30 16:10:27 +0800823 fmba_t *fmba = find_fmba(image, size);
824 if (!fmba)
825 exit(EXIT_FAILURE);
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700826 /* TODO: Dynamically take Platform Data Region and GbE Region
827 * into regard.
828 */
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700829
830 if (ifd_version >= IFD_VERSION_2) {
831 wr_shift = FLMSTR_WR_SHIFT_V2;
832 rd_shift = FLMSTR_RD_SHIFT_V2;
833
834 /* Clear non-reserved bits */
835 fmba->flmstr1 &= 0xff;
836 fmba->flmstr2 &= 0xff;
837 fmba->flmstr3 &= 0xff;
838 } else {
839 wr_shift = FLMSTR_WR_SHIFT_V1;
840 rd_shift = FLMSTR_RD_SHIFT_V1;
841
842 fmba->flmstr1 = 0;
843 fmba->flmstr2 = 0;
844 /* Requestor ID */
845 fmba->flmstr3 = 0x118;
846 }
847
Andrey Petrov96ecb772016-10-31 19:31:54 -0700848 switch (platform) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -0700849 case PLATFORM_APL:
850 case PLATFORM_GLK:
Andrey Petrov96ecb772016-10-31 19:31:54 -0700851 /* CPU/BIOS can read descriptor and BIOS */
852 fmba->flmstr1 |= 0x3 << rd_shift;
853 /* CPU/BIOS can write BIOS */
854 fmba->flmstr1 |= 0x2 << wr_shift;
855 /* TXE can read descriptor, BIOS and Device Expansion */
856 fmba->flmstr2 |= 0x23 << rd_shift;
857 /* TXE can only write Device Expansion */
858 fmba->flmstr2 |= 0x20 << wr_shift;
859 break;
Furquan Shaikh088b6e82018-03-21 10:42:37 -0700860 case PLATFORM_SKLKBL:
861 /* CPU/BIOS can read descriptor, BIOS and GbE. */
862 fmba->flmstr1 |= 0xb << rd_shift;
863 /* CPU/BIOS can write BIOS and Gbe. */
864 fmba->flmstr1 |= 0xa << wr_shift;
865 /* ME can read descriptor, ME and GbE. */
866 fmba->flmstr2 |= 0xd << rd_shift;
867 /* ME can write ME. */
868 fmba->flmstr2 |= 0x4 << wr_shift;
869 /* GbE can read GbE and descriptor. */
870 fmba->flmstr3 |= 0x9 << rd_shift;
871 /* GbE can write GbE. */
872 fmba->flmstr3 |= 0x8 << wr_shift;
873 /* EC can read EC and descriptor. */
874 fmba->flmstr5 |= 0x101 << rd_shift;
875 /* EC can write EC region. */
876 fmba->flmstr5 |= 0x100 << wr_shift;
877 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -0700878 default:
879 /* CPU/BIOS can read descriptor, BIOS, and GbE. */
880 fmba->flmstr1 |= 0xb << rd_shift;
881 /* CPU/BIOS can write BIOS and GbE. */
882 fmba->flmstr1 |= 0xa << wr_shift;
883 /* ME can read descriptor, ME, and GbE. */
884 fmba->flmstr2 |= 0xd << rd_shift;
885 /* ME can write ME and GbE. */
886 fmba->flmstr2 |= 0xc << wr_shift;
887 /* GbE can write only GbE. */
888 fmba->flmstr3 |= 0x8 << rd_shift;
889 /* GbE can read only GbE. */
890 fmba->flmstr3 |= 0x8 << wr_shift;
891 break;
892 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700893
894 write_image(filename, image, size);
895}
896
Bill XIEfa5f9942017-09-12 11:22:29 +0800897static void unlock_descriptor(const char *filename, char *image, int size)
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700898{
Bill XIE612ec0e2017-08-30 16:10:27 +0800899 fmba_t *fmba = find_fmba(image, size);
900 if (!fmba)
901 exit(EXIT_FAILURE);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700902
903 if (ifd_version >= IFD_VERSION_2) {
904 /* Access bits for each region are read: 19:8 write: 31:20 */
905 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
906 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
907 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
908 } else {
909 fmba->flmstr1 = 0xffff0000;
910 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +0100911 /* Keep chipset specific Requester ID */
912 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700913 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700914
915 write_image(filename, image, size);
916}
917
Bill XIEfa5f9942017-09-12 11:22:29 +0800918void inject_region(const char *filename, char *image, int size,
919 unsigned int region_type, const char *region_fname)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700920{
Bill XIE612ec0e2017-08-30 16:10:27 +0800921 frba_t *frba = find_frba(image, size);
922 if (!frba)
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700923 exit(EXIT_FAILURE);
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700924
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700925 region_t region = get_region(frba, region_type);
926 if (region.size <= 0xfff) {
927 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
928 region_name(region_type));
929 exit(EXIT_FAILURE);
930 }
931
Scott Duplichanf2c98372014-12-12 21:03:06 -0600932 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700933 if (region_fd == -1) {
934 perror("Could not open file");
935 exit(EXIT_FAILURE);
936 }
937 struct stat buf;
938 if (fstat(region_fd, &buf) == -1) {
939 perror("Could not stat file");
940 exit(EXIT_FAILURE);
941 }
942 int region_size = buf.st_size;
943
944 printf("File %s is %d bytes\n", region_fname, region_size);
945
946 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -0800947 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700948 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
949 " bytes. Not injecting.\n",
950 region_name(region_type), region.size,
951 region.size, region_size, region_size);
952 exit(EXIT_FAILURE);
953 }
954
955 int offset = 0;
956 if ((region_type == 1) && (region_size < region.size)) {
957 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
958 " bytes. Padding before injecting.\n",
959 region_name(region_type), region.size,
960 region.size, region_size, region_size);
961 offset = region.size - region_size;
962 memset(image + region.base, 0xff, offset);
963 }
964
Stefan Reinauer5e93b372012-09-25 13:30:48 -0700965 if (size < region.base + offset + region_size) {
966 fprintf(stderr, "Output file is too small. (%d < %d)\n",
967 size, region.base + offset + region_size);
968 exit(EXIT_FAILURE);
969 }
970
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700971 if (read(region_fd, image + region.base + offset, region_size)
972 != region_size) {
973 perror("Could not read file");
974 exit(EXIT_FAILURE);
975 }
976
977 close(region_fd);
978
979 printf("Adding %s as the %s section of %s\n",
980 region_fname, region_name(region_type), filename);
981 write_image(filename, image, size);
982}
983
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500984unsigned int next_pow2(unsigned int x)
985{
986 unsigned int y = 1;
987 if (x == 0)
988 return 0;
989 while (y <= x)
990 y = y << 1;
991
992 return y;
993}
994
995/**
996 * Determine if two memory regions overlap.
997 *
998 * @param r1, r2 Memory regions to compare.
999 * @return 0 if the two regions are seperate
1000 * @return 1 if the two regions overlap
1001 */
Bill XIEfa5f9942017-09-12 11:22:29 +08001002static int regions_collide(const region_t *r1, const region_t *r2)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001003{
Bill XIEfa5f9942017-09-12 11:22:29 +08001004 if ((r1->size == 0) || (r2->size == 0))
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001005 return 0;
1006
Bill XIEfa5f9942017-09-12 11:22:29 +08001007 if ( ((r1->base >= r2->base) && (r1->base <= r2->limit)) ||
1008 ((r1->limit >= r2->base) && (r1->limit <= r2->limit)) )
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001009 return 1;
1010
1011 return 0;
1012}
1013
Bill XIEfa5f9942017-09-12 11:22:29 +08001014void new_layout(const char *filename, char *image, int size,
1015 const char *layout_fname)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001016{
1017 FILE *romlayout;
1018 char tempstr[256];
1019 char layout_region_name[256];
Bill XIEfa5f9942017-09-12 11:22:29 +08001020 unsigned int i, j;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001021 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001022 region_t current_regions[MAX_REGIONS];
1023 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001024 int new_extent = 0;
1025 char *new_image;
1026
1027 /* load current descriptor map and regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001028 frba_t *frba = find_frba(image, size);
1029 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001030 exit(EXIT_FAILURE);
1031
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001032 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001033 current_regions[i] = get_region(frba, i);
1034 new_regions[i] = get_region(frba, i);
1035 }
1036
1037 /* read new layout */
1038 romlayout = fopen(layout_fname, "r");
1039
1040 if (!romlayout) {
1041 perror("Could not read layout file.\n");
1042 exit(EXIT_FAILURE);
1043 }
1044
1045 while (!feof(romlayout)) {
1046 char *tstr1, *tstr2;
1047
Patrick Georgi802ad522014-08-09 17:12:23 +02001048 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001049 layout_region_name))
1050 continue;
1051
1052 region_number = region_num(layout_region_name);
1053 if (region_number < 0)
1054 continue;
1055
1056 tstr1 = strtok(tempstr, ":");
1057 tstr2 = strtok(NULL, ":");
1058 if (!tstr1 || !tstr2) {
1059 fprintf(stderr, "Could not parse layout file.\n");
1060 exit(EXIT_FAILURE);
1061 }
1062 new_regions[region_number].base = strtol(tstr1,
1063 (char **)NULL, 16);
1064 new_regions[region_number].limit = strtol(tstr2,
1065 (char **)NULL, 16);
1066 new_regions[region_number].size =
1067 new_regions[region_number].limit -
1068 new_regions[region_number].base + 1;
1069
1070 if (new_regions[region_number].size < 0)
1071 new_regions[region_number].size = 0;
1072 }
1073 fclose(romlayout);
1074
1075 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001076 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001077 if (new_regions[i].size == 0)
1078 continue;
1079
1080 if (new_regions[i].size < current_regions[i].size) {
1081 printf("DANGER: Region %s is shrinking.\n",
1082 region_name(i));
1083 printf(" The region will be truncated to fit.\n");
1084 printf(" This may result in an unusable image.\n");
1085 }
1086
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001087 for (j = i + 1; j < max_regions; j++) {
Bill XIEfa5f9942017-09-12 11:22:29 +08001088 if (regions_collide(&new_regions[i], &new_regions[j])) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001089 fprintf(stderr, "Regions would overlap.\n");
1090 exit(EXIT_FAILURE);
1091 }
1092 }
1093
1094 /* detect if the image size should grow */
1095 if (new_extent < new_regions[i].limit)
1096 new_extent = new_regions[i].limit;
1097 }
1098
1099 new_extent = next_pow2(new_extent - 1);
1100 if (new_extent != size) {
1101 printf("The image has changed in size.\n");
1102 printf("The old image is %d bytes.\n", size);
1103 printf("The new image is %d bytes.\n", new_extent);
1104 }
1105
1106 /* copy regions to a new image */
1107 new_image = malloc(new_extent);
1108 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001109 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001110 int copy_size = new_regions[i].size;
1111 int offset_current = 0, offset_new = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001112 const region_t *current = &current_regions[i];
1113 const region_t *new = &new_regions[i];
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001114
Bill XIEfa5f9942017-09-12 11:22:29 +08001115 if (new->size == 0)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001116 continue;
1117
Bill XIEfa5f9942017-09-12 11:22:29 +08001118 if (new->size > current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001119 /* copy from the end of the current region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001120 copy_size = current->size;
1121 offset_new = new->size - current->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001122 }
1123
Bill XIEfa5f9942017-09-12 11:22:29 +08001124 if (new->size < current->size) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001125 /* copy to the end of the new region */
Bill XIEfa5f9942017-09-12 11:22:29 +08001126 offset_current = current->size - new->size;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001127 }
1128
1129 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1130 region_name(i), copy_size);
Bill XIEfa5f9942017-09-12 11:22:29 +08001131 printf(" from %08x+%08x:%08x (%10d)\n", current->base,
1132 offset_current, current->limit, current->size);
1133 printf(" to %08x+%08x:%08x (%10d)\n", new->base,
1134 offset_new, new->limit, new->size);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001135
Bill XIEfa5f9942017-09-12 11:22:29 +08001136 memcpy(new_image + new->base + offset_new,
1137 image + current->base + offset_current,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001138 copy_size);
1139 }
1140
1141 /* update new descriptor regions */
Bill XIE612ec0e2017-08-30 16:10:27 +08001142 frba = find_frba(new_image, new_extent);
1143 if (!frba)
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001144 exit(EXIT_FAILURE);
1145
Bill XIE612ec0e2017-08-30 16:10:27 +08001146 for (i = 1; i < max_regions; i++)
Bill XIEfa5f9942017-09-12 11:22:29 +08001147 set_region(frba, i, &new_regions[i]);
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001148
1149 write_image(filename, new_image, new_extent);
1150 free(new_image);
1151}
1152
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001153static void print_version(void)
1154{
1155 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1156 printf("Copyright (C) 2011 Google Inc.\n\n");
1157 printf
1158 ("This program is free software: you can redistribute it and/or modify\n"
1159 "it under the terms of the GNU General Public License as published by\n"
1160 "the Free Software Foundation, version 2 of the License.\n\n"
1161 "This program is distributed in the hope that it will be useful,\n"
1162 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1163 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001164 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001165}
1166
1167static void print_usage(const char *name)
1168{
1169 printf("usage: %s [-vhdix?] <filename>\n", name);
1170 printf("\n"
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001171 " -d | --dump: dump intel firmware descriptor\n"
1172 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1173 " -x | --extract: extract intel fd modules\n"
1174 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1175 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
1176 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
Jan Tatjefa317512016-03-11 00:52:07 +01001177 " -D | --density <512|1|2|4|8|16> set chip density (512 in KByte, others in MByte)\n"
1178 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1179 " can only be used once per run:\n"
1180 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001181 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1182 " Dual Output Fast Read Support\n"
1183 " -l | --lock Lock firmware descriptor and ME region\n"
1184 " -u | --unlock Unlock firmware descriptor and ME region\n"
Andrey Petrov96ecb772016-10-31 19:31:54 -07001185 " -p | --platform Add platform-specific quirks\n"
1186 " aplk - Apollo Lake\n"
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001187 " cnl - Cannon Lake\n"
1188 " glk - Gemini Lake\n"
1189 " sklkbl - Skylake/Kaby Lake\n"
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001190 " -v | --version: print the version\n"
1191 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001192 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1193 "\n");
1194}
1195
1196int main(int argc, char *argv[])
1197{
1198 int opt, option_index = 0;
1199 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001200 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001201 int mode_layout = 0, mode_newlayout = 0, mode_density = 0;
Bill XIEfa5f9942017-09-12 11:22:29 +08001202 char *region_type_string = NULL, *region_fname = NULL;
1203 const char *layout_fname = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001204 int region_type = -1, inputfreq = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001205 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001206 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1207
Bill XIEfa5f9942017-09-12 11:22:29 +08001208 static const struct option long_options[] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001209 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001210 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001211 {"extract", 0, NULL, 'x'},
1212 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001213 {"newlayout", 1, NULL, 'n'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001214 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001215 {"density", 1, NULL, 'D'},
1216 {"chip", 1, NULL, 'C'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001217 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001218 {"lock", 0, NULL, 'l'},
1219 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001220 {"version", 0, NULL, 'v'},
1221 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001222 {"platform", 0, NULL, 'p'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001223 {0, 0, 0, 0}
1224 };
1225
Andrey Petrov96ecb772016-10-31 19:31:54 -07001226 while ((opt = getopt_long(argc, argv, "df:D:C:xi:n:s:p:eluvh?",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001227 long_options, &option_index)) != EOF) {
1228 switch (opt) {
1229 case 'd':
1230 mode_dump = 1;
1231 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001232 case 'f':
1233 mode_layout = 1;
1234 layout_fname = strdup(optarg);
1235 if (!layout_fname) {
1236 fprintf(stderr, "No layout file specified\n");
1237 print_usage(argv[0]);
1238 exit(EXIT_FAILURE);
1239 }
1240 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001241 case 'x':
1242 mode_extract = 1;
1243 break;
1244 case 'i':
1245 // separate type and file name
1246 region_type_string = strdup(optarg);
1247 region_fname = strchr(region_type_string, ':');
1248 if (!region_fname) {
1249 print_usage(argv[0]);
1250 exit(EXIT_FAILURE);
1251 }
1252 region_fname[0] = '\0';
1253 region_fname++;
1254 // Descriptor, BIOS, ME, GbE, Platform
1255 // valid type?
1256 if (!strcasecmp("Descriptor", region_type_string))
1257 region_type = 0;
1258 else if (!strcasecmp("BIOS", region_type_string))
1259 region_type = 1;
1260 else if (!strcasecmp("ME", region_type_string))
1261 region_type = 2;
1262 else if (!strcasecmp("GbE", region_type_string))
1263 region_type = 3;
1264 else if (!strcasecmp("Platform", region_type_string))
1265 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001266 else if (!strcasecmp("EC", region_type_string))
1267 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001268 if (region_type == -1) {
1269 fprintf(stderr, "No such region type: '%s'\n\n",
1270 region_type_string);
1271 print_usage(argv[0]);
1272 exit(EXIT_FAILURE);
1273 }
1274 mode_inject = 1;
1275 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001276 case 'n':
1277 mode_newlayout = 1;
1278 layout_fname = strdup(optarg);
1279 if (!layout_fname) {
1280 fprintf(stderr, "No layout file specified\n");
1281 print_usage(argv[0]);
1282 exit(EXIT_FAILURE);
1283 }
1284 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001285 case 'D':
1286 mode_density = 1;
1287 new_density = strtoul(optarg, NULL, 0);
1288 switch (new_density) {
1289 case 512:
1290 new_density = COMPONENT_DENSITY_512KB;
1291 break;
1292 case 1:
1293 new_density = COMPONENT_DENSITY_1MB;
1294 break;
1295 case 2:
1296 new_density = COMPONENT_DENSITY_2MB;
1297 break;
1298 case 4:
1299 new_density = COMPONENT_DENSITY_4MB;
1300 break;
1301 case 8:
1302 new_density = COMPONENT_DENSITY_8MB;
1303 break;
1304 case 16:
1305 new_density = COMPONENT_DENSITY_16MB;
1306 break;
1307 case 32:
1308 new_density = COMPONENT_DENSITY_32MB;
1309 break;
1310 case 64:
1311 new_density = COMPONENT_DENSITY_64MB;
1312 break;
1313 case 0:
1314 new_density = COMPONENT_DENSITY_UNUSED;
1315 break;
1316 default:
1317 printf("error: Unknown density\n");
1318 print_usage(argv[0]);
1319 exit(EXIT_FAILURE);
1320 }
1321 break;
1322 case 'C':
1323 selected_chip = strtol(optarg, NULL, 0);
1324 if (selected_chip > 2) {
1325 fprintf(stderr, "error: Invalid chip selection\n");
1326 print_usage(argv[0]);
1327 exit(EXIT_FAILURE);
1328 }
1329 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001330 case 's':
1331 // Parse the requested SPI frequency
1332 inputfreq = strtol(optarg, NULL, 0);
1333 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001334 case 17:
1335 spifreq = SPI_FREQUENCY_17MHZ;
1336 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001337 case 20:
1338 spifreq = SPI_FREQUENCY_20MHZ;
1339 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001340 case 30:
1341 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1342 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001343 case 33:
1344 spifreq = SPI_FREQUENCY_33MHZ;
1345 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001346 case 48:
1347 spifreq = SPI_FREQUENCY_48MHZ;
1348 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001349 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001350 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001351 break;
1352 default:
1353 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1354 inputfreq);
1355 print_usage(argv[0]);
1356 exit(EXIT_FAILURE);
1357 }
1358 mode_spifreq = 1;
1359 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001360 case 'e':
1361 mode_em100 = 1;
1362 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001363 case 'l':
1364 mode_locked = 1;
1365 if (mode_unlocked == 1) {
1366 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1367 exit(EXIT_FAILURE);
1368 }
1369 break;
1370 case 'u':
1371 mode_unlocked = 1;
1372 if (mode_locked == 1) {
1373 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1374 exit(EXIT_FAILURE);
1375 }
1376 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001377 case 'p':
1378 if (!strcmp(optarg, "aplk")) {
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001379 platform = PLATFORM_APL;
1380 } else if (!strcmp(optarg, "cnl")) {
1381 platform = PLATFORM_CNL;
1382 } else if (!strcmp(optarg, "glk")) {
1383 platform = PLATFORM_GLK;
Furquan Shaikh088b6e82018-03-21 10:42:37 -07001384 } else if (!strcmp(optarg, "sklkbl")) {
1385 platform = PLATFORM_SKLKBL;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001386 } else {
1387 fprintf(stderr, "Unknown platform: %s\n", optarg);
1388 exit(EXIT_FAILURE);
1389 }
Furquan Shaikhc0257dd2018-05-02 23:29:04 -07001390 fprintf(stderr, "Platform is: %s\n", optarg);
Andrey Petrov96ecb772016-10-31 19:31:54 -07001391 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001392 case 'v':
1393 print_version();
1394 exit(EXIT_SUCCESS);
1395 break;
1396 case 'h':
1397 case '?':
1398 default:
1399 print_usage(argv[0]);
1400 exit(EXIT_SUCCESS);
1401 break;
1402 }
1403 }
1404
Chris Douglass03ce0142014-02-26 13:30:13 -05001405 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001406 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001407 mode_locked)) > 1) {
1408 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001409 print_usage(argv[0]);
1410 exit(EXIT_FAILURE);
1411 }
1412
Chris Douglass03ce0142014-02-26 13:30:13 -05001413 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001414 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Jan Tatjefa317512016-03-11 00:52:07 +01001415 mode_unlocked + mode_density) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001416 fprintf(stderr, "You need to specify a mode.\n\n");
1417 print_usage(argv[0]);
1418 exit(EXIT_FAILURE);
1419 }
1420
1421 if (optind + 1 != argc) {
1422 fprintf(stderr, "You need to specify a file.\n\n");
1423 print_usage(argv[0]);
1424 exit(EXIT_FAILURE);
1425 }
1426
1427 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001428 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001429 if (bios_fd == -1) {
1430 perror("Could not open file");
1431 exit(EXIT_FAILURE);
1432 }
1433 struct stat buf;
1434 if (fstat(bios_fd, &buf) == -1) {
1435 perror("Could not stat file");
1436 exit(EXIT_FAILURE);
1437 }
1438 int size = buf.st_size;
1439
1440 printf("File %s is %d bytes\n", filename, size);
1441
1442 char *image = malloc(size);
1443 if (!image) {
1444 printf("Out of memory.\n");
1445 exit(EXIT_FAILURE);
1446 }
1447
1448 if (read(bios_fd, image, size) != size) {
1449 perror("Could not read file");
1450 exit(EXIT_FAILURE);
1451 }
1452
1453 close(bios_fd);
1454
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001455 check_ifd_version(image, size);
1456
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001457 if (mode_dump)
1458 dump_fd(image, size);
1459
Chris Douglass03ce0142014-02-26 13:30:13 -05001460 if (mode_layout)
1461 dump_layout(image, size, layout_fname);
1462
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001463 if (mode_extract)
1464 write_regions(image, size);
1465
1466 if (mode_inject)
1467 inject_region(filename, image, size, region_type,
1468 region_fname);
1469
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001470 if (mode_newlayout)
1471 new_layout(filename, image, size, layout_fname);
1472
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001473 if (mode_spifreq)
1474 set_spi_frequency(filename, image, size, spifreq);
1475
Jan Tatjefa317512016-03-11 00:52:07 +01001476 if (mode_density)
1477 set_chipdensity(filename, image, size, new_density);
1478
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001479 if (mode_em100)
1480 set_em100_mode(filename, image, size);
1481
Alexander Couzensd12ea112016-09-10 13:33:05 +02001482 if (mode_locked)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001483 lock_descriptor(filename, image, size);
1484
1485 if (mode_unlocked)
1486 unlock_descriptor(filename, image, size);
1487
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001488 free(image);
1489
1490 return 0;
1491}