1 /*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2005-2008 coresystems GmbH
5 * (Written by Stefan Reinauer <[email protected]> for coresystems GmbH)
6 * Copyright (C) 2011-2013 Stefan Tauner
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
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 #include <ctype.h>
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <limits.h>
24 #include "flash.h"
25 #include "programmer.h"
26 #include "layout.h"
27
28 struct flashrom_layout {
29 struct romentry *head;
30 };
31
32 struct layout_include_args {
33 char *name;
34 char *file;
35 struct layout_include_args *next;
36 };
37
get_default_layout(const struct flashrom_flashctx * const flashctx)38 const struct flashrom_layout *get_default_layout(const struct flashrom_flashctx *const flashctx)
39 {
40 return flashctx->default_layout;
41 }
42
get_layout(const struct flashrom_flashctx * const flashctx)43 const struct flashrom_layout *get_layout(const struct flashrom_flashctx *const flashctx)
44 {
45 if (flashctx->layout)
46 return flashctx->layout;
47 else
48 return get_default_layout(flashctx);
49 }
50
mutable_layout_next(const struct flashrom_layout * const layout,struct romentry * iterator)51 static struct romentry *mutable_layout_next(
52 const struct flashrom_layout *const layout, struct romentry *iterator)
53 {
54 return iterator ? iterator->next : layout->head;
55 }
56
_layout_entry_by_name(const struct flashrom_layout * const layout,const char * name)57 static struct romentry *_layout_entry_by_name(
58 const struct flashrom_layout *const layout, const char *name)
59 {
60 struct romentry *entry = NULL;
61 if (!layout || !name)
62 return NULL;
63 while ((entry = mutable_layout_next(layout, entry))) {
64 if (!strcmp(entry->region.name, name))
65 return entry;
66 }
67 return NULL;
68 }
69
70 #ifndef __LIBPAYLOAD__
layout_from_file(struct flashrom_layout ** layout,const char * name)71 int layout_from_file(struct flashrom_layout **layout, const char *name)
72 {
73 FILE *romlayout;
74 char tempstr[256], tempname[256];
75 int ret = 1;
76
77 if (flashrom_layout_new(layout))
78 return 1;
79
80 romlayout = fopen(name, "r");
81
82 if (!romlayout) {
83 msg_gerr("ERROR: Could not open layout file (%s).\n",
84 name);
85 return -1;
86 }
87
88 while (!feof(romlayout)) {
89 char *tstr1, *tstr2;
90
91 if (2 != fscanf(romlayout, "%255s %255s\n", tempstr, tempname))
92 continue;
93 #if 0
94 // fscanf does not like arbitrary comments like that :( later
95 if (tempstr[0] == '#') {
96 continue;
97 }
98 #endif
99 tstr1 = strtok(tempstr, ":");
100 tstr2 = strtok(NULL, ":");
101 if (!tstr1 || !tstr2) {
102 msg_gerr("Error parsing layout file. Offending string: \"%s\"\n", tempstr);
103 goto _close_ret;
104 }
105 if (flashrom_layout_add_region(*layout,
106 strtol(tstr1, NULL, 16), strtol(tstr2, NULL, 16), tempname))
107 goto _close_ret;
108 }
109 ret = 0;
110
111 _close_ret:
112 (void)fclose(romlayout);
113 return ret;
114 }
115 #endif
116
parse_include_args(const char * arg,char ** name,char ** file)117 static bool parse_include_args(const char *arg, char **name, char **file)
118 {
119 char *colon;
120 char *tmp_name;
121 char *tmp_file = NULL; /* file is optional, so defaults to NULL */
122
123 if (arg == NULL) {
124 msg_gerr("<NULL> is a bad region name.\n");
125 return false;
126 }
127
128 /* -i <image>[:<file>] */
129 colon = strchr(arg, ':');
130 if (colon && !colon[1]) {
131 msg_gerr("Missing filename parameter in %s\n", arg);
132 return false;
133 }
134
135 if (colon) {
136 tmp_name = strndup(arg, colon - arg);
137 if (!tmp_name) {
138 msg_gerr("Out of memory\n");
139 goto error;
140 }
141
142 tmp_file = strdup(colon + 1);
143 if (!tmp_file) {
144 msg_gerr("Out of memory\n");
145 goto error;
146 }
147 } else {
148 tmp_name = strdup(arg);
149 }
150
151 *name = tmp_name;
152 *file = tmp_file;
153
154 return true;
155
156 error:
157 free(tmp_name);
158 free(tmp_file);
159 return false;
160 }
161
162 /* register an include argument (-i) for later processing */
register_include_arg(struct layout_include_args ** args,const char * arg)163 int register_include_arg(struct layout_include_args **args, const char *arg)
164 {
165 struct layout_include_args *tmp;
166 char *name;
167 char *file;
168
169 if (!parse_include_args(arg, &name, &file))
170 return 1;
171
172 for (tmp = *args; tmp; tmp = tmp->next) {
173 if (!strcmp(tmp->name, name)) {
174 msg_gerr("Duplicate region name: \"%s\".\n", name);
175 goto error;
176 }
177 }
178
179 tmp = malloc(sizeof(*tmp));
180 if (tmp == NULL) {
181 msg_gerr("Out of memory\n");
182 goto error;
183 }
184
185 tmp->name = name;
186 tmp->file = file;
187 tmp->next = *args;
188 *args = tmp;
189 return 0;
190
191 error:
192 free(name);
193 free(file);
194 return 1;
195 }
196
sanitise_filename(char * filename)197 static char *sanitise_filename(char *filename)
198 {
199 for (unsigned i = 0; filename[i]; i++) {
200 if (isspace((unsigned char)filename[i]))
201 filename[i] = '_';
202 }
203 return filename;
204 }
205
206 /* returns 0 to indicate success, 1 to indicate failure */
include_region(struct flashrom_layout * const l,const char * name,const char * file)207 static int include_region(struct flashrom_layout *const l, const char *name,
208 const char *file)
209 {
210 struct romentry *const entry = _layout_entry_by_name(l, name);
211 if (entry) {
212 entry->included = true;
213 if (file)
214 entry->file = sanitise_filename(strdup(file));
215 return 0;
216 }
217 return 1;
218 }
219
220 /* returns 0 to indicate success, 1 to indicate failure */
exclude_region(struct flashrom_layout * const l,const char * name)221 static int exclude_region(struct flashrom_layout *const l, const char *name)
222 {
223 struct romentry *const entry = _layout_entry_by_name(l, name);
224 if (entry) {
225 entry->included = false;
226 return 0;
227 }
228 return 1;
229 }
230
231 /* returns -1 if an entry is not found, 0 if found. */
romentry_exists(struct flashrom_layout * const l,char * name,char * file)232 static int romentry_exists(struct flashrom_layout *const l, char *name, char *file)
233 {
234 if (!l->head)
235 return -1;
236
237 msg_gspew("Looking for region \"%s\"... ", name);
238 if (include_region(l, name, file)) {
239 msg_gspew("not found.\n");
240 return -1;
241 }
242 msg_gspew("found.\n");
243 return 0;
244 }
245
246 /* process -i arguments
247 * returns 0 to indicate success, >0 to indicate failure
248 */
process_include_args(struct flashrom_layout * l,const struct layout_include_args * const args)249 int process_include_args(struct flashrom_layout *l, const struct layout_include_args *const args)
250 {
251 unsigned int found = 0;
252 const struct layout_include_args *tmp;
253
254 if (args == NULL)
255 return 0;
256
257 /* User has specified an include argument, but no layout is loaded. */
258 if (!l || !l->head) {
259 msg_gerr("Region requested (with -i \"%s\"), "
260 "but no layout data is available.\n",
261 args->name);
262 return 1;
263 }
264
265 tmp = args;
266 while (tmp) {
267 if (romentry_exists(l, tmp->name, tmp->file) < 0) {
268 msg_gerr("Invalid region specified: \"%s\".\n",
269 tmp->name);
270 return 1;
271 }
272 tmp = tmp->next;
273 found++;
274 }
275
276 msg_ginfo("Using region%s: ", found > 1 ? "s" : "");
277 tmp = args;
278 while (tmp) {
279 msg_ginfo("\"%s\"", tmp->name);
280 if (tmp->file)
281 msg_ginfo(":\"%s\"", tmp->file);
282 if (found > 1)
283 msg_ginfo(", ");
284 found--;
285 tmp = tmp->next;
286 }
287 msg_ginfo(".\n");
288 return 0;
289 }
290
check_include_args_filename(const struct layout_include_args * include_args)291 int check_include_args_filename(const struct layout_include_args *include_args)
292 {
293 const struct layout_include_args *arg;
294 for (arg = include_args; arg; arg = arg->next) {
295 if (!arg->file || (arg->file[0] == '\0')) {
296 fprintf(stderr, "Error: No region file specified.\n");
297 return 1;
298 }
299 }
300
301 return 0;
302 }
303
304 /* returns boolean 1 if any regions overlap, 0 otherwise */
included_regions_overlap(const struct flashrom_layout * const l)305 int included_regions_overlap(const struct flashrom_layout *const l)
306 {
307 const struct romentry *lhs = NULL;
308 int overlap_detected = 0;
309
310 while ((lhs = layout_next(l, lhs))) {
311 if (!lhs->included)
312 continue;
313
314 const struct romentry *rhs = lhs;
315 while ((rhs = layout_next(l, rhs))) {
316 if (!rhs->included)
317 continue;
318
319 const struct flash_region *rhsr = &rhs->region;
320 const struct flash_region *lhsr = &lhs->region;
321
322 if (lhsr->start > rhsr->end)
323 continue;
324
325 if (lhsr->end < rhsr->start)
326 continue;
327
328 msg_gwarn("Regions %s [0x%08"PRIx32"-0x%08"PRIx32"] and %s [0x%08"PRIx32"-0x%08"PRIx32"] overlap\n",
329 lhsr->name, lhsr->start, lhsr->end, rhsr->name, rhsr->start, rhsr->end);
330 overlap_detected = 1;
331 }
332 }
333 return overlap_detected;
334 }
335
cleanup_include_args(struct layout_include_args ** args)336 void cleanup_include_args(struct layout_include_args **args)
337 {
338 struct layout_include_args *tmp;
339
340 while (*args) {
341 tmp = (*args)->next;
342 free((*args)->name);
343 free((*args)->file);
344 free(*args);
345 *args = tmp;
346 }
347 }
348
layout_sanity_checks(const struct flashrom_flashctx * const flash)349 int layout_sanity_checks(const struct flashrom_flashctx *const flash)
350 {
351 const struct flashrom_layout *const layout = get_layout(flash);
352 const chipsize_t total_size = flash->chip->total_size * 1024;
353 int ret = 0;
354
355 const struct romentry *entry = NULL;
356 while ((entry = layout_next(layout, entry))) {
357 const struct flash_region *region = &entry->region;
358 if (region->start >= total_size || region->end >= total_size) {
359 msg_gwarn("Warning: Address range of region \"%s\" "
360 "exceeds the current chip's address space.\n", region->name);
361 if (entry->included)
362 ret = 1;
363 }
364 if (region->start > region->end) {
365 msg_gerr("Error: Size of the address range of region \"%s\" is not positive.\n",
366 region->name);
367 ret = 1;
368 }
369 }
370
371 return ret;
372 }
373
prepare_layout_for_extraction(struct flashctx * flash)374 void prepare_layout_for_extraction(struct flashctx *flash)
375 {
376 const struct flashrom_layout *const l = get_layout(flash);
377 struct romentry *entry = NULL;
378
379 while ((entry = mutable_layout_next(l, entry))) {
380 entry->included = true;
381
382 if (!entry->file)
383 entry->file = sanitise_filename(strdup(entry->region.name));
384 }
385 }
386
layout_next_included_region(const struct flashrom_layout * const l,const chipoff_t where)387 const struct romentry *layout_next_included_region(
388 const struct flashrom_layout *const l, const chipoff_t where)
389 {
390 const struct romentry *entry = NULL, *lowest = NULL;
391
392 while ((entry = layout_next(l, entry))) {
393 if (!entry->included)
394 continue;
395 if (entry->region.end < where)
396 continue;
397 if (!lowest || lowest->region.start > entry->region.start)
398 lowest = entry;
399 }
400
401 return lowest;
402 }
403
layout_next_included(const struct flashrom_layout * const layout,const struct romentry * iterator)404 const struct romentry *layout_next_included(
405 const struct flashrom_layout *const layout, const struct romentry *iterator)
406 {
407 while ((iterator = layout_next(layout, iterator))) {
408 if (iterator->included)
409 break;
410 }
411 return iterator;
412 }
413
layout_next(const struct flashrom_layout * const layout,const struct romentry * iterator)414 const struct romentry *layout_next(
415 const struct flashrom_layout *const layout, const struct romentry *iterator)
416 {
417 return iterator ? iterator->next : layout->head;
418 }
419
flashrom_layout_new(struct flashrom_layout ** const layout)420 int flashrom_layout_new(struct flashrom_layout **const layout)
421 {
422 *layout = calloc(1, sizeof(**layout));
423 if (!*layout) {
424 msg_gerr("Error creating layout: %s\n", strerror(errno));
425 return 1;
426 }
427
428 return 0;
429 }
430
flashrom_layout_add_region(struct flashrom_layout * const layout,const size_t start,const size_t end,const char * const name)431 int flashrom_layout_add_region(
432 struct flashrom_layout *const layout,
433 const size_t start, const size_t end, const char *const name)
434 {
435 struct romentry *const entry = malloc(sizeof(*entry));
436 if (!entry)
437 goto _err_ret;
438
439 const struct romentry tmp = {
440 .next = layout->head,
441 .included = false,
442 .file = NULL,
443 .region = {
444 .start = start,
445 .end = end,
446 .name = strdup(name),
447 },
448 };
449 *entry = tmp;
450 if (!entry->region.name)
451 goto _err_ret;
452
453 msg_gdbg("Added layout entry %08zx - %08zx named %s\n", start, end, name);
454 layout->head = entry;
455 return 0;
456
457 _err_ret:
458 msg_gerr("Error adding layout entry: %s\n", strerror(errno));
459 free(entry);
460 return 1;
461 }
462
flashrom_layout_include_region(struct flashrom_layout * const layout,const char * name)463 int flashrom_layout_include_region(struct flashrom_layout *const layout, const char *name)
464 {
465 return include_region(layout, name, NULL);
466 }
467
flashrom_layout_exclude_region(struct flashrom_layout * const layout,const char * name)468 int flashrom_layout_exclude_region(struct flashrom_layout *const layout, const char *name)
469 {
470 return exclude_region(layout, name);
471 }
472
flashrom_layout_get_region_range(struct flashrom_layout * const l,const char * name,unsigned int * start,unsigned int * len)473 int flashrom_layout_get_region_range(struct flashrom_layout *const l, const char *name,
474 unsigned int *start, unsigned int *len)
475 {
476 const struct romentry *const entry = _layout_entry_by_name(l, name);
477 if (entry) {
478 const struct flash_region *region = &entry->region;
479 *start = region->start;
480 *len = region->end - region->start + 1;
481 return 0;
482 }
483 return 1;
484 }
485
flashrom_layout_release(struct flashrom_layout * const layout)486 void flashrom_layout_release(struct flashrom_layout *const layout)
487 {
488 if (!layout)
489 return;
490
491 while (layout->head) {
492 struct romentry *const entry = layout->head;
493 layout->head = entry->next;
494 free(entry->file);
495 free(entry->region.name);
496 free(entry);
497 }
498 free(layout);
499 }
500