xref: /aosp_15_r20/external/flashrom/util/ich_descriptors_tool/ich_descriptors_tool.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
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