blob: 7921ef02dd462397a05239345fbb1e00a1e1bb49 [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;
Chris Douglasse2718652014-02-28 08:54:41 -050031
Duncan Laurie1f7fd722015-06-22 11:14:48 -070032static const struct region_name region_names[MAX_REGIONS] = {
Chris Douglass03ce0142014-02-26 13:30:13 -050033 { "Flash Descriptor", "fd" },
34 { "BIOS", "bios" },
35 { "Intel ME", "me" },
36 { "GbE", "gbe" },
Duncan Laurie1f7fd722015-06-22 11:14:48 -070037 { "Platform Data", "pd" },
38 { "Reserved", "res1" },
39 { "Reserved", "res2" },
40 { "Reserved", "res3" },
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -070041 { "EC", "ec" },
Chris Douglass03ce0142014-02-26 13:30:13 -050042};
43
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070044static fdbar_t *find_fd(char *image, int size)
45{
46 int i, found = 0;
47
48 /* Scan for FD signature */
49 for (i = 0; i < (size - 4); i += 4) {
50 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
51 found = 1;
52 break; // signature found.
53 }
54 }
55
56 if (!found) {
57 printf("No Flash Descriptor found in this image\n");
58 return NULL;
59 }
60
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070061 return (fdbar_t *) (image + i);
62}
63
Duncan Laurie1f7fd722015-06-22 11:14:48 -070064/*
65 * There is no version field in the descriptor so to determine
66 * if this is a new descriptor format we check the hardcoded SPI
67 * read frequency to see if it is fixed at 20MHz or 17MHz.
68 */
69static void check_ifd_version(char *image, int size)
70{
71 fdbar_t *fdb = find_fd(image, size);
72 fcba_t *fcba;
73 int read_freq;
74
75 if (!fdb)
76 exit(EXIT_FAILURE);
77
78 fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
79 if (!fcba)
80 exit(EXIT_FAILURE);
81
82 read_freq = (fcba->flcomp >> 17) & 7;
83
84 switch (read_freq) {
85 case SPI_FREQUENCY_20MHZ:
86 ifd_version = IFD_VERSION_1;
87 break;
88 case SPI_FREQUENCY_17MHZ:
89 ifd_version = IFD_VERSION_2;
90 break;
91 default:
92 fprintf(stderr, "Unknown descriptor version: %d\n",
93 read_freq);
94 exit(EXIT_FAILURE);
95 }
96}
97
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070098static region_t get_region(frba_t *frba, int region_type)
99{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500100 int base_mask;
101 int limit_mask;
102 uint32_t *flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700103 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500104
105 if (ifd_version >= IFD_VERSION_2)
106 base_mask = 0x7fff;
107 else
108 base_mask = 0xfff;
109
110 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700111
112 switch (region_type) {
113 case 0:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500114 flreg = &frba->flreg0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700115 break;
116 case 1:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500117 flreg = &frba->flreg1;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700118 break;
119 case 2:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500120 flreg = &frba->flreg2;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700121 break;
122 case 3:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500123 flreg = &frba->flreg3;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700124 break;
125 case 4:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500126 flreg = &frba->flreg4;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700127 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700128 case 5:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500129 flreg = &frba->flreg5;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700130 break;
131 case 6:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500132 flreg = &frba->flreg6;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700133 break;
134 case 7:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500135 flreg = &frba->flreg7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700136 break;
137 case 8:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500138 flreg = &frba->flreg8;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700139 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700140 default:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700141 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700142 exit (EXIT_FAILURE);
143 }
144
Aaron Durbin0a31e592015-08-12 11:44:02 -0500145 region.base = (*flreg & base_mask) << 12;
146 region.limit = ((*flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700147 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500148
Chris Douglass03ce0142014-02-26 13:30:13 -0500149 if (region.size < 0)
150 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700151
152 return region;
153}
154
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500155static void set_region(frba_t *frba, int region_type, region_t region)
156{
157 switch (region_type) {
158 case 0:
159 frba->flreg0 = (((region.limit >> 12) & 0x7fff) << 16)
160 | ((region.base >> 12) & 0x7fff);
161 break;
162 case 1:
163 frba->flreg1 = (((region.limit >> 12) & 0x7fff) << 16)
164 | ((region.base >> 12) & 0x7fff);
165 break;
166 case 2:
167 frba->flreg2 = (((region.limit >> 12) & 0x7fff) << 16)
168 | ((region.base >> 12) & 0x7fff);
169 break;
170 case 3:
171 frba->flreg3 = (((region.limit >> 12) & 0x7fff) << 16)
172 | ((region.base >> 12) & 0x7fff);
173 break;
174 case 4:
175 frba->flreg4 = (((region.limit >> 12) & 0x7fff) << 16)
176 | ((region.base >> 12) & 0x7fff);
177 break;
178 default:
179 fprintf(stderr, "Invalid region type.\n");
180 exit (EXIT_FAILURE);
181 }
182}
183
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700184static const char *region_name(int region_type)
185{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700186 if (region_type < 0 || region_type >= MAX_REGIONS) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700187 fprintf(stderr, "Invalid region type.\n");
188 exit (EXIT_FAILURE);
189 }
190
Chris Douglass03ce0142014-02-26 13:30:13 -0500191 return region_names[region_type].pretty;
192}
193
194static const char *region_name_short(int region_type)
195{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700196 if (region_type < 0 || region_type >= MAX_REGIONS) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500197 fprintf(stderr, "Invalid region type.\n");
198 exit (EXIT_FAILURE);
199 }
200
201 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700202}
203
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500204static int region_num(const char *name)
205{
206 int i;
207
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700208 for (i = 0; i < MAX_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500209 if (strcasecmp(name, region_names[i].pretty) == 0)
210 return i;
211 if (strcasecmp(name, region_names[i].terse) == 0)
212 return i;
213 }
214
215 return -1;
216}
217
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700218static const char *region_filename(int region_type)
219{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700220 static const char *region_filenames[MAX_REGIONS] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700221 "flashregion_0_flashdescriptor.bin",
222 "flashregion_1_bios.bin",
223 "flashregion_2_intel_me.bin",
224 "flashregion_3_gbe.bin",
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700225 "flashregion_4_platform_data.bin",
226 "flashregion_5_reserved.bin",
227 "flashregion_6_reserved.bin",
228 "flashregion_7_reserved.bin",
229 "flashregion_8_ec.bin",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700230 };
231
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700232 if (region_type < 0 || region_type >= MAX_REGIONS) {
233 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700234 exit (EXIT_FAILURE);
235 }
236
237 return region_filenames[region_type];
238}
239
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700240static void dump_region(int num, frba_t *frba)
241{
242 region_t region = get_region(frba, num);
243 printf(" Flash Region %d (%s): %08x - %08x %s\n",
244 num, region_name(num), region.base, region.limit,
245 region.size < 1 ? "(unused)" : "");
246}
247
Chris Douglass03ce0142014-02-26 13:30:13 -0500248static void dump_region_layout(char *buf, size_t bufsize, int num, frba_t *frba)
249{
250 region_t region = get_region(frba, num);
251 snprintf(buf, bufsize, "%08x:%08x %s\n",
252 region.base, region.limit, region_name_short(num));
253}
254
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700255static void dump_frba(frba_t * frba)
256{
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700257 printf("Found Region Section\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700258 printf("FLREG0: 0x%08x\n", frba->flreg0);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700259 dump_region(0, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700260 printf("FLREG1: 0x%08x\n", frba->flreg1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700261 dump_region(1, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700262 printf("FLREG2: 0x%08x\n", frba->flreg2);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700263 dump_region(2, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700264 printf("FLREG3: 0x%08x\n", frba->flreg3);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700265 dump_region(3, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700266 printf("FLREG4: 0x%08x\n", frba->flreg4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700267 dump_region(4, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700268
269 if (ifd_version >= IFD_VERSION_2) {
270 printf("FLREG5: 0x%08x\n", frba->flreg5);
271 dump_region(5, frba);
272 printf("FLREG6: 0x%08x\n", frba->flreg6);
273 dump_region(6, frba);
274 printf("FLREG7: 0x%08x\n", frba->flreg7);
275 dump_region(7, frba);
276 printf("FLREG8: 0x%08x\n", frba->flreg8);
277 dump_region(8, frba);
278 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700279}
280
Chris Douglass03ce0142014-02-26 13:30:13 -0500281static void dump_frba_layout(frba_t * frba, char *layout_fname)
282{
283 char buf[LAYOUT_LINELEN];
284 size_t bufsize = LAYOUT_LINELEN;
285 int i;
286
287 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
288 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
289 if (layout_fd == -1) {
290 perror("Could not open file");
291 exit(EXIT_FAILURE);
292 }
293
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700294 for (i = 0; i < MAX_REGIONS; i++) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500295 dump_region_layout(buf, bufsize, i, frba);
296 if (write(layout_fd, buf, strlen(buf)) < 0) {
297 perror("Could not write to file");
298 exit(EXIT_FAILURE);
299 }
300 }
301 close(layout_fd);
302 printf("Wrote layout to %s\n", layout_fname);
303}
304
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700305static void decode_spi_frequency(unsigned int freq)
306{
307 switch (freq) {
308 case SPI_FREQUENCY_20MHZ:
309 printf("20MHz");
310 break;
311 case SPI_FREQUENCY_33MHZ:
312 printf("33MHz");
313 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700314 case SPI_FREQUENCY_48MHZ:
315 printf("48MHz");
316 break;
317 case SPI_FREQUENCY_50MHZ_30MHZ:
318 switch (ifd_version) {
319 case IFD_VERSION_1:
320 printf("50MHz");
321 break;
322 case IFD_VERSION_2:
323 printf("30MHz");
324 break;
325 }
326 break;
327 case SPI_FREQUENCY_17MHZ:
328 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700329 break;
330 default:
331 printf("unknown<%x>MHz", freq);
332 }
333}
334
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700335static void decode_component_density(unsigned int density)
336{
337 switch (density) {
338 case COMPONENT_DENSITY_512KB:
339 printf("512KB");
340 break;
341 case COMPONENT_DENSITY_1MB:
342 printf("1MB");
343 break;
344 case COMPONENT_DENSITY_2MB:
345 printf("2MB");
346 break;
347 case COMPONENT_DENSITY_4MB:
348 printf("4MB");
349 break;
350 case COMPONENT_DENSITY_8MB:
351 printf("8MB");
352 break;
353 case COMPONENT_DENSITY_16MB:
354 printf("16MB");
355 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700356 case COMPONENT_DENSITY_32MB:
357 printf("32MB");
358 break;
359 case COMPONENT_DENSITY_64MB:
360 printf("64MB");
361 break;
362 case COMPONENT_DENSITY_UNUSED:
363 printf("UNUSED");
364 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700365 default:
366 printf("unknown<%x>MB", density);
367 }
368}
369
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700370static void dump_fcba(fcba_t * fcba)
371{
372 printf("\nFound Component Section\n");
373 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700374 printf(" Dual Output Fast Read Support: %ssupported\n",
375 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700376 printf(" Read ID/Read Status Clock Frequency: ");
377 decode_spi_frequency((fcba->flcomp >> 27) & 7);
378 printf("\n Write/Erase Clock Frequency: ");
379 decode_spi_frequency((fcba->flcomp >> 24) & 7);
380 printf("\n Fast Read Clock Frequency: ");
381 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700382 printf("\n Fast Read Support: %ssupported",
383 (fcba->flcomp & (1 << 20))?"":"not ");
384 printf("\n Read Clock Frequency: ");
385 decode_spi_frequency((fcba->flcomp >> 17) & 7);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700386
387 switch (ifd_version) {
388 case IFD_VERSION_1:
389 printf("\n Component 2 Density: ");
390 decode_component_density((fcba->flcomp >> 3) & 7);
391 printf("\n Component 1 Density: ");
392 decode_component_density(fcba->flcomp & 7);
393 break;
394 case IFD_VERSION_2:
395 printf("\n Component 2 Density: ");
396 decode_component_density((fcba->flcomp >> 4) & 0xf);
397 printf("\n Component 1 Density: ");
398 decode_component_density(fcba->flcomp & 0xf);
399 break;
400 }
401
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700402 printf("\n");
403 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700404 printf(" Invalid Instruction 3: 0x%02x\n",
405 (fcba->flill >> 24) & 0xff);
406 printf(" Invalid Instruction 2: 0x%02x\n",
407 (fcba->flill >> 16) & 0xff);
408 printf(" Invalid Instruction 1: 0x%02x\n",
409 (fcba->flill >> 8) & 0xff);
410 printf(" Invalid Instruction 0: 0x%02x\n",
411 fcba->flill & 0xff);
412 printf("FLPB 0x%08x\n", fcba->flpb);
413 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
414 (fcba->flpb & 0xfff) << 12);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700415}
416
417static void dump_fpsba(fpsba_t * fpsba)
418{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700419 printf("Found PCH Strap Section\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700420 printf("PCHSTRP0: 0x%08x\n", fpsba->pchstrp0);
421 printf("PCHSTRP1: 0x%08x\n", fpsba->pchstrp1);
422 printf("PCHSTRP2: 0x%08x\n", fpsba->pchstrp2);
423 printf("PCHSTRP3: 0x%08x\n", fpsba->pchstrp3);
424 printf("PCHSTRP4: 0x%08x\n", fpsba->pchstrp4);
425 printf("PCHSTRP5: 0x%08x\n", fpsba->pchstrp5);
426 printf("PCHSTRP6: 0x%08x\n", fpsba->pchstrp6);
427 printf("PCHSTRP7: 0x%08x\n", fpsba->pchstrp7);
428 printf("PCHSTRP8: 0x%08x\n", fpsba->pchstrp8);
429 printf("PCHSTRP9: 0x%08x\n", fpsba->pchstrp9);
430 printf("PCHSTRP10: 0x%08x\n", fpsba->pchstrp10);
431 printf("PCHSTRP11: 0x%08x\n", fpsba->pchstrp11);
432 printf("PCHSTRP12: 0x%08x\n", fpsba->pchstrp12);
433 printf("PCHSTRP13: 0x%08x\n", fpsba->pchstrp13);
434 printf("PCHSTRP14: 0x%08x\n", fpsba->pchstrp14);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700435 printf("PCHSTRP15: 0x%08x\n", fpsba->pchstrp15);
436 printf("PCHSTRP16: 0x%08x\n", fpsba->pchstrp16);
437 printf("PCHSTRP17: 0x%08x\n\n", fpsba->pchstrp17);
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700438}
439
440static void decode_flmstr(uint32_t flmstr)
441{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700442 int wr_shift, rd_shift;
443 if (ifd_version >= IFD_VERSION_2) {
444 wr_shift = FLMSTR_WR_SHIFT_V2;
445 rd_shift = FLMSTR_RD_SHIFT_V2;
446 } else {
447 wr_shift = FLMSTR_WR_SHIFT_V1;
448 rd_shift = FLMSTR_RD_SHIFT_V1;
449 }
450
451 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700452 if (ifd_version >= IFD_VERSION_2)
453 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700454 (flmstr & (1 << (wr_shift + 8))) ?
455 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700456 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700457 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700458 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700459 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700460 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700461 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700462 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700463 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700464 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700465 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700466
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700467 if (ifd_version >= IFD_VERSION_2)
468 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700469 (flmstr & (1 << (rd_shift + 8))) ?
470 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700471 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700472 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700473 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700474 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700475 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700476 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700477 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700478 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700479 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700480 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700481
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700482 /* Requestor ID doesn't exist for ifd 2 */
483 if (ifd_version < IFD_VERSION_2)
484 printf(" Requester ID: 0x%04x\n\n",
485 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700486}
487
488static void dump_fmba(fmba_t * fmba)
489{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700490 printf("Found Master Section\n");
491 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
492 decode_flmstr(fmba->flmstr1);
493 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
494 decode_flmstr(fmba->flmstr2);
495 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
496 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700497 if (ifd_version >= IFD_VERSION_2) {
498 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
499 decode_flmstr(fmba->flmstr5);
500 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700501}
502
503static void dump_fmsba(fmsba_t * fmsba)
504{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700505 printf("Found Processor Strap Section\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700506 printf("????: 0x%08x\n", fmsba->data[0]);
507 printf("????: 0x%08x\n", fmsba->data[1]);
508 printf("????: 0x%08x\n", fmsba->data[2]);
509 printf("????: 0x%08x\n", fmsba->data[3]);
510}
511
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700512static void dump_jid(uint32_t jid)
513{
514 printf(" SPI Componend Device ID 1: 0x%02x\n",
515 (jid >> 16) & 0xff);
516 printf(" SPI Componend Device ID 0: 0x%02x\n",
517 (jid >> 8) & 0xff);
518 printf(" SPI Componend Vendor ID: 0x%02x\n",
519 jid & 0xff);
520}
521
522static void dump_vscc(uint32_t vscc)
523{
524 printf(" Lower Erase Opcode: 0x%02x\n",
525 vscc >> 24);
526 printf(" Lower Write Enable on Write Status: 0x%02x\n",
527 vscc & (1 << 20) ? 0x06 : 0x50);
528 printf(" Lower Write Status Required: %s\n",
529 vscc & (1 << 19) ? "Yes" : "No");
530 printf(" Lower Write Granularity: %d bytes\n",
531 vscc & (1 << 18) ? 64 : 1);
532 printf(" Lower Block / Sector Erase Size: ");
533 switch ((vscc >> 16) & 0x3) {
534 case 0:
535 printf("256 Byte\n");
536 break;
537 case 1:
538 printf("4KB\n");
539 break;
540 case 2:
541 printf("8KB\n");
542 break;
543 case 3:
544 printf("64KB\n");
545 break;
546 }
547
548 printf(" Upper Erase Opcode: 0x%02x\n",
549 (vscc >> 8) & 0xff);
550 printf(" Upper Write Enable on Write Status: 0x%02x\n",
551 vscc & (1 << 4) ? 0x06 : 0x50);
552 printf(" Upper Write Status Required: %s\n",
553 vscc & (1 << 3) ? "Yes" : "No");
554 printf(" Upper Write Granularity: %d bytes\n",
555 vscc & (1 << 2) ? 64 : 1);
556 printf(" Upper Block / Sector Erase Size: ");
557 switch (vscc & 0x3) {
558 case 0:
559 printf("256 Byte\n");
560 break;
561 case 1:
562 printf("4KB\n");
563 break;
564 case 2:
565 printf("8KB\n");
566 break;
567 case 3:
568 printf("64KB\n");
569 break;
570 }
571}
572
573static void dump_vtba(vtba_t *vtba, int vtl)
574{
575 int i;
576 int num = (vtl >> 1) < 8 ? (vtl >> 1) : 8;
577
578 printf("ME VSCC table:\n");
579 for (i = 0; i < num; i++) {
580 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
581 dump_jid(vtba->entry[i].jid);
582 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
583 dump_vscc(vtba->entry[i].vscc);
584 }
585 printf("\n");
586}
587
588static void dump_oem(uint8_t *oem)
589{
590 int i, j;
591 printf("OEM Section:\n");
592 for (i = 0; i < 4; i++) {
593 printf("%02x:", i << 4);
594 for (j = 0; j < 16; j++)
595 printf(" %02x", oem[(i<<4)+j]);
596 printf ("\n");
597 }
598 printf ("\n");
599}
600
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700601static void dump_fd(char *image, int size)
602{
603 fdbar_t *fdb = find_fd(image, size);
604 if (!fdb)
605 exit(EXIT_FAILURE);
606
607 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
608 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
609 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
610 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
611 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
612
613 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
614 printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
615 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
616 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
617 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
618
619 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
620 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
621 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
622
623 printf("FLUMAP1: 0x%08x\n", fdb->flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700624 printf(" Intel ME VSCC Table Length (VTL): %d\n",
625 (fdb->flumap1 >> 8) & 0xff);
626 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
627 (fdb->flumap1 & 0xff) << 4);
628 dump_vtba((vtba_t *)
629 (image + ((fdb->flumap1 & 0xff) << 4)),
630 (fdb->flumap1 >> 8) & 0xff);
631 dump_oem((uint8_t *)image + 0xf00);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700632 dump_frba((frba_t *)
633 (image + (((fdb->flmap0 >> 16) & 0xff) << 4)));
634 dump_fcba((fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4)));
635 dump_fpsba((fpsba_t *)
636 (image + (((fdb->flmap1 >> 16) & 0xff) << 4)));
637 dump_fmba((fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4)));
638 dump_fmsba((fmsba_t *) (image + (((fdb->flmap2) & 0xff) << 4)));
639}
640
Chris Douglass03ce0142014-02-26 13:30:13 -0500641static void dump_layout(char *image, int size, char *layout_fname)
642{
643 fdbar_t *fdb = find_fd(image, size);
644 if (!fdb)
645 exit(EXIT_FAILURE);
646
647 dump_frba_layout((frba_t *)
648 (image + (((fdb->flmap0 >> 16) & 0xff) << 4)),
649 layout_fname);
650}
651
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700652static void write_regions(char *image, int size)
653{
654 int i;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700655 int max_regions = MAX_REGIONS;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700656
657 fdbar_t *fdb = find_fd(image, size);
658 if (!fdb)
659 exit(EXIT_FAILURE);
660
661 frba_t *frba =
662 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
663
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700664 /* Older descriptor images have fewer regions */
665 if (ifd_version < IFD_VERSION_2)
666 max_regions = MAX_REGIONS_OLD;
667
668 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700669 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700670 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700671 if (region.size > 0) {
672 int region_fd;
673 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600674 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700675 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200676 if (region_fd < 0) {
677 perror("Error while trying to open file");
678 exit(EXIT_FAILURE);
679 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700680 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700681 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700682 close(region_fd);
683 }
684 }
685}
686
687static void write_image(char *filename, char *image, int size)
688{
689 char new_filename[FILENAME_MAX]; // allow long file names
690 int new_fd;
691
Patrick Georgi440daf72014-08-03 12:14:25 +0200692 // - 5: leave room for ".new\0"
693 strncpy(new_filename, filename, FILENAME_MAX - 5);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700694 strncat(new_filename, ".new", FILENAME_MAX - strlen(filename));
695
696 printf("Writing new image to %s\n", new_filename);
697
698 // Now write out new image
699 new_fd = open(new_filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600700 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700701 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200702 if (new_fd < 0) {
703 perror("Error while trying to open file");
704 exit(EXIT_FAILURE);
705 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700706 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700707 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700708 close(new_fd);
709}
710
711static void set_spi_frequency(char *filename, char *image, int size,
712 enum spi_frequency freq)
713{
714 fdbar_t *fdb = find_fd(image, size);
715 fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
716
717 /* clear bits 21-29 */
718 fcba->flcomp &= ~0x3fe00000;
719 /* Read ID and Read Status Clock Frequency */
720 fcba->flcomp |= freq << 27;
721 /* Write and Erase Clock Frequency */
722 fcba->flcomp |= freq << 24;
723 /* Fast Read Clock Frequency */
724 fcba->flcomp |= freq << 21;
725
726 write_image(filename, image, size);
727}
728
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700729static void set_em100_mode(char *filename, char *image, int size)
730{
731 fdbar_t *fdb = find_fd(image, size);
732 fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700733 int freq;
734
735 switch (ifd_version) {
736 case IFD_VERSION_1:
737 freq = SPI_FREQUENCY_20MHZ;
738 break;
739 case IFD_VERSION_2:
740 freq = SPI_FREQUENCY_17MHZ;
741 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -0700742 default:
743 freq = SPI_FREQUENCY_17MHZ;
744 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700745 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700746
747 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700748 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700749}
750
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700751static void lock_descriptor(char *filename, char *image, int size)
752{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700753 int wr_shift, rd_shift;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700754 fdbar_t *fdb = find_fd(image, size);
755 fmba_t *fmba = (fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4));
756 /* TODO: Dynamically take Platform Data Region and GbE Region
757 * into regard.
758 */
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700759
760 if (ifd_version >= IFD_VERSION_2) {
761 wr_shift = FLMSTR_WR_SHIFT_V2;
762 rd_shift = FLMSTR_RD_SHIFT_V2;
763
764 /* Clear non-reserved bits */
765 fmba->flmstr1 &= 0xff;
766 fmba->flmstr2 &= 0xff;
767 fmba->flmstr3 &= 0xff;
768 } else {
769 wr_shift = FLMSTR_WR_SHIFT_V1;
770 rd_shift = FLMSTR_RD_SHIFT_V1;
771
772 fmba->flmstr1 = 0;
773 fmba->flmstr2 = 0;
774 /* Requestor ID */
775 fmba->flmstr3 = 0x118;
776 }
777
778 /* CPU/BIOS can read descriptor, BIOS, and GbE. */
779 fmba->flmstr1 |= 0xb << rd_shift;
780 /* CPU/BIOS can write BIOS and GbE. */
781 fmba->flmstr1 |= 0xa << wr_shift;
782 /* ME can read descriptor, ME, and GbE. */
783 fmba->flmstr2 |= 0xd << rd_shift;
784 /* ME can write ME and GbE. */
785 fmba->flmstr2 |= 0xc << wr_shift;
786 /* GbE can write only GbE. */
787 fmba->flmstr3 |= 0x8 << rd_shift;
788 /* GbE can read only GbE. */
789 fmba->flmstr3 |= 0x8 << wr_shift;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700790
791 write_image(filename, image, size);
792}
793
794static void unlock_descriptor(char *filename, char *image, int size)
795{
796 fdbar_t *fdb = find_fd(image, size);
797 fmba_t *fmba = (fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4));
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700798
799 if (ifd_version >= IFD_VERSION_2) {
800 /* Access bits for each region are read: 19:8 write: 31:20 */
801 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
802 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
803 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
804 } else {
805 fmba->flmstr1 = 0xffff0000;
806 fmba->flmstr2 = 0xffff0000;
807 fmba->flmstr3 = 0x08080118;
808 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700809
810 write_image(filename, image, size);
811}
812
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700813void inject_region(char *filename, char *image, int size, int region_type,
814 char *region_fname)
815{
816 fdbar_t *fdb = find_fd(image, size);
817 if (!fdb)
818 exit(EXIT_FAILURE);
819 frba_t *frba =
820 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700821
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700822 region_t region = get_region(frba, region_type);
823 if (region.size <= 0xfff) {
824 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
825 region_name(region_type));
826 exit(EXIT_FAILURE);
827 }
828
Scott Duplichanf2c98372014-12-12 21:03:06 -0600829 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700830 if (region_fd == -1) {
831 perror("Could not open file");
832 exit(EXIT_FAILURE);
833 }
834 struct stat buf;
835 if (fstat(region_fd, &buf) == -1) {
836 perror("Could not stat file");
837 exit(EXIT_FAILURE);
838 }
839 int region_size = buf.st_size;
840
841 printf("File %s is %d bytes\n", region_fname, region_size);
842
843 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -0800844 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700845 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
846 " bytes. Not injecting.\n",
847 region_name(region_type), region.size,
848 region.size, region_size, region_size);
849 exit(EXIT_FAILURE);
850 }
851
852 int offset = 0;
853 if ((region_type == 1) && (region_size < region.size)) {
854 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
855 " bytes. Padding before injecting.\n",
856 region_name(region_type), region.size,
857 region.size, region_size, region_size);
858 offset = region.size - region_size;
859 memset(image + region.base, 0xff, offset);
860 }
861
Stefan Reinauer5e93b372012-09-25 13:30:48 -0700862 if (size < region.base + offset + region_size) {
863 fprintf(stderr, "Output file is too small. (%d < %d)\n",
864 size, region.base + offset + region_size);
865 exit(EXIT_FAILURE);
866 }
867
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700868 if (read(region_fd, image + region.base + offset, region_size)
869 != region_size) {
870 perror("Could not read file");
871 exit(EXIT_FAILURE);
872 }
873
874 close(region_fd);
875
876 printf("Adding %s as the %s section of %s\n",
877 region_fname, region_name(region_type), filename);
878 write_image(filename, image, size);
879}
880
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500881unsigned int next_pow2(unsigned int x)
882{
883 unsigned int y = 1;
884 if (x == 0)
885 return 0;
886 while (y <= x)
887 y = y << 1;
888
889 return y;
890}
891
892/**
893 * Determine if two memory regions overlap.
894 *
895 * @param r1, r2 Memory regions to compare.
896 * @return 0 if the two regions are seperate
897 * @return 1 if the two regions overlap
898 */
899static int regions_collide(region_t r1, region_t r2)
900{
901 if ((r1.size == 0) || (r2.size == 0))
902 return 0;
903
904 if ( ((r1.base >= r2.base) && (r1.base <= r2.limit)) ||
905 ((r1.limit >= r2.base) && (r1.limit <= r2.limit)) )
906 return 1;
907
908 return 0;
909}
910
911void new_layout(char *filename, char *image, int size, char *layout_fname)
912{
913 FILE *romlayout;
914 char tempstr[256];
915 char layout_region_name[256];
916 int i, j;
917 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700918 region_t current_regions[MAX_REGIONS];
919 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500920 int new_extent = 0;
921 char *new_image;
922
923 /* load current descriptor map and regions */
924 fdbar_t *fdb = find_fd(image, size);
925 if (!fdb)
926 exit(EXIT_FAILURE);
927
928 frba_t *frba =
929 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
930
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700931 for (i = 0; i < MAX_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500932 current_regions[i] = get_region(frba, i);
933 new_regions[i] = get_region(frba, i);
934 }
935
936 /* read new layout */
937 romlayout = fopen(layout_fname, "r");
938
939 if (!romlayout) {
940 perror("Could not read layout file.\n");
941 exit(EXIT_FAILURE);
942 }
943
944 while (!feof(romlayout)) {
945 char *tstr1, *tstr2;
946
Patrick Georgi802ad522014-08-09 17:12:23 +0200947 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500948 layout_region_name))
949 continue;
950
951 region_number = region_num(layout_region_name);
952 if (region_number < 0)
953 continue;
954
955 tstr1 = strtok(tempstr, ":");
956 tstr2 = strtok(NULL, ":");
957 if (!tstr1 || !tstr2) {
958 fprintf(stderr, "Could not parse layout file.\n");
959 exit(EXIT_FAILURE);
960 }
961 new_regions[region_number].base = strtol(tstr1,
962 (char **)NULL, 16);
963 new_regions[region_number].limit = strtol(tstr2,
964 (char **)NULL, 16);
965 new_regions[region_number].size =
966 new_regions[region_number].limit -
967 new_regions[region_number].base + 1;
968
969 if (new_regions[region_number].size < 0)
970 new_regions[region_number].size = 0;
971 }
972 fclose(romlayout);
973
974 /* check new layout */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700975 for (i = 0; i < MAX_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500976 if (new_regions[i].size == 0)
977 continue;
978
979 if (new_regions[i].size < current_regions[i].size) {
980 printf("DANGER: Region %s is shrinking.\n",
981 region_name(i));
982 printf(" The region will be truncated to fit.\n");
983 printf(" This may result in an unusable image.\n");
984 }
985
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700986 for (j = i + 1; j < MAX_REGIONS; j++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500987 if (regions_collide(new_regions[i], new_regions[j])) {
988 fprintf(stderr, "Regions would overlap.\n");
989 exit(EXIT_FAILURE);
990 }
991 }
992
993 /* detect if the image size should grow */
994 if (new_extent < new_regions[i].limit)
995 new_extent = new_regions[i].limit;
996 }
997
998 new_extent = next_pow2(new_extent - 1);
999 if (new_extent != size) {
1000 printf("The image has changed in size.\n");
1001 printf("The old image is %d bytes.\n", size);
1002 printf("The new image is %d bytes.\n", new_extent);
1003 }
1004
1005 /* copy regions to a new image */
1006 new_image = malloc(new_extent);
1007 memset(new_image, 0xff, new_extent);
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001008 for (i = 0; i < MAX_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001009 int copy_size = new_regions[i].size;
1010 int offset_current = 0, offset_new = 0;
1011 region_t current = current_regions[i];
1012 region_t new = new_regions[i];
1013
1014 if (new.size == 0)
1015 continue;
1016
1017 if (new.size > current.size) {
1018 /* copy from the end of the current region */
1019 copy_size = current.size;
1020 offset_new = new.size - current.size;
1021 }
1022
1023 if (new.size < current.size) {
1024 /* copy to the end of the new region */
1025 offset_current = current.size - new.size;
1026 }
1027
1028 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1029 region_name(i), copy_size);
1030 printf(" from %08x+%08x:%08x (%10d)\n", current.base,
1031 offset_current, current.limit, current.size);
1032 printf(" to %08x+%08x:%08x (%10d)\n", new.base,
1033 offset_new, new.limit, new.size);
1034
1035 memcpy(new_image + new.base + offset_new,
1036 image + current.base + offset_current,
1037 copy_size);
1038 }
1039
1040 /* update new descriptor regions */
1041 fdb = find_fd(new_image, new_extent);
1042 if (!fdb)
1043 exit(EXIT_FAILURE);
1044
1045 frba = (frba_t *) (new_image + (((fdb->flmap0 >> 16) & 0xff) << 4));
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001046 for (i = 1; i < MAX_REGIONS; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001047 set_region(frba, i, new_regions[i]);
1048 }
1049
1050 write_image(filename, new_image, new_extent);
1051 free(new_image);
1052}
1053
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001054static void print_version(void)
1055{
1056 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1057 printf("Copyright (C) 2011 Google Inc.\n\n");
1058 printf
1059 ("This program is free software: you can redistribute it and/or modify\n"
1060 "it under the terms of the GNU General Public License as published by\n"
1061 "the Free Software Foundation, version 2 of the License.\n\n"
1062 "This program is distributed in the hope that it will be useful,\n"
1063 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1064 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1065 "GNU General Public License for more details.\n\n"
1066 "You should have received a copy of the GNU General Public License\n"
1067 "along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n");
1068}
1069
1070static void print_usage(const char *name)
1071{
1072 printf("usage: %s [-vhdix?] <filename>\n", name);
1073 printf("\n"
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001074 " -d | --dump: dump intel firmware descriptor\n"
1075 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1076 " -x | --extract: extract intel fd modules\n"
1077 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1078 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
1079 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
1080 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1081 " Dual Output Fast Read Support\n"
1082 " -l | --lock Lock firmware descriptor and ME region\n"
1083 " -u | --unlock Unlock firmware descriptor and ME region\n"
1084 " -v | --version: print the version\n"
1085 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001086 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1087 "\n");
1088}
1089
1090int main(int argc, char *argv[])
1091{
1092 int opt, option_index = 0;
1093 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001094 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001095 int mode_layout = 0, mode_newlayout = 0;
Chris Douglass03ce0142014-02-26 13:30:13 -05001096 char *region_type_string = NULL, *region_fname = NULL, *layout_fname = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001097 int region_type = -1, inputfreq = 0;
1098 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1099
1100 static struct option long_options[] = {
1101 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001102 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001103 {"extract", 0, NULL, 'x'},
1104 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001105 {"newlayout", 1, NULL, 'n'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001106 {"spifreq", 1, NULL, 's'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001107 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001108 {"lock", 0, NULL, 'l'},
1109 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001110 {"version", 0, NULL, 'v'},
1111 {"help", 0, NULL, 'h'},
1112 {0, 0, 0, 0}
1113 };
1114
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001115 while ((opt = getopt_long(argc, argv, "df:xi:n:s:eluvh?",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001116 long_options, &option_index)) != EOF) {
1117 switch (opt) {
1118 case 'd':
1119 mode_dump = 1;
1120 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001121 case 'f':
1122 mode_layout = 1;
1123 layout_fname = strdup(optarg);
1124 if (!layout_fname) {
1125 fprintf(stderr, "No layout file specified\n");
1126 print_usage(argv[0]);
1127 exit(EXIT_FAILURE);
1128 }
1129 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001130 case 'x':
1131 mode_extract = 1;
1132 break;
1133 case 'i':
1134 // separate type and file name
1135 region_type_string = strdup(optarg);
1136 region_fname = strchr(region_type_string, ':');
1137 if (!region_fname) {
1138 print_usage(argv[0]);
1139 exit(EXIT_FAILURE);
1140 }
1141 region_fname[0] = '\0';
1142 region_fname++;
1143 // Descriptor, BIOS, ME, GbE, Platform
1144 // valid type?
1145 if (!strcasecmp("Descriptor", region_type_string))
1146 region_type = 0;
1147 else if (!strcasecmp("BIOS", region_type_string))
1148 region_type = 1;
1149 else if (!strcasecmp("ME", region_type_string))
1150 region_type = 2;
1151 else if (!strcasecmp("GbE", region_type_string))
1152 region_type = 3;
1153 else if (!strcasecmp("Platform", region_type_string))
1154 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001155 else if (!strcasecmp("EC", region_type_string))
1156 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001157 if (region_type == -1) {
1158 fprintf(stderr, "No such region type: '%s'\n\n",
1159 region_type_string);
1160 print_usage(argv[0]);
1161 exit(EXIT_FAILURE);
1162 }
1163 mode_inject = 1;
1164 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001165 case 'n':
1166 mode_newlayout = 1;
1167 layout_fname = strdup(optarg);
1168 if (!layout_fname) {
1169 fprintf(stderr, "No layout file specified\n");
1170 print_usage(argv[0]);
1171 exit(EXIT_FAILURE);
1172 }
1173 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001174 case 's':
1175 // Parse the requested SPI frequency
1176 inputfreq = strtol(optarg, NULL, 0);
1177 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001178 case 17:
1179 spifreq = SPI_FREQUENCY_17MHZ;
1180 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001181 case 20:
1182 spifreq = SPI_FREQUENCY_20MHZ;
1183 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001184 case 30:
1185 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1186 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001187 case 33:
1188 spifreq = SPI_FREQUENCY_33MHZ;
1189 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001190 case 48:
1191 spifreq = SPI_FREQUENCY_48MHZ;
1192 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001193 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001194 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001195 break;
1196 default:
1197 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1198 inputfreq);
1199 print_usage(argv[0]);
1200 exit(EXIT_FAILURE);
1201 }
1202 mode_spifreq = 1;
1203 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001204 case 'e':
1205 mode_em100 = 1;
1206 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001207 case 'l':
1208 mode_locked = 1;
1209 if (mode_unlocked == 1) {
1210 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1211 exit(EXIT_FAILURE);
1212 }
1213 break;
1214 case 'u':
1215 mode_unlocked = 1;
1216 if (mode_locked == 1) {
1217 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1218 exit(EXIT_FAILURE);
1219 }
1220 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001221 case 'v':
1222 print_version();
1223 exit(EXIT_SUCCESS);
1224 break;
1225 case 'h':
1226 case '?':
1227 default:
1228 print_usage(argv[0]);
1229 exit(EXIT_SUCCESS);
1230 break;
1231 }
1232 }
1233
Chris Douglass03ce0142014-02-26 13:30:13 -05001234 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001235 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001236 mode_locked)) > 1) {
1237 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001238 print_usage(argv[0]);
1239 exit(EXIT_FAILURE);
1240 }
1241
Chris Douglass03ce0142014-02-26 13:30:13 -05001242 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001243 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Chris Douglass03ce0142014-02-26 13:30:13 -05001244 mode_unlocked) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001245 fprintf(stderr, "You need to specify a mode.\n\n");
1246 print_usage(argv[0]);
1247 exit(EXIT_FAILURE);
1248 }
1249
1250 if (optind + 1 != argc) {
1251 fprintf(stderr, "You need to specify a file.\n\n");
1252 print_usage(argv[0]);
1253 exit(EXIT_FAILURE);
1254 }
1255
1256 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001257 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001258 if (bios_fd == -1) {
1259 perror("Could not open file");
1260 exit(EXIT_FAILURE);
1261 }
1262 struct stat buf;
1263 if (fstat(bios_fd, &buf) == -1) {
1264 perror("Could not stat file");
1265 exit(EXIT_FAILURE);
1266 }
1267 int size = buf.st_size;
1268
1269 printf("File %s is %d bytes\n", filename, size);
1270
1271 char *image = malloc(size);
1272 if (!image) {
1273 printf("Out of memory.\n");
1274 exit(EXIT_FAILURE);
1275 }
1276
1277 if (read(bios_fd, image, size) != size) {
1278 perror("Could not read file");
1279 exit(EXIT_FAILURE);
1280 }
1281
1282 close(bios_fd);
1283
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001284 check_ifd_version(image, size);
1285
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001286 if (mode_dump)
1287 dump_fd(image, size);
1288
Chris Douglass03ce0142014-02-26 13:30:13 -05001289 if (mode_layout)
1290 dump_layout(image, size, layout_fname);
1291
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001292 if (mode_extract)
1293 write_regions(image, size);
1294
1295 if (mode_inject)
1296 inject_region(filename, image, size, region_type,
1297 region_fname);
1298
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001299 if (mode_newlayout)
1300 new_layout(filename, image, size, layout_fname);
1301
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001302 if (mode_spifreq)
1303 set_spi_frequency(filename, image, size, spifreq);
1304
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001305 if (mode_em100)
1306 set_em100_mode(filename, image, size);
1307
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001308 if(mode_locked)
1309 lock_descriptor(filename, image, size);
1310
1311 if (mode_unlocked)
1312 unlock_descriptor(filename, image, size);
1313
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001314 free(image);
1315
1316 return 0;
1317}