blob: 1024690423f365269512fde7598963ae41243efe [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;
Alexander Couzensa81bef12016-10-08 00:29:15 +020031static int max_regions = 0;
Jan Tatjefa317512016-03-11 00:52:07 +010032static int selected_chip = 0;
Andrey Petrov96ecb772016-10-31 19:31:54 -070033static int platform = -1;
Chris Douglasse2718652014-02-28 08:54:41 -050034
Duncan Laurie1f7fd722015-06-22 11:14:48 -070035static const struct region_name region_names[MAX_REGIONS] = {
Chris Douglass03ce0142014-02-26 13:30:13 -050036 { "Flash Descriptor", "fd" },
37 { "BIOS", "bios" },
38 { "Intel ME", "me" },
39 { "GbE", "gbe" },
Duncan Laurie1f7fd722015-06-22 11:14:48 -070040 { "Platform Data", "pd" },
41 { "Reserved", "res1" },
42 { "Reserved", "res2" },
43 { "Reserved", "res3" },
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -070044 { "EC", "ec" },
Chris Douglass03ce0142014-02-26 13:30:13 -050045};
46
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070047static fdbar_t *find_fd(char *image, int size)
48{
49 int i, found = 0;
50
51 /* Scan for FD signature */
52 for (i = 0; i < (size - 4); i += 4) {
53 if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
54 found = 1;
55 break; // signature found.
56 }
57 }
58
59 if (!found) {
60 printf("No Flash Descriptor found in this image\n");
61 return NULL;
62 }
63
Stefan Reinauer1c795ad12011-10-14 12:49:41 -070064 return (fdbar_t *) (image + i);
65}
66
Duncan Laurie1f7fd722015-06-22 11:14:48 -070067/*
68 * There is no version field in the descriptor so to determine
69 * if this is a new descriptor format we check the hardcoded SPI
70 * read frequency to see if it is fixed at 20MHz or 17MHz.
71 */
72static void check_ifd_version(char *image, int size)
73{
74 fdbar_t *fdb = find_fd(image, size);
75 fcba_t *fcba;
76 int read_freq;
77
78 if (!fdb)
79 exit(EXIT_FAILURE);
80
81 fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
82 if (!fcba)
83 exit(EXIT_FAILURE);
84
85 read_freq = (fcba->flcomp >> 17) & 7;
86
87 switch (read_freq) {
88 case SPI_FREQUENCY_20MHZ:
89 ifd_version = IFD_VERSION_1;
Alexander Couzensa81bef12016-10-08 00:29:15 +020090 max_regions = MAX_REGIONS_OLD;
Duncan Laurie1f7fd722015-06-22 11:14:48 -070091 break;
92 case SPI_FREQUENCY_17MHZ:
Hannah Williams589fc342016-10-06 14:29:48 -070093 case SPI_FREQUENCY_50MHZ_30MHZ:
Duncan Laurie1f7fd722015-06-22 11:14:48 -070094 ifd_version = IFD_VERSION_2;
Alexander Couzensa81bef12016-10-08 00:29:15 +020095 max_regions = MAX_REGIONS;
Duncan Laurie1f7fd722015-06-22 11:14:48 -070096 break;
97 default:
98 fprintf(stderr, "Unknown descriptor version: %d\n",
99 read_freq);
100 exit(EXIT_FAILURE);
101 }
102}
103
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700104static region_t get_region(frba_t *frba, int region_type)
105{
Aaron Durbin0a31e592015-08-12 11:44:02 -0500106 int base_mask;
107 int limit_mask;
108 uint32_t *flreg;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700109 region_t region;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500110
111 if (ifd_version >= IFD_VERSION_2)
112 base_mask = 0x7fff;
113 else
114 base_mask = 0xfff;
115
116 limit_mask = base_mask << 16;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700117
118 switch (region_type) {
119 case 0:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500120 flreg = &frba->flreg0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700121 break;
122 case 1:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500123 flreg = &frba->flreg1;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700124 break;
125 case 2:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500126 flreg = &frba->flreg2;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700127 break;
128 case 3:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500129 flreg = &frba->flreg3;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700130 break;
131 case 4:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500132 flreg = &frba->flreg4;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700133 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700134 case 5:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500135 flreg = &frba->flreg5;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700136 break;
137 case 6:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500138 flreg = &frba->flreg6;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700139 break;
140 case 7:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500141 flreg = &frba->flreg7;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700142 break;
143 case 8:
Aaron Durbin0a31e592015-08-12 11:44:02 -0500144 flreg = &frba->flreg8;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700145 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700146 default:
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700147 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700148 exit (EXIT_FAILURE);
149 }
150
Aaron Durbin0a31e592015-08-12 11:44:02 -0500151 region.base = (*flreg & base_mask) << 12;
152 region.limit = ((*flreg & limit_mask) >> 4) | 0xfff;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700153 region.size = region.limit - region.base + 1;
Aaron Durbin0a31e592015-08-12 11:44:02 -0500154
Chris Douglass03ce0142014-02-26 13:30:13 -0500155 if (region.size < 0)
156 region.size = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700157
158 return region;
159}
160
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500161static void set_region(frba_t *frba, int region_type, region_t region)
162{
163 switch (region_type) {
164 case 0:
165 frba->flreg0 = (((region.limit >> 12) & 0x7fff) << 16)
166 | ((region.base >> 12) & 0x7fff);
167 break;
168 case 1:
169 frba->flreg1 = (((region.limit >> 12) & 0x7fff) << 16)
170 | ((region.base >> 12) & 0x7fff);
171 break;
172 case 2:
173 frba->flreg2 = (((region.limit >> 12) & 0x7fff) << 16)
174 | ((region.base >> 12) & 0x7fff);
175 break;
176 case 3:
177 frba->flreg3 = (((region.limit >> 12) & 0x7fff) << 16)
178 | ((region.base >> 12) & 0x7fff);
179 break;
180 case 4:
181 frba->flreg4 = (((region.limit >> 12) & 0x7fff) << 16)
182 | ((region.base >> 12) & 0x7fff);
183 break;
184 default:
185 fprintf(stderr, "Invalid region type.\n");
186 exit (EXIT_FAILURE);
187 }
188}
189
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700190static const char *region_name(int region_type)
191{
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200192 if (region_type < 0 || region_type >= max_regions) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700193 fprintf(stderr, "Invalid region type.\n");
194 exit (EXIT_FAILURE);
195 }
196
Chris Douglass03ce0142014-02-26 13:30:13 -0500197 return region_names[region_type].pretty;
198}
199
200static const char *region_name_short(int region_type)
201{
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200202 if (region_type < 0 || region_type >= max_regions) {
Chris Douglass03ce0142014-02-26 13:30:13 -0500203 fprintf(stderr, "Invalid region type.\n");
204 exit (EXIT_FAILURE);
205 }
206
207 return region_names[region_type].terse;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700208}
209
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500210static int region_num(const char *name)
211{
212 int i;
213
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200214 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500215 if (strcasecmp(name, region_names[i].pretty) == 0)
216 return i;
217 if (strcasecmp(name, region_names[i].terse) == 0)
218 return i;
219 }
220
221 return -1;
222}
223
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700224static const char *region_filename(int region_type)
225{
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700226 static const char *region_filenames[MAX_REGIONS] = {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700227 "flashregion_0_flashdescriptor.bin",
228 "flashregion_1_bios.bin",
229 "flashregion_2_intel_me.bin",
230 "flashregion_3_gbe.bin",
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700231 "flashregion_4_platform_data.bin",
232 "flashregion_5_reserved.bin",
233 "flashregion_6_reserved.bin",
234 "flashregion_7_reserved.bin",
235 "flashregion_8_ec.bin",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700236 };
237
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200238 if (region_type < 0 || region_type >= max_regions) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700239 fprintf(stderr, "Invalid region type %d.\n", region_type);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700240 exit (EXIT_FAILURE);
241 }
242
243 return region_filenames[region_type];
244}
245
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700246static void dump_region(int num, frba_t *frba)
247{
248 region_t region = get_region(frba, num);
249 printf(" Flash Region %d (%s): %08x - %08x %s\n",
250 num, region_name(num), region.base, region.limit,
251 region.size < 1 ? "(unused)" : "");
252}
253
Chris Douglass03ce0142014-02-26 13:30:13 -0500254static void dump_region_layout(char *buf, size_t bufsize, int num, frba_t *frba)
255{
256 region_t region = get_region(frba, num);
257 snprintf(buf, bufsize, "%08x:%08x %s\n",
258 region.base, region.limit, region_name_short(num));
259}
260
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700261static void dump_frba(frba_t * frba)
262{
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700263 printf("Found Region Section\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700264 printf("FLREG0: 0x%08x\n", frba->flreg0);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700265 dump_region(0, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700266 printf("FLREG1: 0x%08x\n", frba->flreg1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700267 dump_region(1, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700268 printf("FLREG2: 0x%08x\n", frba->flreg2);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700269 dump_region(2, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700270 printf("FLREG3: 0x%08x\n", frba->flreg3);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700271 dump_region(3, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700272 printf("FLREG4: 0x%08x\n", frba->flreg4);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700273 dump_region(4, frba);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700274
275 if (ifd_version >= IFD_VERSION_2) {
276 printf("FLREG5: 0x%08x\n", frba->flreg5);
277 dump_region(5, frba);
278 printf("FLREG6: 0x%08x\n", frba->flreg6);
279 dump_region(6, frba);
280 printf("FLREG7: 0x%08x\n", frba->flreg7);
281 dump_region(7, frba);
282 printf("FLREG8: 0x%08x\n", frba->flreg8);
283 dump_region(8, frba);
284 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700285}
286
Chris Douglass03ce0142014-02-26 13:30:13 -0500287static void dump_frba_layout(frba_t * frba, char *layout_fname)
288{
289 char buf[LAYOUT_LINELEN];
290 size_t bufsize = LAYOUT_LINELEN;
291 int i;
292
293 int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
294 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
295 if (layout_fd == -1) {
296 perror("Could not open file");
297 exit(EXIT_FAILURE);
298 }
299
Alexander Couzensfd5c6582016-10-08 00:37:24 +0200300 for (i = 0; i < max_regions; i++) {
Alexander Couzenseff596b2016-10-08 00:53:09 +0200301 region_t region = get_region(frba, i);
302 /* is region invalid? */
303 if (region.size < 1)
304 continue;
305
Chris Douglass03ce0142014-02-26 13:30:13 -0500306 dump_region_layout(buf, bufsize, i, frba);
307 if (write(layout_fd, buf, strlen(buf)) < 0) {
308 perror("Could not write to file");
309 exit(EXIT_FAILURE);
310 }
311 }
312 close(layout_fd);
313 printf("Wrote layout to %s\n", layout_fname);
314}
315
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700316static void decode_spi_frequency(unsigned int freq)
317{
318 switch (freq) {
319 case SPI_FREQUENCY_20MHZ:
320 printf("20MHz");
321 break;
322 case SPI_FREQUENCY_33MHZ:
323 printf("33MHz");
324 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700325 case SPI_FREQUENCY_48MHZ:
326 printf("48MHz");
327 break;
328 case SPI_FREQUENCY_50MHZ_30MHZ:
329 switch (ifd_version) {
330 case IFD_VERSION_1:
331 printf("50MHz");
332 break;
333 case IFD_VERSION_2:
334 printf("30MHz");
335 break;
336 }
337 break;
338 case SPI_FREQUENCY_17MHZ:
339 printf("17MHz");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700340 break;
341 default:
342 printf("unknown<%x>MHz", freq);
343 }
344}
345
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700346static void decode_component_density(unsigned int density)
347{
348 switch (density) {
349 case COMPONENT_DENSITY_512KB:
350 printf("512KB");
351 break;
352 case COMPONENT_DENSITY_1MB:
353 printf("1MB");
354 break;
355 case COMPONENT_DENSITY_2MB:
356 printf("2MB");
357 break;
358 case COMPONENT_DENSITY_4MB:
359 printf("4MB");
360 break;
361 case COMPONENT_DENSITY_8MB:
362 printf("8MB");
363 break;
364 case COMPONENT_DENSITY_16MB:
365 printf("16MB");
366 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700367 case COMPONENT_DENSITY_32MB:
368 printf("32MB");
369 break;
370 case COMPONENT_DENSITY_64MB:
371 printf("64MB");
372 break;
373 case COMPONENT_DENSITY_UNUSED:
374 printf("UNUSED");
375 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700376 default:
377 printf("unknown<%x>MB", density);
378 }
379}
380
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700381static void dump_fcba(fcba_t * fcba)
382{
383 printf("\nFound Component Section\n");
384 printf("FLCOMP 0x%08x\n", fcba->flcomp);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700385 printf(" Dual Output Fast Read Support: %ssupported\n",
386 (fcba->flcomp & (1 << 30))?"":"not ");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700387 printf(" Read ID/Read Status Clock Frequency: ");
388 decode_spi_frequency((fcba->flcomp >> 27) & 7);
389 printf("\n Write/Erase Clock Frequency: ");
390 decode_spi_frequency((fcba->flcomp >> 24) & 7);
391 printf("\n Fast Read Clock Frequency: ");
392 decode_spi_frequency((fcba->flcomp >> 21) & 7);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700393 printf("\n Fast Read Support: %ssupported",
394 (fcba->flcomp & (1 << 20))?"":"not ");
395 printf("\n Read Clock Frequency: ");
396 decode_spi_frequency((fcba->flcomp >> 17) & 7);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700397
398 switch (ifd_version) {
399 case IFD_VERSION_1:
400 printf("\n Component 2 Density: ");
401 decode_component_density((fcba->flcomp >> 3) & 7);
402 printf("\n Component 1 Density: ");
403 decode_component_density(fcba->flcomp & 7);
404 break;
405 case IFD_VERSION_2:
406 printf("\n Component 2 Density: ");
407 decode_component_density((fcba->flcomp >> 4) & 0xf);
408 printf("\n Component 1 Density: ");
409 decode_component_density(fcba->flcomp & 0xf);
410 break;
411 }
412
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700413 printf("\n");
414 printf("FLILL 0x%08x\n", fcba->flill);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700415 printf(" Invalid Instruction 3: 0x%02x\n",
416 (fcba->flill >> 24) & 0xff);
417 printf(" Invalid Instruction 2: 0x%02x\n",
418 (fcba->flill >> 16) & 0xff);
419 printf(" Invalid Instruction 1: 0x%02x\n",
420 (fcba->flill >> 8) & 0xff);
421 printf(" Invalid Instruction 0: 0x%02x\n",
422 fcba->flill & 0xff);
423 printf("FLPB 0x%08x\n", fcba->flpb);
424 printf(" Flash Partition Boundary Address: 0x%06x\n\n",
425 (fcba->flpb & 0xfff) << 12);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700426}
427
428static void dump_fpsba(fpsba_t * fpsba)
429{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700430 printf("Found PCH Strap Section\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700431 printf("PCHSTRP0: 0x%08x\n", fpsba->pchstrp0);
432 printf("PCHSTRP1: 0x%08x\n", fpsba->pchstrp1);
433 printf("PCHSTRP2: 0x%08x\n", fpsba->pchstrp2);
434 printf("PCHSTRP3: 0x%08x\n", fpsba->pchstrp3);
435 printf("PCHSTRP4: 0x%08x\n", fpsba->pchstrp4);
436 printf("PCHSTRP5: 0x%08x\n", fpsba->pchstrp5);
437 printf("PCHSTRP6: 0x%08x\n", fpsba->pchstrp6);
438 printf("PCHSTRP7: 0x%08x\n", fpsba->pchstrp7);
439 printf("PCHSTRP8: 0x%08x\n", fpsba->pchstrp8);
440 printf("PCHSTRP9: 0x%08x\n", fpsba->pchstrp9);
441 printf("PCHSTRP10: 0x%08x\n", fpsba->pchstrp10);
442 printf("PCHSTRP11: 0x%08x\n", fpsba->pchstrp11);
443 printf("PCHSTRP12: 0x%08x\n", fpsba->pchstrp12);
444 printf("PCHSTRP13: 0x%08x\n", fpsba->pchstrp13);
445 printf("PCHSTRP14: 0x%08x\n", fpsba->pchstrp14);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700446 printf("PCHSTRP15: 0x%08x\n", fpsba->pchstrp15);
447 printf("PCHSTRP16: 0x%08x\n", fpsba->pchstrp16);
448 printf("PCHSTRP17: 0x%08x\n\n", fpsba->pchstrp17);
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700449}
450
451static void decode_flmstr(uint32_t flmstr)
452{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700453 int wr_shift, rd_shift;
454 if (ifd_version >= IFD_VERSION_2) {
455 wr_shift = FLMSTR_WR_SHIFT_V2;
456 rd_shift = FLMSTR_RD_SHIFT_V2;
457 } else {
458 wr_shift = FLMSTR_WR_SHIFT_V1;
459 rd_shift = FLMSTR_RD_SHIFT_V1;
460 }
461
462 /* EC region access only available on v2+ */
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700463 if (ifd_version >= IFD_VERSION_2)
464 printf(" EC Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700465 (flmstr & (1 << (wr_shift + 8))) ?
466 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700467 printf(" Platform Data Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700468 (flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700469 printf(" GbE Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700470 (flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700471 printf(" Intel ME Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700472 (flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700473 printf(" Host CPU/BIOS Region Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700474 (flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700475 printf(" Flash Descriptor Write Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700476 (flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700477
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700478 if (ifd_version >= IFD_VERSION_2)
479 printf(" EC Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700480 (flmstr & (1 << (rd_shift + 8))) ?
481 "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700482 printf(" Platform Data Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700483 (flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700484 printf(" GbE Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700485 (flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700486 printf(" Intel ME Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700487 (flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700488 printf(" Host CPU/BIOS Region Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700489 (flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700490 printf(" Flash Descriptor Read Access: %s\n",
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700491 (flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700492
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700493 /* Requestor ID doesn't exist for ifd 2 */
494 if (ifd_version < IFD_VERSION_2)
495 printf(" Requester ID: 0x%04x\n\n",
496 flmstr & 0xffff);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700497}
498
499static void dump_fmba(fmba_t * fmba)
500{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700501 printf("Found Master Section\n");
502 printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
503 decode_flmstr(fmba->flmstr1);
504 printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
505 decode_flmstr(fmba->flmstr2);
506 printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
507 decode_flmstr(fmba->flmstr3);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700508 if (ifd_version >= IFD_VERSION_2) {
509 printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
510 decode_flmstr(fmba->flmstr5);
511 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700512}
513
514static void dump_fmsba(fmsba_t * fmsba)
515{
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700516 printf("Found Processor Strap Section\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700517 printf("????: 0x%08x\n", fmsba->data[0]);
518 printf("????: 0x%08x\n", fmsba->data[1]);
519 printf("????: 0x%08x\n", fmsba->data[2]);
520 printf("????: 0x%08x\n", fmsba->data[3]);
521}
522
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700523static void dump_jid(uint32_t jid)
524{
525 printf(" SPI Componend Device ID 1: 0x%02x\n",
526 (jid >> 16) & 0xff);
527 printf(" SPI Componend Device ID 0: 0x%02x\n",
528 (jid >> 8) & 0xff);
529 printf(" SPI Componend Vendor ID: 0x%02x\n",
530 jid & 0xff);
531}
532
533static void dump_vscc(uint32_t vscc)
534{
535 printf(" Lower Erase Opcode: 0x%02x\n",
536 vscc >> 24);
537 printf(" Lower Write Enable on Write Status: 0x%02x\n",
538 vscc & (1 << 20) ? 0x06 : 0x50);
539 printf(" Lower Write Status Required: %s\n",
540 vscc & (1 << 19) ? "Yes" : "No");
541 printf(" Lower Write Granularity: %d bytes\n",
542 vscc & (1 << 18) ? 64 : 1);
543 printf(" Lower Block / Sector Erase Size: ");
544 switch ((vscc >> 16) & 0x3) {
545 case 0:
546 printf("256 Byte\n");
547 break;
548 case 1:
549 printf("4KB\n");
550 break;
551 case 2:
552 printf("8KB\n");
553 break;
554 case 3:
555 printf("64KB\n");
556 break;
557 }
558
559 printf(" Upper Erase Opcode: 0x%02x\n",
560 (vscc >> 8) & 0xff);
561 printf(" Upper Write Enable on Write Status: 0x%02x\n",
562 vscc & (1 << 4) ? 0x06 : 0x50);
563 printf(" Upper Write Status Required: %s\n",
564 vscc & (1 << 3) ? "Yes" : "No");
565 printf(" Upper Write Granularity: %d bytes\n",
566 vscc & (1 << 2) ? 64 : 1);
567 printf(" Upper Block / Sector Erase Size: ");
568 switch (vscc & 0x3) {
569 case 0:
570 printf("256 Byte\n");
571 break;
572 case 1:
573 printf("4KB\n");
574 break;
575 case 2:
576 printf("8KB\n");
577 break;
578 case 3:
579 printf("64KB\n");
580 break;
581 }
582}
583
584static void dump_vtba(vtba_t *vtba, int vtl)
585{
586 int i;
587 int num = (vtl >> 1) < 8 ? (vtl >> 1) : 8;
588
589 printf("ME VSCC table:\n");
590 for (i = 0; i < num; i++) {
591 printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
592 dump_jid(vtba->entry[i].jid);
593 printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
594 dump_vscc(vtba->entry[i].vscc);
595 }
596 printf("\n");
597}
598
599static void dump_oem(uint8_t *oem)
600{
601 int i, j;
602 printf("OEM Section:\n");
603 for (i = 0; i < 4; i++) {
604 printf("%02x:", i << 4);
605 for (j = 0; j < 16; j++)
606 printf(" %02x", oem[(i<<4)+j]);
607 printf ("\n");
608 }
609 printf ("\n");
610}
611
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700612static void dump_fd(char *image, int size)
613{
614 fdbar_t *fdb = find_fd(image, size);
615 if (!fdb)
616 exit(EXIT_FAILURE);
617
618 printf("FLMAP0: 0x%08x\n", fdb->flmap0);
619 printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
620 printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
621 printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
622 printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
623
624 printf("FLMAP1: 0x%08x\n", fdb->flmap1);
625 printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
626 printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
627 printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
628 printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
629
630 printf("FLMAP2: 0x%08x\n", fdb->flmap2);
631 printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
632 printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
633
634 printf("FLUMAP1: 0x%08x\n", fdb->flumap1);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700635 printf(" Intel ME VSCC Table Length (VTL): %d\n",
636 (fdb->flumap1 >> 8) & 0xff);
637 printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
638 (fdb->flumap1 & 0xff) << 4);
639 dump_vtba((vtba_t *)
640 (image + ((fdb->flumap1 & 0xff) << 4)),
641 (fdb->flumap1 >> 8) & 0xff);
642 dump_oem((uint8_t *)image + 0xf00);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700643 dump_frba((frba_t *)
644 (image + (((fdb->flmap0 >> 16) & 0xff) << 4)));
645 dump_fcba((fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4)));
646 dump_fpsba((fpsba_t *)
647 (image + (((fdb->flmap1 >> 16) & 0xff) << 4)));
648 dump_fmba((fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4)));
649 dump_fmsba((fmsba_t *) (image + (((fdb->flmap2) & 0xff) << 4)));
650}
651
Chris Douglass03ce0142014-02-26 13:30:13 -0500652static void dump_layout(char *image, int size, char *layout_fname)
653{
654 fdbar_t *fdb = find_fd(image, size);
655 if (!fdb)
656 exit(EXIT_FAILURE);
657
658 dump_frba_layout((frba_t *)
659 (image + (((fdb->flmap0 >> 16) & 0xff) << 4)),
660 layout_fname);
661}
662
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700663static void write_regions(char *image, int size)
664{
665 int i;
666
667 fdbar_t *fdb = find_fd(image, size);
668 if (!fdb)
669 exit(EXIT_FAILURE);
670
671 frba_t *frba =
672 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
673
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700674 for (i = 0; i < max_regions; i++) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700675 region_t region = get_region(frba, i);
Stefan Reinauer4a17d292012-09-27 12:42:15 -0700676 dump_region(i, frba);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700677 if (region.size > 0) {
678 int region_fd;
679 region_fd = open(region_filename(i),
Scott Duplichanf2c98372014-12-12 21:03:06 -0600680 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700681 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200682 if (region_fd < 0) {
683 perror("Error while trying to open file");
684 exit(EXIT_FAILURE);
685 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700686 if (write(region_fd, image + region.base, region.size) != region.size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700687 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700688 close(region_fd);
689 }
690 }
691}
692
693static void write_image(char *filename, char *image, int size)
694{
695 char new_filename[FILENAME_MAX]; // allow long file names
696 int new_fd;
697
Patrick Georgi440daf72014-08-03 12:14:25 +0200698 // - 5: leave room for ".new\0"
699 strncpy(new_filename, filename, FILENAME_MAX - 5);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700700 strncat(new_filename, ".new", FILENAME_MAX - strlen(filename));
701
702 printf("Writing new image to %s\n", new_filename);
703
704 // Now write out new image
705 new_fd = open(new_filename,
Scott Duplichanf2c98372014-12-12 21:03:06 -0600706 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700707 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Patrick Georgi38fa6ed2014-08-03 12:18:45 +0200708 if (new_fd < 0) {
709 perror("Error while trying to open file");
710 exit(EXIT_FAILURE);
711 }
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700712 if (write(new_fd, image, size) != size)
Stefan Reinauera9f670a2012-06-18 16:02:20 -0700713 perror("Error while writing");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700714 close(new_fd);
715}
716
717static void set_spi_frequency(char *filename, char *image, int size,
718 enum spi_frequency freq)
719{
720 fdbar_t *fdb = find_fd(image, size);
721 fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
722
723 /* clear bits 21-29 */
724 fcba->flcomp &= ~0x3fe00000;
725 /* Read ID and Read Status Clock Frequency */
726 fcba->flcomp |= freq << 27;
727 /* Write and Erase Clock Frequency */
728 fcba->flcomp |= freq << 24;
729 /* Fast Read Clock Frequency */
730 fcba->flcomp |= freq << 21;
731
732 write_image(filename, image, size);
733}
734
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700735static void set_em100_mode(char *filename, char *image, int size)
736{
737 fdbar_t *fdb = find_fd(image, size);
738 fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700739 int freq;
740
741 switch (ifd_version) {
742 case IFD_VERSION_1:
743 freq = SPI_FREQUENCY_20MHZ;
744 break;
745 case IFD_VERSION_2:
746 freq = SPI_FREQUENCY_17MHZ;
747 break;
Alexandru Gagniuc71a7ba22015-09-10 08:37:42 -0700748 default:
749 freq = SPI_FREQUENCY_17MHZ;
750 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700751 }
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700752
753 fcba->flcomp &= ~(1 << 30);
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700754 set_spi_frequency(filename, image, size, freq);
Stefan Reinauer1b1309f2012-05-11 15:53:43 -0700755}
756
Jan Tatjefa317512016-03-11 00:52:07 +0100757static void set_chipdensity(char *filename, char *image, int size,
758 unsigned int density)
759{
760 fdbar_t *fdb = find_fd(image, size);
761 fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
762
763 printf("Setting chip density to ");
764 decode_component_density(density);
765 printf("\n");
766
767 switch (ifd_version) {
768 case IFD_VERSION_1:
769 /* fail if selected density is not supported by this version */
770 if ( (density == COMPONENT_DENSITY_32MB) ||
771 (density == COMPONENT_DENSITY_64MB) ||
772 (density == COMPONENT_DENSITY_UNUSED) ) {
773 printf("error: Selected density not supported in IFD version 1.\n");
774 exit(EXIT_FAILURE);
775 }
776 break;
777 case IFD_VERSION_2:
778 /* I do not have a version 2 IFD nor do i have the docs. */
779 printf("error: Changing the chip density for IFD version 2 has not been"
780 " implemented yet.\n");
781 exit(EXIT_FAILURE);
782 default:
783 printf("error: Unknown IFD version\n");
784 exit(EXIT_FAILURE);
785 break;
786 }
787
788 /* clear chip density for corresponding chip */
789 switch (selected_chip) {
790 case 1:
791 fcba->flcomp &= ~(0x7);
792 break;
793 case 2:
794 fcba->flcomp &= ~(0x7 << 3);
795 break;
796 default: /*both chips*/
797 fcba->flcomp &= ~(0x3F);
798 break;
799 }
800
801 /* set the new density */
802 if (selected_chip == 1 || selected_chip == 0)
803 fcba->flcomp |= (density); /* first chip */
804 if (selected_chip == 2 || selected_chip == 0)
805 fcba->flcomp |= (density << 3); /* second chip */
806
807 write_image(filename, image, size);
808}
809
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700810static void lock_descriptor(char *filename, char *image, int size)
811{
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700812 int wr_shift, rd_shift;
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700813 fdbar_t *fdb = find_fd(image, size);
814 fmba_t *fmba = (fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4));
815 /* TODO: Dynamically take Platform Data Region and GbE Region
816 * into regard.
817 */
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700818
819 if (ifd_version >= IFD_VERSION_2) {
820 wr_shift = FLMSTR_WR_SHIFT_V2;
821 rd_shift = FLMSTR_RD_SHIFT_V2;
822
823 /* Clear non-reserved bits */
824 fmba->flmstr1 &= 0xff;
825 fmba->flmstr2 &= 0xff;
826 fmba->flmstr3 &= 0xff;
827 } else {
828 wr_shift = FLMSTR_WR_SHIFT_V1;
829 rd_shift = FLMSTR_RD_SHIFT_V1;
830
831 fmba->flmstr1 = 0;
832 fmba->flmstr2 = 0;
833 /* Requestor ID */
834 fmba->flmstr3 = 0x118;
835 }
836
Andrey Petrov96ecb772016-10-31 19:31:54 -0700837 switch (platform) {
838 case PLATFORM_APOLLOLAKE:
839 /* CPU/BIOS can read descriptor and BIOS */
840 fmba->flmstr1 |= 0x3 << rd_shift;
841 /* CPU/BIOS can write BIOS */
842 fmba->flmstr1 |= 0x2 << wr_shift;
843 /* TXE can read descriptor, BIOS and Device Expansion */
844 fmba->flmstr2 |= 0x23 << rd_shift;
845 /* TXE can only write Device Expansion */
846 fmba->flmstr2 |= 0x20 << wr_shift;
847 break;
848 default:
849 /* CPU/BIOS can read descriptor, BIOS, and GbE. */
850 fmba->flmstr1 |= 0xb << rd_shift;
851 /* CPU/BIOS can write BIOS and GbE. */
852 fmba->flmstr1 |= 0xa << wr_shift;
853 /* ME can read descriptor, ME, and GbE. */
854 fmba->flmstr2 |= 0xd << rd_shift;
855 /* ME can write ME and GbE. */
856 fmba->flmstr2 |= 0xc << wr_shift;
857 /* GbE can write only GbE. */
858 fmba->flmstr3 |= 0x8 << rd_shift;
859 /* GbE can read only GbE. */
860 fmba->flmstr3 |= 0x8 << wr_shift;
861 break;
862 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700863
864 write_image(filename, image, size);
865}
866
867static void unlock_descriptor(char *filename, char *image, int size)
868{
869 fdbar_t *fdb = find_fd(image, size);
870 fmba_t *fmba = (fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4));
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700871
872 if (ifd_version >= IFD_VERSION_2) {
873 /* Access bits for each region are read: 19:8 write: 31:20 */
874 fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
875 fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
876 fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
877 } else {
878 fmba->flmstr1 = 0xffff0000;
879 fmba->flmstr2 = 0xffff0000;
Patrick Rudolph8a06cc72017-01-08 09:57:47 +0100880 /* Keep chipset specific Requester ID */
881 fmba->flmstr3 = 0x08080000 | (fmba->flmstr3 & 0xffff);
Shawn Nematbakhshd2cb1182015-09-10 19:07:13 -0700882 }
Stefan Reinauer3c53d332012-09-26 17:33:39 -0700883
884 write_image(filename, image, size);
885}
886
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700887void inject_region(char *filename, char *image, int size, int region_type,
888 char *region_fname)
889{
890 fdbar_t *fdb = find_fd(image, size);
891 if (!fdb)
892 exit(EXIT_FAILURE);
893 frba_t *frba =
894 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
Stefan Reinauer5ff7c132011-10-31 12:56:45 -0700895
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700896 region_t region = get_region(frba, region_type);
897 if (region.size <= 0xfff) {
898 fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
899 region_name(region_type));
900 exit(EXIT_FAILURE);
901 }
902
Scott Duplichanf2c98372014-12-12 21:03:06 -0600903 int region_fd = open(region_fname, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700904 if (region_fd == -1) {
905 perror("Could not open file");
906 exit(EXIT_FAILURE);
907 }
908 struct stat buf;
909 if (fstat(region_fd, &buf) == -1) {
910 perror("Could not stat file");
911 exit(EXIT_FAILURE);
912 }
913 int region_size = buf.st_size;
914
915 printf("File %s is %d bytes\n", region_fname, region_size);
916
917 if ( (region_size > region.size) || ((region_type != 1) &&
Vadim Bendeburybb1177e2011-11-09 14:11:26 -0800918 (region_size > region.size))) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700919 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
920 " bytes. Not injecting.\n",
921 region_name(region_type), region.size,
922 region.size, region_size, region_size);
923 exit(EXIT_FAILURE);
924 }
925
926 int offset = 0;
927 if ((region_type == 1) && (region_size < region.size)) {
928 fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
929 " bytes. Padding before injecting.\n",
930 region_name(region_type), region.size,
931 region.size, region_size, region_size);
932 offset = region.size - region_size;
933 memset(image + region.base, 0xff, offset);
934 }
935
Stefan Reinauer5e93b372012-09-25 13:30:48 -0700936 if (size < region.base + offset + region_size) {
937 fprintf(stderr, "Output file is too small. (%d < %d)\n",
938 size, region.base + offset + region_size);
939 exit(EXIT_FAILURE);
940 }
941
Stefan Reinauer1c795ad12011-10-14 12:49:41 -0700942 if (read(region_fd, image + region.base + offset, region_size)
943 != region_size) {
944 perror("Could not read file");
945 exit(EXIT_FAILURE);
946 }
947
948 close(region_fd);
949
950 printf("Adding %s as the %s section of %s\n",
951 region_fname, region_name(region_type), filename);
952 write_image(filename, image, size);
953}
954
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500955unsigned int next_pow2(unsigned int x)
956{
957 unsigned int y = 1;
958 if (x == 0)
959 return 0;
960 while (y <= x)
961 y = y << 1;
962
963 return y;
964}
965
966/**
967 * Determine if two memory regions overlap.
968 *
969 * @param r1, r2 Memory regions to compare.
970 * @return 0 if the two regions are seperate
971 * @return 1 if the two regions overlap
972 */
973static int regions_collide(region_t r1, region_t r2)
974{
975 if ((r1.size == 0) || (r2.size == 0))
976 return 0;
977
978 if ( ((r1.base >= r2.base) && (r1.base <= r2.limit)) ||
979 ((r1.limit >= r2.base) && (r1.limit <= r2.limit)) )
980 return 1;
981
982 return 0;
983}
984
985void new_layout(char *filename, char *image, int size, char *layout_fname)
986{
987 FILE *romlayout;
988 char tempstr[256];
989 char layout_region_name[256];
990 int i, j;
991 int region_number;
Duncan Laurie1f7fd722015-06-22 11:14:48 -0700992 region_t current_regions[MAX_REGIONS];
993 region_t new_regions[MAX_REGIONS];
Chris Douglass4eabe1e2014-02-27 09:25:19 -0500994 int new_extent = 0;
995 char *new_image;
996
997 /* load current descriptor map and regions */
998 fdbar_t *fdb = find_fd(image, size);
999 if (!fdb)
1000 exit(EXIT_FAILURE);
1001
1002 frba_t *frba =
1003 (frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
1004
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001005 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001006 current_regions[i] = get_region(frba, i);
1007 new_regions[i] = get_region(frba, i);
1008 }
1009
1010 /* read new layout */
1011 romlayout = fopen(layout_fname, "r");
1012
1013 if (!romlayout) {
1014 perror("Could not read layout file.\n");
1015 exit(EXIT_FAILURE);
1016 }
1017
1018 while (!feof(romlayout)) {
1019 char *tstr1, *tstr2;
1020
Patrick Georgi802ad522014-08-09 17:12:23 +02001021 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001022 layout_region_name))
1023 continue;
1024
1025 region_number = region_num(layout_region_name);
1026 if (region_number < 0)
1027 continue;
1028
1029 tstr1 = strtok(tempstr, ":");
1030 tstr2 = strtok(NULL, ":");
1031 if (!tstr1 || !tstr2) {
1032 fprintf(stderr, "Could not parse layout file.\n");
1033 exit(EXIT_FAILURE);
1034 }
1035 new_regions[region_number].base = strtol(tstr1,
1036 (char **)NULL, 16);
1037 new_regions[region_number].limit = strtol(tstr2,
1038 (char **)NULL, 16);
1039 new_regions[region_number].size =
1040 new_regions[region_number].limit -
1041 new_regions[region_number].base + 1;
1042
1043 if (new_regions[region_number].size < 0)
1044 new_regions[region_number].size = 0;
1045 }
1046 fclose(romlayout);
1047
1048 /* check new layout */
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001049 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001050 if (new_regions[i].size == 0)
1051 continue;
1052
1053 if (new_regions[i].size < current_regions[i].size) {
1054 printf("DANGER: Region %s is shrinking.\n",
1055 region_name(i));
1056 printf(" The region will be truncated to fit.\n");
1057 printf(" This may result in an unusable image.\n");
1058 }
1059
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001060 for (j = i + 1; j < max_regions; j++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001061 if (regions_collide(new_regions[i], new_regions[j])) {
1062 fprintf(stderr, "Regions would overlap.\n");
1063 exit(EXIT_FAILURE);
1064 }
1065 }
1066
1067 /* detect if the image size should grow */
1068 if (new_extent < new_regions[i].limit)
1069 new_extent = new_regions[i].limit;
1070 }
1071
1072 new_extent = next_pow2(new_extent - 1);
1073 if (new_extent != size) {
1074 printf("The image has changed in size.\n");
1075 printf("The old image is %d bytes.\n", size);
1076 printf("The new image is %d bytes.\n", new_extent);
1077 }
1078
1079 /* copy regions to a new image */
1080 new_image = malloc(new_extent);
1081 memset(new_image, 0xff, new_extent);
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001082 for (i = 0; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001083 int copy_size = new_regions[i].size;
1084 int offset_current = 0, offset_new = 0;
1085 region_t current = current_regions[i];
1086 region_t new = new_regions[i];
1087
1088 if (new.size == 0)
1089 continue;
1090
1091 if (new.size > current.size) {
1092 /* copy from the end of the current region */
1093 copy_size = current.size;
1094 offset_new = new.size - current.size;
1095 }
1096
1097 if (new.size < current.size) {
1098 /* copy to the end of the new region */
1099 offset_current = current.size - new.size;
1100 }
1101
1102 printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
1103 region_name(i), copy_size);
1104 printf(" from %08x+%08x:%08x (%10d)\n", current.base,
1105 offset_current, current.limit, current.size);
1106 printf(" to %08x+%08x:%08x (%10d)\n", new.base,
1107 offset_new, new.limit, new.size);
1108
1109 memcpy(new_image + new.base + offset_new,
1110 image + current.base + offset_current,
1111 copy_size);
1112 }
1113
1114 /* update new descriptor regions */
1115 fdb = find_fd(new_image, new_extent);
1116 if (!fdb)
1117 exit(EXIT_FAILURE);
1118
1119 frba = (frba_t *) (new_image + (((fdb->flmap0 >> 16) & 0xff) << 4));
Alexander Couzensfd5c6582016-10-08 00:37:24 +02001120 for (i = 1; i < max_regions; i++) {
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001121 set_region(frba, i, new_regions[i]);
1122 }
1123
1124 write_image(filename, new_image, new_extent);
1125 free(new_image);
1126}
1127
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001128static void print_version(void)
1129{
1130 printf("ifdtool v%s -- ", IFDTOOL_VERSION);
1131 printf("Copyright (C) 2011 Google Inc.\n\n");
1132 printf
1133 ("This program is free software: you can redistribute it and/or modify\n"
1134 "it under the terms of the GNU General Public License as published by\n"
1135 "the Free Software Foundation, version 2 of the License.\n\n"
1136 "This program is distributed in the hope that it will be useful,\n"
1137 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1138 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
Martin Rotheb20e602016-01-12 13:30:50 -07001139 "GNU General Public License for more details.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001140}
1141
1142static void print_usage(const char *name)
1143{
1144 printf("usage: %s [-vhdix?] <filename>\n", name);
1145 printf("\n"
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001146 " -d | --dump: dump intel firmware descriptor\n"
1147 " -f | --layout <filename> dump regions into a flashrom layout file\n"
1148 " -x | --extract: extract intel fd modules\n"
1149 " -i | --inject <region>:<module> inject file <module> into region <region>\n"
1150 " -n | --newlayout <filename> update regions using a flashrom layout file\n"
1151 " -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
Jan Tatjefa317512016-03-11 00:52:07 +01001152 " -D | --density <512|1|2|4|8|16> set chip density (512 in KByte, others in MByte)\n"
1153 " -C | --chip <0|1|2> select spi chip on which to operate\n"
1154 " can only be used once per run:\n"
1155 " 0 - both chips (default), 1 - first chip, 2 - second chip\n"
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001156 " -e | --em100 set SPI frequency to 20MHz and disable\n"
1157 " Dual Output Fast Read Support\n"
1158 " -l | --lock Lock firmware descriptor and ME region\n"
1159 " -u | --unlock Unlock firmware descriptor and ME region\n"
Andrey Petrov96ecb772016-10-31 19:31:54 -07001160 " -p | --platform Add platform-specific quirks\n"
1161 " aplk - Apollo Lake\n"
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001162 " -v | --version: print the version\n"
1163 " -h | --help: print this help\n\n"
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001164 "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
1165 "\n");
1166}
1167
1168int main(int argc, char *argv[])
1169{
1170 int opt, option_index = 0;
1171 int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001172 int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001173 int mode_layout = 0, mode_newlayout = 0, mode_density = 0;
Chris Douglass03ce0142014-02-26 13:30:13 -05001174 char *region_type_string = NULL, *region_fname = NULL, *layout_fname = NULL;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001175 int region_type = -1, inputfreq = 0;
Jan Tatjefa317512016-03-11 00:52:07 +01001176 unsigned int new_density = 0;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001177 enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
1178
1179 static struct option long_options[] = {
1180 {"dump", 0, NULL, 'd'},
Chris Douglass03ce0142014-02-26 13:30:13 -05001181 {"layout", 1, NULL, 'f'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001182 {"extract", 0, NULL, 'x'},
1183 {"inject", 1, NULL, 'i'},
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001184 {"newlayout", 1, NULL, 'n'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001185 {"spifreq", 1, NULL, 's'},
Jan Tatjefa317512016-03-11 00:52:07 +01001186 {"density", 1, NULL, 'D'},
1187 {"chip", 1, NULL, 'C'},
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001188 {"em100", 0, NULL, 'e'},
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001189 {"lock", 0, NULL, 'l'},
1190 {"unlock", 0, NULL, 'u'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001191 {"version", 0, NULL, 'v'},
1192 {"help", 0, NULL, 'h'},
Andrey Petrov96ecb772016-10-31 19:31:54 -07001193 {"platform", 0, NULL, 'p'},
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001194 {0, 0, 0, 0}
1195 };
1196
Andrey Petrov96ecb772016-10-31 19:31:54 -07001197 while ((opt = getopt_long(argc, argv, "df:D:C:xi:n:s:p:eluvh?",
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001198 long_options, &option_index)) != EOF) {
1199 switch (opt) {
1200 case 'd':
1201 mode_dump = 1;
1202 break;
Chris Douglass03ce0142014-02-26 13:30:13 -05001203 case 'f':
1204 mode_layout = 1;
1205 layout_fname = strdup(optarg);
1206 if (!layout_fname) {
1207 fprintf(stderr, "No layout file specified\n");
1208 print_usage(argv[0]);
1209 exit(EXIT_FAILURE);
1210 }
1211 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001212 case 'x':
1213 mode_extract = 1;
1214 break;
1215 case 'i':
1216 // separate type and file name
1217 region_type_string = strdup(optarg);
1218 region_fname = strchr(region_type_string, ':');
1219 if (!region_fname) {
1220 print_usage(argv[0]);
1221 exit(EXIT_FAILURE);
1222 }
1223 region_fname[0] = '\0';
1224 region_fname++;
1225 // Descriptor, BIOS, ME, GbE, Platform
1226 // valid type?
1227 if (!strcasecmp("Descriptor", region_type_string))
1228 region_type = 0;
1229 else if (!strcasecmp("BIOS", region_type_string))
1230 region_type = 1;
1231 else if (!strcasecmp("ME", region_type_string))
1232 region_type = 2;
1233 else if (!strcasecmp("GbE", region_type_string))
1234 region_type = 3;
1235 else if (!strcasecmp("Platform", region_type_string))
1236 region_type = 4;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001237 else if (!strcasecmp("EC", region_type_string))
1238 region_type = 8;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001239 if (region_type == -1) {
1240 fprintf(stderr, "No such region type: '%s'\n\n",
1241 region_type_string);
1242 print_usage(argv[0]);
1243 exit(EXIT_FAILURE);
1244 }
1245 mode_inject = 1;
1246 break;
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001247 case 'n':
1248 mode_newlayout = 1;
1249 layout_fname = strdup(optarg);
1250 if (!layout_fname) {
1251 fprintf(stderr, "No layout file specified\n");
1252 print_usage(argv[0]);
1253 exit(EXIT_FAILURE);
1254 }
1255 break;
Jan Tatjefa317512016-03-11 00:52:07 +01001256 case 'D':
1257 mode_density = 1;
1258 new_density = strtoul(optarg, NULL, 0);
1259 switch (new_density) {
1260 case 512:
1261 new_density = COMPONENT_DENSITY_512KB;
1262 break;
1263 case 1:
1264 new_density = COMPONENT_DENSITY_1MB;
1265 break;
1266 case 2:
1267 new_density = COMPONENT_DENSITY_2MB;
1268 break;
1269 case 4:
1270 new_density = COMPONENT_DENSITY_4MB;
1271 break;
1272 case 8:
1273 new_density = COMPONENT_DENSITY_8MB;
1274 break;
1275 case 16:
1276 new_density = COMPONENT_DENSITY_16MB;
1277 break;
1278 case 32:
1279 new_density = COMPONENT_DENSITY_32MB;
1280 break;
1281 case 64:
1282 new_density = COMPONENT_DENSITY_64MB;
1283 break;
1284 case 0:
1285 new_density = COMPONENT_DENSITY_UNUSED;
1286 break;
1287 default:
1288 printf("error: Unknown density\n");
1289 print_usage(argv[0]);
1290 exit(EXIT_FAILURE);
1291 }
1292 break;
1293 case 'C':
1294 selected_chip = strtol(optarg, NULL, 0);
1295 if (selected_chip > 2) {
1296 fprintf(stderr, "error: Invalid chip selection\n");
1297 print_usage(argv[0]);
1298 exit(EXIT_FAILURE);
1299 }
1300 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001301 case 's':
1302 // Parse the requested SPI frequency
1303 inputfreq = strtol(optarg, NULL, 0);
1304 switch (inputfreq) {
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001305 case 17:
1306 spifreq = SPI_FREQUENCY_17MHZ;
1307 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001308 case 20:
1309 spifreq = SPI_FREQUENCY_20MHZ;
1310 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001311 case 30:
1312 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
1313 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001314 case 33:
1315 spifreq = SPI_FREQUENCY_33MHZ;
1316 break;
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001317 case 48:
1318 spifreq = SPI_FREQUENCY_48MHZ;
1319 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001320 case 50:
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001321 spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001322 break;
1323 default:
1324 fprintf(stderr, "Invalid SPI Frequency: %d\n",
1325 inputfreq);
1326 print_usage(argv[0]);
1327 exit(EXIT_FAILURE);
1328 }
1329 mode_spifreq = 1;
1330 break;
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001331 case 'e':
1332 mode_em100 = 1;
1333 break;
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001334 case 'l':
1335 mode_locked = 1;
1336 if (mode_unlocked == 1) {
1337 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1338 exit(EXIT_FAILURE);
1339 }
1340 break;
1341 case 'u':
1342 mode_unlocked = 1;
1343 if (mode_locked == 1) {
1344 fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
1345 exit(EXIT_FAILURE);
1346 }
1347 break;
Andrey Petrov96ecb772016-10-31 19:31:54 -07001348 case 'p':
1349 if (!strcmp(optarg, "aplk")) {
1350 platform = PLATFORM_APOLLOLAKE;
1351 } else {
1352 fprintf(stderr, "Unknown platform: %s\n", optarg);
1353 exit(EXIT_FAILURE);
1354 }
1355 break;
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001356 case 'v':
1357 print_version();
1358 exit(EXIT_SUCCESS);
1359 break;
1360 case 'h':
1361 case '?':
1362 default:
1363 print_usage(argv[0]);
1364 exit(EXIT_SUCCESS);
1365 break;
1366 }
1367 }
1368
Chris Douglass03ce0142014-02-26 13:30:13 -05001369 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001370 mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001371 mode_locked)) > 1) {
1372 fprintf(stderr, "You may not specify more than one mode.\n\n");
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001373 print_usage(argv[0]);
1374 exit(EXIT_FAILURE);
1375 }
1376
Chris Douglass03ce0142014-02-26 13:30:13 -05001377 if ((mode_dump + mode_layout + mode_extract + mode_inject +
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001378 mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
Jan Tatjefa317512016-03-11 00:52:07 +01001379 mode_unlocked + mode_density) == 0) {
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001380 fprintf(stderr, "You need to specify a mode.\n\n");
1381 print_usage(argv[0]);
1382 exit(EXIT_FAILURE);
1383 }
1384
1385 if (optind + 1 != argc) {
1386 fprintf(stderr, "You need to specify a file.\n\n");
1387 print_usage(argv[0]);
1388 exit(EXIT_FAILURE);
1389 }
1390
1391 char *filename = argv[optind];
Scott Duplichanf2c98372014-12-12 21:03:06 -06001392 int bios_fd = open(filename, O_RDONLY | O_BINARY);
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001393 if (bios_fd == -1) {
1394 perror("Could not open file");
1395 exit(EXIT_FAILURE);
1396 }
1397 struct stat buf;
1398 if (fstat(bios_fd, &buf) == -1) {
1399 perror("Could not stat file");
1400 exit(EXIT_FAILURE);
1401 }
1402 int size = buf.st_size;
1403
1404 printf("File %s is %d bytes\n", filename, size);
1405
1406 char *image = malloc(size);
1407 if (!image) {
1408 printf("Out of memory.\n");
1409 exit(EXIT_FAILURE);
1410 }
1411
1412 if (read(bios_fd, image, size) != size) {
1413 perror("Could not read file");
1414 exit(EXIT_FAILURE);
1415 }
1416
1417 close(bios_fd);
1418
Duncan Laurie1f7fd722015-06-22 11:14:48 -07001419 check_ifd_version(image, size);
1420
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001421 if (mode_dump)
1422 dump_fd(image, size);
1423
Chris Douglass03ce0142014-02-26 13:30:13 -05001424 if (mode_layout)
1425 dump_layout(image, size, layout_fname);
1426
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001427 if (mode_extract)
1428 write_regions(image, size);
1429
1430 if (mode_inject)
1431 inject_region(filename, image, size, region_type,
1432 region_fname);
1433
Chris Douglass4eabe1e2014-02-27 09:25:19 -05001434 if (mode_newlayout)
1435 new_layout(filename, image, size, layout_fname);
1436
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001437 if (mode_spifreq)
1438 set_spi_frequency(filename, image, size, spifreq);
1439
Jan Tatjefa317512016-03-11 00:52:07 +01001440 if (mode_density)
1441 set_chipdensity(filename, image, size, new_density);
1442
Stefan Reinauer1b1309f2012-05-11 15:53:43 -07001443 if (mode_em100)
1444 set_em100_mode(filename, image, size);
1445
Alexander Couzensd12ea112016-09-10 13:33:05 +02001446 if (mode_locked)
Stefan Reinauer3c53d332012-09-26 17:33:39 -07001447 lock_descriptor(filename, image, size);
1448
1449 if (mode_unlocked)
1450 unlock_descriptor(filename, image, size);
1451
Stefan Reinauer1c795ad12011-10-14 12:49:41 -07001452 free(image);
1453
1454 return 0;
1455}