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