1 /*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2010 Matthias Wenzel <bios at mazzoo dot de>
5 * Copyright (C) 2011 Stefan Tauner
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18 /*
19 * dump information and binaries from BIOS images that are in descriptor mode
20 */
21 #include <stdio.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <errno.h>
30 #include "ich_descriptors.h"
31 /* Some DJGPP builds define __unix__ although they don't support mmap().
32 * Cygwin defines __unix__ and supports mmap(), but it does not work well.
33 */
34 #if !defined(__MSDOS__) && !IS_WINDOWS && (defined(unix) || defined(__unix__) || defined(__unix)) || (defined(__MACH__) && defined(__APPLE__))
35 #define HAVE_MMAP 1
36 #include <sys/mman.h>
37 #endif
38
39 static const char *const region_names[] = {
40 "Descriptor", "BIOS", "ME", "GbE", "Platform",
41 "DevExp", "BIOS2", "Region7", "EC/BMC", "DevExp2",
42 "IE", "10GbE0", "10GbE1", "Region13", "Region14",
43 "PTT"
44 };
45
dump_file(const char * prefix,const uint32_t * dump,unsigned int len,const struct ich_desc_region * const reg,unsigned int i)46 static void dump_file(const char *prefix, const uint32_t *dump, unsigned int len,
47 const struct ich_desc_region *const reg, unsigned int i)
48 {
49 char *fn;
50 const char *reg_name;
51 uint32_t file_len;
52 uint32_t base = ICH_FREG_BASE(reg->FLREGs[i]);
53 uint32_t limit = ICH_FREG_LIMIT(reg->FLREGs[i]);
54
55 reg_name = region_names[i];
56 if (base > limit) {
57 printf("The %s region is unused and thus not dumped.\n", reg_name);
58 return;
59 }
60
61 file_len = limit + 1 - base;
62 if (base + file_len > len) {
63 printf("The %s region is spanning 0x%08x-0x%08x, but it is "
64 "not (fully) included in the image (0-0x%08x), thus not "
65 "dumped.\n", reg_name, base, limit, len - 1);
66 return;
67 }
68
69 fn = malloc(strlen(prefix) + strlen(reg_name) + strlen(".bin") + 2);
70 if (!fn) {
71 fprintf(stderr, "Out of memory!\n");
72 exit(1);
73 }
74 snprintf(fn, strlen(prefix) + strlen(reg_name) + strlen(".bin") + 2,
75 "%s.%s.bin", prefix, reg_name);
76 printf("Dumping %u bytes of the %s region from 0x%08x-0x%08x to %s... ",
77 file_len, region_names[i], base, limit, fn);
78 int fh = open(fn, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
79 if (fh < 0) {
80 fprintf(stderr,
81 "ERROR: couldn't open(%s): %s\n", fn, strerror(errno));
82 free(fn);
83 exit(1);
84 }
85 free(fn);
86
87 const ssize_t ret = write(fh, &dump[base >> 2], file_len);
88 if (ret < 0 || ((size_t) ret) != file_len) {
89 fprintf(stderr, "FAILED.\n");
90 exit(1);
91 }
92
93 printf("done.\n");
94 close(fh);
95 }
96
min(int a,int b)97 int min(int a, int b)
98 {
99 return (a < b) ? a : b;
100 }
101
dump_files(const char * name,const uint32_t * buf,unsigned int len,const enum ich_chipset cs,const struct ich_descriptors * const desc)102 static void dump_files(const char *name, const uint32_t *buf, unsigned int len,
103 const enum ich_chipset cs, const struct ich_descriptors *const desc)
104 {
105 ssize_t i;
106 const ssize_t nr = min(ich_number_of_regions(cs, &desc->content), ARRAY_SIZE(region_names));
107 printf("=== Dumping region files ===\n");
108 for (i = 0; i < nr; i++)
109 dump_file(name, buf, len, &desc->region, i);
110 printf("\n");
111 }
112
usage(char * argv[],const char * error)113 static void usage(char *argv[], const char *error)
114 {
115 if (error != NULL) {
116 fprintf(stderr, "%s\n", error);
117 }
118 printf("usage: '%s -f <image file name> [-c <chipset name>] [-d]'\n\n"
119 "where <image file name> points to an image of the contents of the SPI flash.\n"
120 "In case the image is really in descriptor mode %s\n"
121 "will pretty print some of the contained information.\n"
122 "To also print the data stored in the descriptor straps you have to indicate\n"
123 "the chipset series with the '-c' parameter and one of the possible arguments:\n"
124 "\t- \"ich8\",\n"
125 "\t- \"ich9\",\n"
126 "\t- \"ich10\",\n"
127 "\t- \"silvermont\" for chipsets from Intel's Silvermont architecture (e.g. Bay Trail),\n"
128 "\t- \"apollo\" for Intel's Apollo Lake SoC.\n"
129 "\t- \"gemini\" for Intel's Gemini Lake SoC.\n"
130 "\t- \"jasper\" for Intel's Jasper Lake SoC.\n"
131 "\t- \"meteor\" for Intel's Meteor Lake SoC.\n"
132 "\t- \"panther\" for Intel's Panther Lake SoC.\n"
133 "\t- \"5\" or \"ibex\" for Intel's 5 series chipsets,\n"
134 "\t- \"6\" or \"cougar\" for Intel's 6 series chipsets,\n"
135 "\t- \"7\" or \"panther\" for Intel's 7 series chipsets.\n"
136 "\t- \"8\" or \"lynx\" for Intel's 8 series chipsets.\n"
137 "\t- \"9\" or \"wildcat\" for Intel's 9 series chipsets.\n"
138 "\t- \"100\" or \"sunrise\" for Intel's 100 series chipsets.\n"
139 "\t- \"300\" or \"cannon\" for Intel's 300 series chipsets.\n"
140 "\t- \"400\" or \"comet\" for Intel's 400 series chipsets.\n"
141 "\t- \"500\" or \"tiger\" for Intel's 500 series chipsets.\n"
142 "\t- \"600\" or \"alder\" for Intel's 600 series chipsets.\n"
143 "\t- \"700\" or \"raptor\" for Intel's 700 series chipsets.\n"
144 "If '-d' is specified some regions such as the BIOS image as seen by the CPU or\n"
145 "the GbE blob that is required to initialize the GbE are also dumped to files.\n",
146 argv[0], argv[0]);
147 exit(1);
148 }
149
main(int argc,char * argv[])150 int main(int argc, char *argv[])
151 {
152 int fd; /* file descriptor to flash file */
153 int len; /* file/buffer size in bytes */
154 uint32_t *buf; /* mmap'd file */
155 uint8_t *pMAC;
156 int opt, ret;
157
158 int dump = 0;
159 const char *fn = NULL;
160 const char *csn = NULL;
161 enum ich_chipset cs = CHIPSET_ICH_UNKNOWN;
162 struct ich_descriptors desc = { 0 };
163
164 while ((opt = getopt(argc, argv, "df:c:")) != -1) {
165 switch (opt) {
166 case 'd':
167 dump = 1;
168 break;
169 case 'f':
170 fn = optarg;
171 break;
172 case 'c':
173 csn = optarg;
174 break;
175 default: /* '?' */
176 usage(argv, NULL);
177 }
178 }
179 if (fn == NULL)
180 usage(argv, "Need the file name of a descriptor image to read from.");
181
182 fd = open(fn, O_RDONLY);
183 if (fd < 0)
184 usage(argv, "No such file");
185 len = lseek(fd, 0, SEEK_END);
186 if (len < 0)
187 usage(argv, "Seeking to the end of the file failed");
188
189 #ifdef HAVE_MMAP
190 buf = (uint32_t *)mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
191 if (buf == (void *) -1)
192 #endif
193 {
194 /* fallback for stupid OSes like cygwin */
195 buf = malloc(len);
196 if (!buf)
197 usage(argv, "Could not allocate memory");
198 lseek(fd, 0, SEEK_SET);
199 if (len != read(fd, buf, len))
200 usage(argv, "Reading the descriptor image file failed");
201 }
202 printf("The flash image has a size of %d [0x%x] bytes.\n", len, len);
203 close(fd);
204
205 if (csn != NULL) {
206 if (strcmp(csn, "ich8") == 0)
207 cs = CHIPSET_ICH8;
208 else if (strcmp(csn, "ich9") == 0)
209 cs = CHIPSET_ICH9;
210 else if (strcmp(csn, "ich10") == 0)
211 cs = CHIPSET_ICH10;
212 else if ((strcmp(csn, "5") == 0) ||
213 (strcmp(csn, "ibex") == 0))
214 cs = CHIPSET_5_SERIES_IBEX_PEAK;
215 else if ((strcmp(csn, "6") == 0) ||
216 (strcmp(csn, "cougar") == 0))
217 cs = CHIPSET_6_SERIES_COUGAR_POINT;
218 else if ((strcmp(csn, "7") == 0) ||
219 (strcmp(csn, "panther") == 0))
220 cs = CHIPSET_7_SERIES_PANTHER_POINT;
221 else if ((strcmp(csn, "8") == 0) ||
222 (strcmp(csn, "lynx") == 0))
223 cs = CHIPSET_8_SERIES_LYNX_POINT;
224 else if ((strcmp(csn, "silvermont") == 0))
225 cs = CHIPSET_BAYTRAIL;
226 else if ((strcmp(csn, "9") == 0) ||
227 (strcmp(csn, "wildcat") == 0))
228 cs = CHIPSET_9_SERIES_WILDCAT_POINT;
229 else if ((strcmp(csn, "100") == 0) ||
230 (strcmp(csn, "sunrise") == 0))
231 cs = CHIPSET_100_SERIES_SUNRISE_POINT;
232 else if ((strcmp(csn, "300") == 0) ||
233 (strcmp(csn, "cannon") == 0))
234 cs = CHIPSET_300_SERIES_CANNON_POINT;
235 else if ((strcmp(csn, "400") == 0) ||
236 (strcmp(csn, "comet") == 0))
237 cs = CHIPSET_400_SERIES_COMET_POINT;
238 else if ((strcmp(csn, "500") == 0) ||
239 (strcmp(csn, "tiger") == 0))
240 cs = CHIPSET_500_SERIES_TIGER_POINT;
241 else if ((strcmp(csn, "600") == 0) ||
242 (strcmp(csn, "alder") == 0))
243 cs = CHIPSET_600_SERIES_ALDER_POINT;
244 else if ((strcmp(csn, "700") == 0) ||
245 (strcmp(csn, "raptor") == 0))
246 cs = CHIPSET_700_SERIES_RAPTOR_POINT;
247 else if (strcmp(csn, "apollo") == 0)
248 cs = CHIPSET_APOLLO_LAKE;
249 else if (strcmp(csn, "gemini") == 0)
250 cs = CHIPSET_GEMINI_LAKE;
251 else if (strcmp(csn, "jasper") == 0)
252 cs = CHIPSET_JASPER_LAKE;
253 else if (strcmp(csn, "elkhart") == 0)
254 cs = CHIPSET_ELKHART_LAKE;
255 else if (strcmp(csn, "meteor") == 0)
256 cs = CHIPSET_METEOR_LAKE;
257 else if (strcmp(csn, "panther") == 0)
258 cs = CHIPSET_PANTHER_LAKE;
259 }
260
261 ret = read_ich_descriptors_from_dump(buf, len, &cs, &desc);
262 switch (ret) {
263 case ICH_RET_OK:
264 break;
265 case ICH_RET_ERR:
266 printf("Image not in descriptor mode.\n");
267 exit(1);
268 case ICH_RET_OOB:
269 printf("Tried to access a location out of bounds of the image. - Corrupt image?\n");
270 exit(1);
271 default:
272 printf("Unhandled return value at %s:%u, please report this.\n",
273 __FILE__, __LINE__);
274 exit(1);
275 }
276
277 prettyprint_ich_descriptors(cs, &desc);
278
279 pMAC = (uint8_t *) &buf[ICH_FREG_BASE(desc.region.FLREGs[3]) >> 2];
280 /* The case len < 0 is handled above as error. At this point len is non-negative. */
281 if (((size_t) len) >= ICH_FREG_BASE(desc.region.FLREGs[3]) + 6 && pMAC[0] != 0xff)
282 printf("The MAC address might be at offset 0x%x: "
283 "%02x:%02x:%02x:%02x:%02x:%02x\n",
284 ICH_FREG_BASE(desc.region.FLREGs[3]),
285 pMAC[0], pMAC[1], pMAC[2], pMAC[3], pMAC[4], pMAC[5]);
286
287 if (dump == 1)
288 dump_files(fn, buf, len, cs, &desc);
289
290 return 0;
291 }
292