blob: a1bce1b22eba8b4f4efac1e3c970b04c491924b3 [file] [log] [blame]
Stefan Taunerb3850962011-12-24 00:00:32 +00001/*
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 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22/*
23 * dump information and binaries from BIOS images that are in descriptor mode
24 */
25#include <stdio.h>
26#include <stdint.h>
27#include <stdlib.h>
28#include <sys/mman.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <fcntl.h>
32#include <unistd.h>
33#include <string.h>
34#include <errno.h>
35#include "ich_descriptors.h"
36
37static void dump_file(const char *basename, const uint32_t *dump, unsigned int len, struct ich_desc_region *reg, unsigned int i)
38{
39 int ret;
40 char *fn;
41 const char *reg_name;
42 uint32_t file_len;
43 const char *const region_names[5] = {
44 "Descriptor", "BIOS", "ME", "GbE", "Platform"
45 };
46 uint32_t base = ICH_FREG_BASE(reg->FLREGs[i]);
47 uint32_t limit = ICH_FREG_LIMIT(reg->FLREGs[i]);
48
49 reg_name = region_names[i];
50 if (base > limit) {
51 printf("The %s region is unused and thus not dumped.\n",
52 reg_name);
53 return;
54 }
55
56 limit = limit | 0x0fff;
57 file_len = limit + 1 - base;
58 if (base + file_len > len) {
59 printf("The %s region is spanning 0x%08x-0x%08x, but it is "
60 "not (fully) included in the image (0-0x%08x), thus not "
61 "dumped.\n", reg_name, base, limit, len - 1);
62 return;
63 }
64
65 fn = malloc(strlen(basename) + strlen(reg_name) + strlen(".bin") + 2);
66 if (!fn) {
67 fprintf(stderr, "Out of memory!\n");
68 exit(1);
69 }
70 snprintf(fn, strlen(basename) + strlen(reg_name) + strlen(".bin") + 2,
71 "%s.%s.bin", basename, reg_name);
72 printf("Dumping %u bytes of the %s region from 0x%08x-0x%08x to %s... ",
73 file_len, region_names[i], base, limit, fn);
74 int fh = open(fn, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
75 free(fn);
76 if (fh < 0) {
77 fprintf(stderr,
78 "ERROR: couldn't open(%s): %s\n", fn, strerror(errno));
79 exit(1);
80 }
81
82 ret = write(fh, &dump[base >> 2], file_len);
83 if (ret != file_len) {
84 fprintf(stderr, "FAILED.\n");
85 exit(1);
86 }
87
88 printf("done.\n");
89 close(fh);
90}
91
92void dump_files(const char *n, const uint32_t *buf, unsigned int len, struct ich_desc_region *reg)
93{
94 unsigned int i;
95 printf("=== Dumping region files ===\n");
96 for (i = 0; i < 5; i++)
97 dump_file(n, buf, len, reg, i);
98 printf("\n");
99}
100
101static void usage(char *argv[], char *error)
102{
103 if (error != NULL) {
104 fprintf(stderr, "%s\n", error);
105 }
106 printf("usage: '%s -f <image file name> [-c <chipset name>] [-d]'\n\n"
107"where <image file name> points to an image of the contents of the SPI flash.\n"
108"In case the image is really in descriptor mode %s\n"
109"will pretty print some of the contained information.\n"
110"To also print the data stored in the descriptor strap you have to indicate\n"
111"the chipset series with the '-c' parameter and one of the possible arguments:\n"
112"\t- \"ich8\",\n"
113"\t- \"ich9\",\n"
114"\t- \"ich10\",\n"
115"\t- \"5\" or \"ibex\" for Intel's 5 series chipsets,\n"
116"\t- \"6\" or \"cougar\" for Intel's 6 series chipsets,\n"
117"\t- \"7\" or \"panther\" for Intel's 7 series chipsets.\n"
118"If '-d' is specified some regions such as the BIOS image as seen by the CPU or\n"
119"the GbE blob that is required to initialize the GbE are also dumped to files.\n",
120 argv[0], argv[0]);
121 exit(1);
122}
123
124int main(int argc, char *argv[])
125{
126 int fd; /* file descriptor to flash file */
127 int len; /* file/buffer size in bytes */
128 uint32_t *buf; /* mmap'd file */
129 uint8_t *pMAC;
130 int opt, ret;
131
132 int dump = 0;
133 const char *fn = NULL;
134 const char *csn = NULL;
135 enum ich_chipset cs = CHIPSET_ICH_UNKNOWN;
136 struct ich_descriptors desc = {{ 0 }};
137
138 while ((opt = getopt(argc, argv, "df:c:")) != -1) {
139 switch (opt) {
140 case 'd':
141 dump = 1;
142 break;
143 case 'f':
144 fn = optarg;
145 break;
146 case 'c':
147 csn = optarg;
148 break;
149 default: /* '?' */
150 usage(argv, NULL);
151 }
152 }
153 if (fn == NULL)
154 usage(argv,
155 "Need a file name of a descriptor image to read from.");
156
157 fd = open(fn, O_RDONLY);
158 if (fd < 0)
159 usage(argv, "No such file");
160 len = lseek(fd, 0, SEEK_END);
161 if (len < 0)
162 usage(argv, "Seeking to the end of the file failed");
163
164 buf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
165 if (buf == (void *) -1) {
166 /* fallback for stupid OSes like cygwin */
167 int ret;
168 buf = malloc(len);
169 if (!buf)
170 usage(argv, "Could not allocate memory");
171 lseek(fd, 0, SEEK_SET);
172 ret = read(fd, buf, len);
173 if (ret != len)
174 usage(argv, "Seeking to the end of the file failed");
175 }
176 printf("The flash image has a size of %d [0x%x] bytes.\n", len, len);
177 close(fd);
178
179 if (csn != NULL) {
180 if (strcmp(csn, "ich8") == 0)
181 cs = CHIPSET_ICH8;
182 else if (strcmp(csn, "ich9") == 0)
183 cs = CHIPSET_ICH9;
184 else if (strcmp(csn, "ich10") == 0)
185 cs = CHIPSET_ICH10;
186 else if ((strcmp(csn, "5") == 0) ||
187 (strcmp(csn, "ibex") == 0))
188 cs = CHIPSET_5_SERIES_IBEX_PEAK;
189 else if ((strcmp(csn, "6") == 0) ||
190 (strcmp(csn, "cougar") == 0))
191 cs = CHIPSET_6_SERIES_COUGAR_POINT;
192 else if ((strcmp(csn, "7") == 0) ||
193 (strcmp(csn, "panther") == 0))
194 cs = CHIPSET_7_SERIES_PANTHER_POINT;
195 }
196
197 ret = read_ich_descriptors_from_dump(buf, len, &desc);
198 switch (ret) {
199 case ICH_RET_OK:
200 break;
201 case ICH_RET_ERR:
202 printf("Image not in descriptor mode.\n");
203 exit(1);
204 case ICH_RET_OOB:
205 printf("Tried to access a location out of bounds of the image. "
206 "- Corrupt image?\n");
207 exit(1);
208 default:
209 printf("Unhandled return value at %s:%u, please report this.\n",
210 __FILE__, __LINE__);
211 exit(1);
212 }
213
214 prettyprint_ich_descriptors(cs, &desc);
215
216 pMAC = (uint8_t *) &buf[ICH_FREG_BASE(desc.region.reg3_base) >> 2];
217 if (len >= ICH_FREG_BASE(desc.region.reg3_base) + 5 && pMAC[0] != 0xff)
218 printf("The MAC address might be at offset 0x%x: "
219 "%02x:%02x:%02x:%02x:%02x:%02x\n",
220 ICH_FREG_BASE(desc.region.reg3_base),
221 pMAC[0], pMAC[1], pMAC[2], pMAC[3], pMAC[4], pMAC[5]);
222
223 if (dump == 1)
224 dump_files(fn, buf, len, &desc.region);
225
226 return 0;
227}