blob: 43054e0eb2d59624bf08dc797b28cc96d2ea122b [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>
24#include "ifdtool.h"
25
Scott Duplichanf2c98372014-12-12 21:03:06 -060026#ifndef O_BINARY
27#define O_BINARY 0
28#endif
29
Duncan Laurie1f7fd722015-06-22 11:14:48 -070030static int ifd_version;
Jan Tatjefa317512016-03-11 00:52:07 +010031static int selected_chip = 0;
Chris Douglasse2718652014-02-28 08:54:41 -050032
Duncan Laurie1f7fd722015-06-22 11:14:48 -070033static const struct region_name region_names[MAX_REGIONS] = {
Chris Douglass03ce0142014-02-26 13:30:13 -050034 { "Flash Descriptor", "fd" },
35 { "BIOS", "bios" },
36 { "Intel ME", "me" },
37 { "GbE", "gbe" },
Duncan Laurie1f7fd722015-06-22 11:14:48 -070038 { "Platform Data", "pd" },
39 { "Reserved", "res1" },
40 { "Reserved", "res2" },
41 { "Reserved", "res3" },
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -070042 { "EC", "ec" },
Chris Douglass03ce0142014-02-26 13:30:13 -050043};
44
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070045static fdbar_t *find_fd(char *image, int size)
46{
47 int i, found = 0;
48
49 /* Scan for FD signature */
50 for (i = 0; i < (size - 4); i += 4) {
51 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
52 found = 1;
53 break; // signature found.
54 }
55 }
56
57 if (!found) {
58 printf("No Flash Descriptor found in this image\n");
59 return NULL;
60 }
61
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070062 return (fdbar_t *) (image + i);
63}
64
Duncan Laurie1f7fd722015-06-22 11:14:48 -070065/*
66 * There is no version field in the descriptor so to determine
67 * if this is a new descriptor format we check the hardcoded SPI
68 * read frequency to see if it is fixed at 20MHz or 17MHz.
69 */
70static void check_ifd_version(char *image, int size)
71{
72 fdbar_t *fdb = find_fd(image, size);
73 fcba_t *fcba;
74 int read_freq;
75
76 if (!fdb)
77 exit(EXIT_FAILURE);
78
79 fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
80 if (!fcba)
81 exit(EXIT_FAILURE);
82
83 read_freq = (fcba->flcomp >> 17) & 7;
84
85 switch (read_freq) {
86 case SPI_FREQUENCY_20MHZ:
87 ifd_version = IFD_VERSION_1;
88 break;
89 case SPI_FREQUENCY_17MHZ:
90 ifd_version = IFD_VERSION_2;
91 break;
92 default:
93 fprintf(stderr, "Unknown descriptor version: %d\n",
94 read_freq);
95 exit(EXIT_FAILURE);
96 }
97}
98
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070099static region_t get_region(frba_t *frba, int region_type)
100{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500101 int base_mask;
102 int limit_mask;
103 uint32_t *flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700104 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500105
106 if (ifd_version >= IFD_VERSION_2)
107 base_mask = 0x7fff;
108 else
109 base_mask = 0xfff;
110
111 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700112
113 switch (region_type) {
114 case 0:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500115 flreg = &frba->flreg0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700116 break;
117 case 1:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500118 flreg = &frba->flreg1;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700119 break;
120 case 2:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500121 flreg = &frba->flreg2;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700122 break;
123 case 3:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500124 flreg = &frba->flreg3;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700125 break;
126 case 4:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500127 flreg = &frba->flreg4;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700128 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700129 case 5:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500130 flreg = &frba->flreg5;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700131 break;
132 case 6:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500133 flreg = &frba->flreg6;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700134 break;
135 case 7:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500136 flreg = &frba->flreg7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700137 break;
138 case 8:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500139 flreg = &frba->flreg8;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700140 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700141 default:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700142 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700143 exit (EXIT_FAILURE);
144 }
145
Aaron Durbin0a31e592015-08-12 11:44:02 -0500146 region.base = (*flreg & base_mask) << 12;
147 region.limit = ((*flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700148 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500149
Chris Douglass03ce0142014-02-26 13:30:13 -0500150 if (region.size < 0)
151 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700152
153 return region;
154}
155
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500156static void set_region(frba_t *frba, int region_type, region_t region)
157{
158 switch (region_type) {
159 case 0:
160 frba->flreg0 = (((region.limit >> 12) & 0x7fff) << 16)
161 | ((region.base >> 12) & 0x7fff);
162 break;
163 case 1:
164 frba->flreg1 = (((region.limit >> 12) & 0x7fff) << 16)
165 | ((region.base >> 12) & 0x7fff);
166 break;
167 case 2:
168 frba->flreg2 = (((region.limit >> 12) & 0x7fff) << 16)
169 | ((region.base >> 12) & 0x7fff);
170 break;
171 case 3:
172 frba->flreg3 = (((region.limit >> 12) & 0x7fff) << 16)
173 | ((region.base >> 12) & 0x7fff);
174 break;
175 case 4:
176 frba->flreg4 = (((region.limit >> 12) & 0x7fff) << 16)
177 | ((region.base >> 12) & 0x7fff);
178 break;
179 default:
180 fprintf(stderr, "Invalid region type.\n");
181 exit (EXIT_FAILURE);
182 }
183}
184
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700185static const char *region_name(int region_type)
186{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700187 if (region_type < 0 || region_type >= MAX_REGIONS) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700188 fprintf(stderr, "Invalid region type.\n");
189 exit (EXIT_FAILURE);
190 }
191
Chris Douglass03ce0142014-02-26 13:30:13 -0500192 return region_names[region_type].pretty;
193}
194
195static const char *region_name_short(int region_type)
196{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700197 if (region_type < 0 || region_type >= MAX_REGIONS) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500198 fprintf(stderr, "Invalid region type.\n");
199 exit (EXIT_FAILURE);
200 }
201
202 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700203}
204
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500205static int region_num(const char *name)
206{
207 int i;
208
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700209 for (i = 0; i < MAX_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500210 if (strcasecmp(name, region_names[i].pretty) == 0)
211 return i;
212 if (strcasecmp(name, region_names[i].terse) == 0)
213 return i;
214 }
215
216 return -1;
217}
218
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700219static const char *region_filename(int region_type)
220{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700221 static const char *region_filenames[MAX_REGIONS] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700222 "flashregion_0_flashdescriptor.bin",
223 "flashregion_1_bios.bin",
224 "flashregion_2_intel_me.bin",
225 "flashregion_3_gbe.bin",
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700226 "flashregion_4_platform_data.bin",
227 "flashregion_5_reserved.bin",
228 "flashregion_6_reserved.bin",
229 "flashregion_7_reserved.bin",
230 "flashregion_8_ec.bin",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700231 };
232
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700233 if (region_type < 0 || region_type >= MAX_REGIONS) {
234 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700235 exit (EXIT_FAILURE);
236 }
237
238 return region_filenames[region_type];
239}
240
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700241static void dump_region(int num, frba_t *frba)
242{
243 region_t region = get_region(frba, num);
244 printf(" Flash Region %d (%s): %08x - %08x %s\n",
245 num, region_name(num), region.base, region.limit,
246 region.size < 1 ? "(unused)" : "");
247}
248
Chris Douglass03ce0142014-02-26 13:30:13 -0500249static void dump_region_layout(char *buf, size_t bufsize, int num, frba_t *frba)
250{
251 region_t region = get_region(frba, num);
252 snprintf(buf, bufsize, "%08x:%08x %s\n",
253 region.base, region.limit, region_name_short(num));
254}
255
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700256static void dump_frba(frba_t * frba)
257{
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700258 printf("Found Region Section\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700259 printf("FLREG0: 0x%08x\n", frba->flreg0);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700260 dump_region(0, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700261 printf("FLREG1: 0x%08x\n", frba->flreg1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700262 dump_region(1, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700263 printf("FLREG2: 0x%08x\n", frba->flreg2);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700264 dump_region(2, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700265 printf("FLREG3: 0x%08x\n", frba->flreg3);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700266 dump_region(3, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700267 printf("FLREG4: 0x%08x\n", frba->flreg4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700268 dump_region(4, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700269
270 if (ifd_version >= IFD_VERSION_2) {
271 printf("FLREG5: 0x%08x\n", frba->flreg5);
272 dump_region(5, frba);
273 printf("FLREG6: 0x%08x\n", frba->flreg6);
274 dump_region(6, frba);
275 printf("FLREG7: 0x%08x\n", frba->flreg7);
276 dump_region(7, frba);
277 printf("FLREG8: 0x%08x\n", frba->flreg8);
278 dump_region(8, frba);
279 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700280}
281
Chris Douglass03ce0142014-02-26 13:30:13 -0500282static void dump_frba_layout(frba_t * frba, char *layout_fname)
283{
284 char buf[LAYOUT_LINELEN];
285 size_t bufsize = LAYOUT_LINELEN;
286 int i;
287
288 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
289 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
290 if (layout_fd == -1) {
291 perror("Could not open file");
292 exit(EXIT_FAILURE);
293 }
294
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700295 for (i = 0; i < MAX_REGIONS; i++) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500296 dump_region_layout(buf, bufsize, i, frba);
297 if (write(layout_fd, buf, strlen(buf)) < 0) {
298 perror("Could not write to file");
299 exit(EXIT_FAILURE);
300 }
301 }
302 close(layout_fd);
303 printf("Wrote layout to %s\n", layout_fname);
304}
305
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700306static void decode_spi_frequency(unsigned int freq)
307{
308 switch (freq) {
309 case SPI_FREQUENCY_20MHZ:
310 printf("20MHz");
311 break;
312 case SPI_FREQUENCY_33MHZ:
313 printf("33MHz");
314 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700315 case SPI_FREQUENCY_48MHZ:
316 printf("48MHz");
317 break;
318 case SPI_FREQUENCY_50MHZ_30MHZ:
319 switch (ifd_version) {
320 case IFD_VERSION_1:
321 printf("50MHz");
322 break;
323 case IFD_VERSION_2:
324 printf("30MHz");
325 break;
326 }
327 break;
328 case SPI_FREQUENCY_17MHZ:
329 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700330 break;
331 default:
332 printf("unknown<%x>MHz", freq);
333 }
334}
335
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700336static void decode_component_density(unsigned int density)
337{
338 switch (density) {
339 case COMPONENT_DENSITY_512KB:
340 printf("512KB");
341 break;
342 case COMPONENT_DENSITY_1MB:
343 printf("1MB");
344 break;
345 case COMPONENT_DENSITY_2MB:
346 printf("2MB");
347 break;
348 case COMPONENT_DENSITY_4MB:
349 printf("4MB");
350 break;
351 case COMPONENT_DENSITY_8MB:
352 printf("8MB");
353 break;
354 case COMPONENT_DENSITY_16MB:
355 printf("16MB");
356 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700357 case COMPONENT_DENSITY_32MB:
358 printf("32MB");
359 break;
360 case COMPONENT_DENSITY_64MB:
361 printf("64MB");
362 break;
363 case COMPONENT_DENSITY_UNUSED:
364 printf("UNUSED");
365 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700366 default:
367 printf("unknown<%x>MB", density);
368 }
369}
370
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700371static void dump_fcba(fcba_t * fcba)
372{
373 printf("\nFound Component Section\n");
374 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700375 printf(" Dual Output Fast Read Support: %ssupported\n",
376 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700377 printf(" Read ID/Read Status Clock Frequency: ");
378 decode_spi_frequency((fcba->flcomp >> 27) & 7);
379 printf("\n Write/Erase Clock Frequency: ");
380 decode_spi_frequency((fcba->flcomp >> 24) & 7);
381 printf("\n Fast Read Clock Frequency: ");
382 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700383 printf("\n Fast Read Support: %ssupported",
384 (fcba->flcomp & (1 << 20))?"":"not ");
385 printf("\n Read Clock Frequency: ");
386 decode_spi_frequency((fcba->flcomp >> 17) & 7);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700387
388 switch (ifd_version) {
389 case IFD_VERSION_1:
390 printf("\n Component 2 Density: ");
391 decode_component_density((fcba->flcomp >> 3) & 7);
392 printf("\n Component 1 Density: ");
393 decode_component_density(fcba->flcomp & 7);
394 break;
395 case IFD_VERSION_2:
396 printf("\n Component 2 Density: ");
397 decode_component_density((fcba->flcomp >> 4) & 0xf);
398 printf("\n Component 1 Density: ");
399 decode_component_density(fcba->flcomp & 0xf);
400 break;
401 }
402
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700403 printf("\n");
404 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700405 printf(" Invalid Instruction 3: 0x%02x\n",
406 (fcba->flill >> 24) & 0xff);
407 printf(" Invalid Instruction 2: 0x%02x\n",
408 (fcba->flill >> 16) & 0xff);
409 printf(" Invalid Instruction 1: 0x%02x\n",
410 (fcba->flill >> 8) & 0xff);
411 printf(" Invalid Instruction 0: 0x%02x\n",
412 fcba->flill & 0xff);
413 printf("FLPB 0x%08x\n", fcba->flpb);
414 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
415 (fcba->flpb & 0xfff) << 12);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700416}
417
418static void dump_fpsba(fpsba_t * fpsba)
419{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700420 printf("Found PCH Strap Section\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700421 printf("PCHSTRP0: 0x%08x\n", fpsba->pchstrp0);
422 printf("PCHSTRP1: 0x%08x\n", fpsba->pchstrp1);
423 printf("PCHSTRP2: 0x%08x\n", fpsba->pchstrp2);
424 printf("PCHSTRP3: 0x%08x\n", fpsba->pchstrp3);
425 printf("PCHSTRP4: 0x%08x\n", fpsba->pchstrp4);
426 printf("PCHSTRP5: 0x%08x\n", fpsba->pchstrp5);
427 printf("PCHSTRP6: 0x%08x\n", fpsba->pchstrp6);
428 printf("PCHSTRP7: 0x%08x\n", fpsba->pchstrp7);
429 printf("PCHSTRP8: 0x%08x\n", fpsba->pchstrp8);
430 printf("PCHSTRP9: 0x%08x\n", fpsba->pchstrp9);
431 printf("PCHSTRP10: 0x%08x\n", fpsba->pchstrp10);
432 printf("PCHSTRP11: 0x%08x\n", fpsba->pchstrp11);
433 printf("PCHSTRP12: 0x%08x\n", fpsba->pchstrp12);
434 printf("PCHSTRP13: 0x%08x\n", fpsba->pchstrp13);
435 printf("PCHSTRP14: 0x%08x\n", fpsba->pchstrp14);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700436 printf("PCHSTRP15: 0x%08x\n", fpsba->pchstrp15);
437 printf("PCHSTRP16: 0x%08x\n", fpsba->pchstrp16);
438 printf("PCHSTRP17: 0x%08x\n\n", fpsba->pchstrp17);
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700439}
440
441static void decode_flmstr(uint32_t flmstr)
442{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700443 int wr_shift, rd_shift;
444 if (ifd_version >= IFD_VERSION_2) {
445 wr_shift = FLMSTR_WR_SHIFT_V2;
446 rd_shift = FLMSTR_RD_SHIFT_V2;
447 } else {
448 wr_shift = FLMSTR_WR_SHIFT_V1;
449 rd_shift = FLMSTR_RD_SHIFT_V1;
450 }
451
452 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700453 if (ifd_version >= IFD_VERSION_2)
454 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700455 (flmstr & (1 << (wr_shift + 8))) ?
456 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700457 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700458 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700459 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700460 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700461 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700462 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700463 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700464 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700465 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700466 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700467
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700468 if (ifd_version >= IFD_VERSION_2)
469 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700470 (flmstr & (1 << (rd_shift + 8))) ?
471 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700472 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700473 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700474 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700475 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700476 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700477 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700478 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700479 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700480 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700481 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700482
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700483 /* Requestor ID doesn't exist for ifd 2 */
484 if (ifd_version < IFD_VERSION_2)
485 printf(" Requester ID: 0x%04x\n\n",
486 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700487}
488
489static void dump_fmba(fmba_t * fmba)
490{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700491 printf("Found Master Section\n");
492 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
493 decode_flmstr(fmba->flmstr1);
494 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
495 decode_flmstr(fmba->flmstr2);
496 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
497 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700498 if (ifd_version >= IFD_VERSION_2) {
499 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
500 decode_flmstr(fmba->flmstr5);
501 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700502}
503
504static void dump_fmsba(fmsba_t * fmsba)
505{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700506 printf("Found Processor Strap Section\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700507 printf("????: 0x%08x\n", fmsba->data[0]);
508 printf("????: 0x%08x\n", fmsba->data[1]);
509 printf("????: 0x%08x\n", fmsba->data[2]);
510 printf("????: 0x%08x\n", fmsba->data[3]);
511}
512
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700513static void dump_jid(uint32_t jid)
514{
515 printf(" SPI Componend Device ID 1: 0x%02x\n",
516 (jid >> 16) & 0xff);
517 printf(" SPI Componend Device ID 0: 0x%02x\n",
518 (jid >> 8) & 0xff);
519 printf(" SPI Componend Vendor ID: 0x%02x\n",
520 jid & 0xff);
521}
522
523static void dump_vscc(uint32_t vscc)
524{
525 printf(" Lower Erase Opcode: 0x%02x\n",
526 vscc >> 24);
527 printf(" Lower Write Enable on Write Status: 0x%02x\n",
528 vscc & (1 << 20) ? 0x06 : 0x50);
529 printf(" Lower Write Status Required: %s\n",
530 vscc & (1 << 19) ? "Yes" : "No");
531 printf(" Lower Write Granularity: %d bytes\n",
532 vscc & (1 << 18) ? 64 : 1);
533 printf(" Lower Block / Sector Erase Size: ");
534 switch ((vscc >> 16) & 0x3) {
535 case 0:
536 printf("256 Byte\n");
537 break;
538 case 1:
539 printf("4KB\n");
540 break;
541 case 2:
542 printf("8KB\n");
543 break;
544 case 3:
545 printf("64KB\n");
546 break;
547 }
548
549 printf(" Upper Erase Opcode: 0x%02x\n",
550 (vscc >> 8) & 0xff);
551 printf(" Upper Write Enable on Write Status: 0x%02x\n",
552 vscc & (1 << 4) ? 0x06 : 0x50);
553 printf(" Upper Write Status Required: %s\n",
554 vscc & (1 << 3) ? "Yes" : "No");
555 printf(" Upper Write Granularity: %d bytes\n",
556 vscc & (1 << 2) ? 64 : 1);
557 printf(" Upper Block / Sector Erase Size: ");
558 switch (vscc & 0x3) {
559 case 0:
560 printf("256 Byte\n");
561 break;
562 case 1:
563 printf("4KB\n");
564 break;
565 case 2:
566 printf("8KB\n");
567 break;
568 case 3:
569 printf("64KB\n");
570 break;
571 }
572}
573
574static void dump_vtba(vtba_t *vtba, int vtl)
575{
576 int i;
577 int num = (vtl >> 1) < 8 ? (vtl >> 1) : 8;
578
579 printf("ME VSCC table:\n");
580 for (i = 0; i < num; i++) {
581 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
582 dump_jid(vtba->entry[i].jid);
583 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
584 dump_vscc(vtba->entry[i].vscc);
585 }
586 printf("\n");
587}
588
589static void dump_oem(uint8_t *oem)
590{
591 int i, j;
592 printf("OEM Section:\n");
593 for (i = 0; i < 4; i++) {
594 printf("%02x:", i << 4);
595 for (j = 0; j < 16; j++)
596 printf(" %02x", oem[(i<<4)+j]);
597 printf ("\n");
598 }
599 printf ("\n");
600}
601
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700602static void dump_fd(char *image, int size)
603{
604 fdbar_t *fdb = find_fd(image, size);
605 if (!fdb)
606 exit(EXIT_FAILURE);
607
608 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
609 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
610 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
611 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
612 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
613
614 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
615 printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
616 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
617 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
618 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
619
620 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
621 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
622 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
623
624 printf("FLUMAP1: 0x%08x\n", fdb->flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700625 printf(" Intel ME VSCC Table Length (VTL): %d\n",
626 (fdb->flumap1 >> 8) & 0xff);
627 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
628 (fdb->flumap1 & 0xff) << 4);
629 dump_vtba((vtba_t *)
630 (image + ((fdb->flumap1 & 0xff) << 4)),
631 (fdb->flumap1 >> 8) & 0xff);
632 dump_oem((uint8_t *)image + 0xf00);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700633 dump_frba((frba_t *)
634 (image + (((fdb->flmap0 >> 16) & 0xff) << 4)));
635 dump_fcba((fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4)));
636 dump_fpsba((fpsba_t *)
637 (image + (((fdb->flmap1 >> 16) & 0xff) << 4)));
638 dump_fmba((fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4)));
639 dump_fmsba((fmsba_t *) (image + (((fdb->flmap2) & 0xff) << 4)));
640}
641
Chris Douglass03ce0142014-02-26 13:30:13 -0500642static void dump_layout(char *image, int size, char *layout_fname)
643{
644 fdbar_t *fdb = find_fd(image, size);
645 if (!fdb)
646 exit(EXIT_FAILURE);
647
648 dump_frba_layout((frba_t *)
649 (image + (((fdb->flmap0 >> 16) & 0xff) << 4)),
650 layout_fname);
651}
652
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700653static void write_regions(char *image, int size)
654{
655 int i;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700656 int max_regions = MAX_REGIONS;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700657
658 fdbar_t *fdb = find_fd(image, size);
659 if (!fdb)
660 exit(EXIT_FAILURE);
661
662 frba_t *frba =
663 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
664
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700665 /* Older descriptor images have fewer regions */
666 if (ifd_version < IFD_VERSION_2)
667 max_regions = MAX_REGIONS_OLD;
668
669 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700670 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700671 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700672 if (region.size > 0) {
673 int region_fd;
674 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600675 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700676 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200677 if (region_fd < 0) {
678 perror("Error while trying to open file");
679 exit(EXIT_FAILURE);
680 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700681 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700682 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700683 close(region_fd);
684 }
685 }
686}
687
688static void write_image(char *filename, char *image, int size)
689{
690 char new_filename[FILENAME_MAX]; // allow long file names
691 int new_fd;
692
Patrick Georgi440daf72014-08-03 12:14:25 +0200693 // - 5: leave room for ".new\0"
694 strncpy(new_filename, filename, FILENAME_MAX - 5);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700695 strncat(new_filename, ".new", FILENAME_MAX - strlen(filename));
696
697 printf("Writing new image to %s\n", new_filename);
698
699 // Now write out new image
700 new_fd = open(new_filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600701 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700702 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200703 if (new_fd < 0) {
704 perror("Error while trying to open file");
705 exit(EXIT_FAILURE);
706 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700707 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700708 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700709 close(new_fd);
710}
711
712static void set_spi_frequency(char *filename, char *image, int size,
713 enum spi_frequency freq)
714{
715 fdbar_t *fdb = find_fd(image, size);
716 fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
717
718 /* clear bits 21-29 */
719 fcba->flcomp &= ~0x3fe00000;
720 /* Read ID and Read Status Clock Frequency */
721 fcba->flcomp |= freq << 27;
722 /* Write and Erase Clock Frequency */
723 fcba->flcomp |= freq << 24;
724 /* Fast Read Clock Frequency */
725 fcba->flcomp |= freq << 21;
726
727 write_image(filename, image, size);
728}
729
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700730static void set_em100_mode(char *filename, char *image, int size)
731{
732 fdbar_t *fdb = find_fd(image, size);
733 fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700734 int freq;
735
736 switch (ifd_version) {
737 case IFD_VERSION_1:
738 freq = SPI_FREQUENCY_20MHZ;
739 break;
740 case IFD_VERSION_2:
741 freq = SPI_FREQUENCY_17MHZ;
742 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -0700743 default:
744 freq = SPI_FREQUENCY_17MHZ;
745 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700746 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700747
748 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700749 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700750}
751
Jan Tatjefa317512016-03-11 00:52:07 +0100752static void set_chipdensity(char *filename, char *image, int size,
753 unsigned int density)
754{
755 fdbar_t *fdb = find_fd(image, size);
756 fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
757
758 printf("Setting chip density to ");
759 decode_component_density(density);
760 printf("\n");
761
762 switch (ifd_version) {
763 case IFD_VERSION_1:
764 /* fail if selected density is not supported by this version */
765 if ( (density == COMPONENT_DENSITY_32MB) ||
766 (density == COMPONENT_DENSITY_64MB) ||
767 (density == COMPONENT_DENSITY_UNUSED) ) {
768 printf("error: Selected density not supported in IFD version 1.\n");
769 exit(EXIT_FAILURE);
770 }
771 break;
772 case IFD_VERSION_2:
773 /* I do not have a version 2 IFD nor do i have the docs. */
774 printf("error: Changing the chip density for IFD version 2 has not been"
775 " implemented yet.\n");
776 exit(EXIT_FAILURE);
777 default:
778 printf("error: Unknown IFD version\n");
779 exit(EXIT_FAILURE);
780 break;
781 }
782
783 /* clear chip density for corresponding chip */
784 switch (selected_chip) {
785 case 1:
786 fcba->flcomp &= ~(0x7);
787 break;
788 case 2:
789 fcba->flcomp &= ~(0x7 << 3);
790 break;
791 default: /*both chips*/
792 fcba->flcomp &= ~(0x3F);
793 break;
794 }
795
796 /* set the new density */
797 if (selected_chip == 1 || selected_chip == 0)
798 fcba->flcomp |= (density); /* first chip */
799 if (selected_chip == 2 || selected_chip == 0)
800 fcba->flcomp |= (density << 3); /* second chip */
801
802 write_image(filename, image, size);
803}
804
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700805static void lock_descriptor(char *filename, char *image, int size)
806{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700807 int wr_shift, rd_shift;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700808 fdbar_t *fdb = find_fd(image, size);
809 fmba_t *fmba = (fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4));
810 /* TODO: Dynamically take Platform Data Region and GbE Region
811 * into regard.
812 */
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700813
814 if (ifd_version >= IFD_VERSION_2) {
815 wr_shift = FLMSTR_WR_SHIFT_V2;
816 rd_shift = FLMSTR_RD_SHIFT_V2;
817
818 /* Clear non-reserved bits */
819 fmba->flmstr1 &= 0xff;
820 fmba->flmstr2 &= 0xff;
821 fmba->flmstr3 &= 0xff;
822 } else {
823 wr_shift = FLMSTR_WR_SHIFT_V1;
824 rd_shift = FLMSTR_RD_SHIFT_V1;
825
826 fmba->flmstr1 = 0;
827 fmba->flmstr2 = 0;
828 /* Requestor ID */
829 fmba->flmstr3 = 0x118;
830 }
831
832 /* CPU/BIOS can read descriptor, BIOS, and GbE. */
833 fmba->flmstr1 |= 0xb << rd_shift;
834 /* CPU/BIOS can write BIOS and GbE. */
835 fmba->flmstr1 |= 0xa << wr_shift;
836 /* ME can read descriptor, ME, and GbE. */
837 fmba->flmstr2 |= 0xd << rd_shift;
838 /* ME can write ME and GbE. */
839 fmba->flmstr2 |= 0xc << wr_shift;
840 /* GbE can write only GbE. */
841 fmba->flmstr3 |= 0x8 << rd_shift;
842 /* GbE can read only GbE. */
843 fmba->flmstr3 |= 0x8 << wr_shift;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700844
845 write_image(filename, image, size);
846}
847
848static void unlock_descriptor(char *filename, char *image, int size)
849{
850 fdbar_t *fdb = find_fd(image, size);
851 fmba_t *fmba = (fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4));
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700852
853 if (ifd_version >= IFD_VERSION_2) {
854 /* Access bits for each region are read: 19:8 write: 31:20 */
855 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
856 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
857 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
858 } else {
859 fmba->flmstr1 = 0xffff0000;
860 fmba->flmstr2 = 0xffff0000;
861 fmba->flmstr3 = 0x08080118;
862 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700863
864 write_image(filename, image, size);
865}
866
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700867void inject_region(char *filename, char *image, int size, int region_type,
868 char *region_fname)
869{
870 fdbar_t *fdb = find_fd(image, size);
871 if (!fdb)
872 exit(EXIT_FAILURE);
873 frba_t *frba =
874 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700875
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700876 region_t region = get_region(frba, region_type);
877 if (region.size <= 0xfff) {
878 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
879 region_name(region_type));
880 exit(EXIT_FAILURE);
881 }
882
Scott Duplichanf2c98372014-12-12 21:03:06 -0600883 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700884 if (region_fd == -1) {
885 perror("Could not open file");
886 exit(EXIT_FAILURE);
887 }
888 struct stat buf;
889 if (fstat(region_fd, &buf) == -1) {
890 perror("Could not stat file");
891 exit(EXIT_FAILURE);
892 }
893 int region_size = buf.st_size;
894
895 printf("File %s is %d bytes\n", region_fname, region_size);
896
897 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -0800898 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700899 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
900 " bytes. Not injecting.\n",
901 region_name(region_type), region.size,
902 region.size, region_size, region_size);
903 exit(EXIT_FAILURE);
904 }
905
906 int offset = 0;
907 if ((region_type == 1) && (region_size < region.size)) {
908 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
909 " bytes. Padding before injecting.\n",
910 region_name(region_type), region.size,
911 region.size, region_size, region_size);
912 offset = region.size - region_size;
913 memset(image + region.base, 0xff, offset);
914 }
915
Stefan Reinauer5e93b372012-09-25 13:30:48 -0700916 if (size < region.base + offset + region_size) {
917 fprintf(stderr, "Output file is too small. (%d < %d)\n",
918 size, region.base + offset + region_size);
919 exit(EXIT_FAILURE);
920 }
921
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700922 if (read(region_fd, image + region.base + offset, region_size)
923 != region_size) {
924 perror("Could not read file");
925 exit(EXIT_FAILURE);
926 }
927
928 close(region_fd);
929
930 printf("Adding %s as the %s section of %s\n",
931 region_fname, region_name(region_type), filename);
932 write_image(filename, image, size);
933}
934
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500935unsigned int next_pow2(unsigned int x)
936{
937 unsigned int y = 1;
938 if (x == 0)
939 return 0;
940 while (y <= x)
941 y = y << 1;
942
943 return y;
944}
945
946/**
947 * Determine if two memory regions overlap.
948 *
949 * @param r1, r2 Memory regions to compare.
950 * @return 0 if the two regions are seperate
951 * @return 1 if the two regions overlap
952 */
953static int regions_collide(region_t r1, region_t r2)
954{
955 if ((r1.size == 0) || (r2.size == 0))
956 return 0;
957
958 if ( ((r1.base >= r2.base) && (r1.base <= r2.limit)) ||
959 ((r1.limit >= r2.base) && (r1.limit <= r2.limit)) )
960 return 1;
961
962 return 0;
963}
964
965void new_layout(char *filename, char *image, int size, char *layout_fname)
966{
967 FILE *romlayout;
968 char tempstr[256];
969 char layout_region_name[256];
970 int i, j;
971 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700972 region_t current_regions[MAX_REGIONS];
973 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500974 int new_extent = 0;
975 char *new_image;
976
977 /* load current descriptor map and regions */
978 fdbar_t *fdb = find_fd(image, size);
979 if (!fdb)
980 exit(EXIT_FAILURE);
981
982 frba_t *frba =
983 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
984
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700985 for (i = 0; i < MAX_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500986 current_regions[i] = get_region(frba, i);
987 new_regions[i] = get_region(frba, i);
988 }
989
990 /* read new layout */
991 romlayout = fopen(layout_fname, "r");
992
993 if (!romlayout) {
994 perror("Could not read layout file.\n");
995 exit(EXIT_FAILURE);
996 }
997
998 while (!feof(romlayout)) {
999 char *tstr1, *tstr2;
1000
Patrick Georgi802ad522014-08-09 17:12:23 +02001001 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001002 layout_region_name))
1003 continue;
1004
1005 region_number = region_num(layout_region_name);
1006 if (region_number < 0)
1007 continue;
1008
1009 tstr1 = strtok(tempstr, ":");
1010 tstr2 = strtok(NULL, ":");
1011 if (!tstr1 || !tstr2) {
1012 fprintf(stderr, "Could not parse layout file.\n");
1013 exit(EXIT_FAILURE);
1014 }
1015 new_regions[region_number].base = strtol(tstr1,
1016 (char **)NULL, 16);
1017 new_regions[region_number].limit = strtol(tstr2,
1018 (char **)NULL, 16);
1019 new_regions[region_number].size =
1020 new_regions[region_number].limit -
1021 new_regions[region_number].base + 1;
1022
1023 if (new_regions[region_number].size < 0)
1024 new_regions[region_number].size = 0;
1025 }
1026 fclose(romlayout);
1027
1028 /* check new layout */
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001029 for (i = 0; i < MAX_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001030 if (new_regions[i].size == 0)
1031 continue;
1032
1033 if (new_regions[i].size < current_regions[i].size) {
1034 printf("DANGER: Region %s is shrinking.\n",
1035 region_name(i));
1036 printf(" The region will be truncated to fit.\n");
1037 printf(" This may result in an unusable image.\n");
1038 }
1039
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001040 for (j = i + 1; j < MAX_REGIONS; j++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001041 if (regions_collide(new_regions[i], new_regions[j])) {
1042 fprintf(stderr, "Regions would overlap.\n");
1043 exit(EXIT_FAILURE);
1044 }
1045 }
1046
1047 /* detect if the image size should grow */
1048 if (new_extent < new_regions[i].limit)
1049 new_extent = new_regions[i].limit;
1050 }
1051
1052 new_extent = next_pow2(new_extent - 1);
1053 if (new_extent != size) {
1054 printf("The image has changed in size.\n");
1055 printf("The old image is %d bytes.\n", size);
1056 printf("The new image is %d bytes.\n", new_extent);
1057 }
1058
1059 /* copy regions to a new image */
1060 new_image = malloc(new_extent);
1061 memset(new_image, 0xff, new_extent);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001062 for (i = 0; i < MAX_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001063 int copy_size = new_regions[i].size;
1064 int offset_current = 0, offset_new = 0;
1065 region_t current = current_regions[i];
1066 region_t new = new_regions[i];
1067
1068 if (new.size == 0)
1069 continue;
1070
1071 if (new.size > current.size) {
1072 /* copy from the end of the current region */
1073 copy_size = current.size;
1074 offset_new = new.size - current.size;
1075 }
1076
1077 if (new.size < current.size) {
1078 /* copy to the end of the new region */
1079 offset_current = current.size - new.size;
1080 }
1081
1082 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1083 region_name(i), copy_size);
1084 printf(" from %08x+%08x:%08x (%10d)\n", current.base,
1085 offset_current, current.limit, current.size);
1086 printf(" to %08x+%08x:%08x (%10d)\n", new.base,
1087 offset_new, new.limit, new.size);
1088
1089 memcpy(new_image + new.base + offset_new,
1090 image + current.base + offset_current,
1091 copy_size);
1092 }
1093
1094 /* update new descriptor regions */
1095 fdb = find_fd(new_image, new_extent);
1096 if (!fdb)
1097 exit(EXIT_FAILURE);
1098
1099 frba = (frba_t *) (new_image + (((fdb->flmap0 >> 16) & 0xff) << 4));
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001100 for (i = 1; i < MAX_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001101 set_region(frba, i, new_regions[i]);
1102 }
1103
1104 write_image(filename, new_image, new_extent);
1105 free(new_image);
1106}
1107
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001108static void print_version(void)
1109{
1110 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1111 printf("Copyright (C) 2011 Google Inc.\n\n");
1112 printf
1113 ("This program is free software: you can redistribute it and/or modify\n"
1114 "it under the terms of the GNU General Public License as published by\n"
1115 "the Free Software Foundation, version 2 of the License.\n\n"
1116 "This program is distributed in the hope that it will be useful,\n"
1117 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1118 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001119 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001120}
1121
1122static void print_usage(const char *name)
1123{
1124 printf("usage: %s [-vhdix?] <filename>\n", name);
1125 printf("\n"
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001126 " -d | --dump: dump intel firmware descriptor\n"
1127 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1128 " -x | --extract: extract intel fd modules\n"
1129 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1130 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
1131 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
Jan Tatjefa317512016-03-11 00:52:07 +01001132 " -D | --density <512|1|2|4|8|16> set chip density (512 in KByte, others in MByte)\n"
1133 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1134 " can only be used once per run:\n"
1135 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001136 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1137 " Dual Output Fast Read Support\n"
1138 " -l | --lock Lock firmware descriptor and ME region\n"
1139 " -u | --unlock Unlock firmware descriptor and ME region\n"
1140 " -v | --version: print the version\n"
1141 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001142 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1143 "\n");
1144}
1145
1146int main(int argc, char *argv[])
1147{
1148 int opt, option_index = 0;
1149 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001150 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001151 int mode_layout = 0, mode_newlayout = 0, mode_density = 0;
Chris Douglass03ce0142014-02-26 13:30:13 -05001152 char *region_type_string = NULL, *region_fname = NULL, *layout_fname = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001153 int region_type = -1, inputfreq = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001154 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001155 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1156
1157 static struct option long_options[] = {
1158 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001159 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001160 {"extract", 0, NULL, 'x'},
1161 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001162 {"newlayout", 1, NULL, 'n'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001163 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001164 {"density", 1, NULL, 'D'},
1165 {"chip", 1, NULL, 'C'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001166 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001167 {"lock", 0, NULL, 'l'},
1168 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001169 {"version", 0, NULL, 'v'},
1170 {"help", 0, NULL, 'h'},
1171 {0, 0, 0, 0}
1172 };
1173
Jan Tatjefa317512016-03-11 00:52:07 +01001174 while ((opt = getopt_long(argc, argv, "df:D:C:xi:n:s:eluvh?",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001175 long_options, &option_index)) != EOF) {
1176 switch (opt) {
1177 case 'd':
1178 mode_dump = 1;
1179 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001180 case 'f':
1181 mode_layout = 1;
1182 layout_fname = strdup(optarg);
1183 if (!layout_fname) {
1184 fprintf(stderr, "No layout file specified\n");
1185 print_usage(argv[0]);
1186 exit(EXIT_FAILURE);
1187 }
1188 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001189 case 'x':
1190 mode_extract = 1;
1191 break;
1192 case 'i':
1193 // separate type and file name
1194 region_type_string = strdup(optarg);
1195 region_fname = strchr(region_type_string, ':');
1196 if (!region_fname) {
1197 print_usage(argv[0]);
1198 exit(EXIT_FAILURE);
1199 }
1200 region_fname[0] = '\0';
1201 region_fname++;
1202 // Descriptor, BIOS, ME, GbE, Platform
1203 // valid type?
1204 if (!strcasecmp("Descriptor", region_type_string))
1205 region_type = 0;
1206 else if (!strcasecmp("BIOS", region_type_string))
1207 region_type = 1;
1208 else if (!strcasecmp("ME", region_type_string))
1209 region_type = 2;
1210 else if (!strcasecmp("GbE", region_type_string))
1211 region_type = 3;
1212 else if (!strcasecmp("Platform", region_type_string))
1213 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001214 else if (!strcasecmp("EC", region_type_string))
1215 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001216 if (region_type == -1) {
1217 fprintf(stderr, "No such region type: '%s'\n\n",
1218 region_type_string);
1219 print_usage(argv[0]);
1220 exit(EXIT_FAILURE);
1221 }
1222 mode_inject = 1;
1223 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001224 case 'n':
1225 mode_newlayout = 1;
1226 layout_fname = strdup(optarg);
1227 if (!layout_fname) {
1228 fprintf(stderr, "No layout file specified\n");
1229 print_usage(argv[0]);
1230 exit(EXIT_FAILURE);
1231 }
1232 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001233 case 'D':
1234 mode_density = 1;
1235 new_density = strtoul(optarg, NULL, 0);
1236 switch (new_density) {
1237 case 512:
1238 new_density = COMPONENT_DENSITY_512KB;
1239 break;
1240 case 1:
1241 new_density = COMPONENT_DENSITY_1MB;
1242 break;
1243 case 2:
1244 new_density = COMPONENT_DENSITY_2MB;
1245 break;
1246 case 4:
1247 new_density = COMPONENT_DENSITY_4MB;
1248 break;
1249 case 8:
1250 new_density = COMPONENT_DENSITY_8MB;
1251 break;
1252 case 16:
1253 new_density = COMPONENT_DENSITY_16MB;
1254 break;
1255 case 32:
1256 new_density = COMPONENT_DENSITY_32MB;
1257 break;
1258 case 64:
1259 new_density = COMPONENT_DENSITY_64MB;
1260 break;
1261 case 0:
1262 new_density = COMPONENT_DENSITY_UNUSED;
1263 break;
1264 default:
1265 printf("error: Unknown density\n");
1266 print_usage(argv[0]);
1267 exit(EXIT_FAILURE);
1268 }
1269 break;
1270 case 'C':
1271 selected_chip = strtol(optarg, NULL, 0);
1272 if (selected_chip > 2) {
1273 fprintf(stderr, "error: Invalid chip selection\n");
1274 print_usage(argv[0]);
1275 exit(EXIT_FAILURE);
1276 }
1277 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001278 case 's':
1279 // Parse the requested SPI frequency
1280 inputfreq = strtol(optarg, NULL, 0);
1281 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001282 case 17:
1283 spifreq = SPI_FREQUENCY_17MHZ;
1284 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001285 case 20:
1286 spifreq = SPI_FREQUENCY_20MHZ;
1287 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001288 case 30:
1289 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1290 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001291 case 33:
1292 spifreq = SPI_FREQUENCY_33MHZ;
1293 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001294 case 48:
1295 spifreq = SPI_FREQUENCY_48MHZ;
1296 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001297 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001298 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001299 break;
1300 default:
1301 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1302 inputfreq);
1303 print_usage(argv[0]);
1304 exit(EXIT_FAILURE);
1305 }
1306 mode_spifreq = 1;
1307 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001308 case 'e':
1309 mode_em100 = 1;
1310 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001311 case 'l':
1312 mode_locked = 1;
1313 if (mode_unlocked == 1) {
1314 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1315 exit(EXIT_FAILURE);
1316 }
1317 break;
1318 case 'u':
1319 mode_unlocked = 1;
1320 if (mode_locked == 1) {
1321 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1322 exit(EXIT_FAILURE);
1323 }
1324 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001325 case 'v':
1326 print_version();
1327 exit(EXIT_SUCCESS);
1328 break;
1329 case 'h':
1330 case '?':
1331 default:
1332 print_usage(argv[0]);
1333 exit(EXIT_SUCCESS);
1334 break;
1335 }
1336 }
1337
Chris Douglass03ce0142014-02-26 13:30:13 -05001338 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001339 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001340 mode_locked)) > 1) {
1341 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001342 print_usage(argv[0]);
1343 exit(EXIT_FAILURE);
1344 }
1345
Chris Douglass03ce0142014-02-26 13:30:13 -05001346 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001347 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Jan Tatjefa317512016-03-11 00:52:07 +01001348 mode_unlocked + mode_density) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001349 fprintf(stderr, "You need to specify a mode.\n\n");
1350 print_usage(argv[0]);
1351 exit(EXIT_FAILURE);
1352 }
1353
1354 if (optind + 1 != argc) {
1355 fprintf(stderr, "You need to specify a file.\n\n");
1356 print_usage(argv[0]);
1357 exit(EXIT_FAILURE);
1358 }
1359
1360 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001361 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001362 if (bios_fd == -1) {
1363 perror("Could not open file");
1364 exit(EXIT_FAILURE);
1365 }
1366 struct stat buf;
1367 if (fstat(bios_fd, &buf) == -1) {
1368 perror("Could not stat file");
1369 exit(EXIT_FAILURE);
1370 }
1371 int size = buf.st_size;
1372
1373 printf("File %s is %d bytes\n", filename, size);
1374
1375 char *image = malloc(size);
1376 if (!image) {
1377 printf("Out of memory.\n");
1378 exit(EXIT_FAILURE);
1379 }
1380
1381 if (read(bios_fd, image, size) != size) {
1382 perror("Could not read file");
1383 exit(EXIT_FAILURE);
1384 }
1385
1386 close(bios_fd);
1387
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001388 check_ifd_version(image, size);
1389
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001390 if (mode_dump)
1391 dump_fd(image, size);
1392
Chris Douglass03ce0142014-02-26 13:30:13 -05001393 if (mode_layout)
1394 dump_layout(image, size, layout_fname);
1395
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001396 if (mode_extract)
1397 write_regions(image, size);
1398
1399 if (mode_inject)
1400 inject_region(filename, image, size, region_type,
1401 region_fname);
1402
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001403 if (mode_newlayout)
1404 new_layout(filename, image, size, layout_fname);
1405
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001406 if (mode_spifreq)
1407 set_spi_frequency(filename, image, size, spifreq);
1408
Jan Tatjefa317512016-03-11 00:52:07 +01001409 if (mode_density)
1410 set_chipdensity(filename, image, size, new_density);
1411
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001412 if (mode_em100)
1413 set_em100_mode(filename, image, size);
1414
Alexander Couzensd12ea112016-09-10 13:33:05 +02001415 if (mode_locked)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001416 lock_descriptor(filename, image, size);
1417
1418 if (mode_unlocked)
1419 unlock_descriptor(filename, image, size);
1420
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001421 free(image);
1422
1423 return 0;
1424}