diff options
Diffstat (limited to 'layout.c')
-rw-r--r-- | layout.c | 407 |
1 files changed, 288 insertions, 119 deletions
@@ -15,6 +15,7 @@ * GNU General Public License for more details. */ +#include <ctype.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> @@ -24,35 +25,62 @@ #include "programmer.h" #include "layout.h" -static struct romentry entries[MAX_ROMLAYOUT]; -static struct flashrom_layout global_layout = { entries, 0 }; +struct flashrom_layout { + struct romentry *head; +}; -struct flashrom_layout *get_global_layout(void) +struct layout_include_args { + char *name; + char *file; + struct layout_include_args *next; +}; + +const struct flashrom_layout *get_default_layout(const struct flashrom_flashctx *const flashctx) { - return &global_layout; + return flashctx->default_layout; } const struct flashrom_layout *get_layout(const struct flashrom_flashctx *const flashctx) { - if (flashctx->layout && flashctx->layout->num_entries) + if (flashctx->layout) return flashctx->layout; else - return &flashctx->fallback_layout.base; + return get_default_layout(flashctx); +} + +static struct romentry *mutable_layout_next( + const struct flashrom_layout *const layout, struct romentry *iterator) +{ + return iterator ? iterator->next : layout->head; +} + +static struct romentry *_layout_entry_by_name( + const struct flashrom_layout *const layout, const char *name) +{ + struct romentry *entry = NULL; + if (!layout || !name) + return NULL; + while ((entry = mutable_layout_next(layout, entry))) { + if (!strcmp(entry->region.name, name)) + return entry; + } + return NULL; } #ifndef __LIBPAYLOAD__ -int read_romlayout(const char *name) +int layout_from_file(struct flashrom_layout **layout, const char *name) { - struct flashrom_layout *const layout = get_global_layout(); FILE *romlayout; char tempstr[256], tempname[256]; - unsigned int i; int ret = 1; + if (flashrom_layout_new(layout)) + return 1; + romlayout = fopen(name, "r"); if (!romlayout) { - msg_gerr("ERROR: Could not open ROM layout (%s).\n", + msg_gerr("ERROR: Could not open layout file (%s).\n", name); return -1; } @@ -60,11 +88,6 @@ int read_romlayout(const char *name) while (!feof(romlayout)) { char *tstr1, *tstr2; - if (layout->num_entries >= MAX_ROMLAYOUT) { - msg_gerr("Maximum number of ROM images (%i) in layout " - "file reached.\n", MAX_ROMLAYOUT); - goto _close_ret; - } if (2 != fscanf(romlayout, "%255s %255s\n", tempstr, tempname)) continue; #if 0 @@ -79,23 +102,10 @@ int read_romlayout(const char *name) msg_gerr("Error parsing layout file. Offending string: \"%s\"\n", tempstr); goto _close_ret; } - layout->entries[layout->num_entries].start = strtol(tstr1, (char **)NULL, 16); - layout->entries[layout->num_entries].end = strtol(tstr2, (char **)NULL, 16); - layout->entries[layout->num_entries].included = false; - layout->entries[layout->num_entries].name = strdup(tempname); - if (!layout->entries[layout->num_entries].name) { - msg_gerr("Error adding layout entry: %s\n", strerror(errno)); + if (flashrom_layout_add_region(*layout, + strtol(tstr1, NULL, 16), strtol(tstr2, NULL, 16), tempname)) goto _close_ret; - } - layout->num_entries++; } - - for (i = 0; i < layout->num_entries; i++) { - msg_gdbg("romlayout %08x - %08x named %s\n", - layout->entries[i].start, - layout->entries[i].end, layout->entries[i].name); - } - ret = 0; _close_ret: @@ -104,45 +114,128 @@ _close_ret: } #endif +static bool parse_include_args(const char *arg, char **name, char **file) +{ + char *colon; + char *tmp_name; + char *tmp_file = NULL; /* file is optional, so defaults to NULL */ + + if (arg == NULL) { + msg_gerr("<NULL> is a bad region name.\n"); + return false; + } + + /* -i <image>[:<file>] */ + colon = strchr(arg, ':'); + if (colon && !colon[1]) { + msg_gerr("Missing filename parameter in %s\n", arg); + return false; + } + + if (colon) { + tmp_name = strndup(arg, colon - arg); + if (!tmp_name) { + msg_gerr("Out of memory\n"); + goto error; + } + + tmp_file = strdup(colon + 1); + if (!tmp_file) { + msg_gerr("Out of memory\n"); + goto error; + } + } else { + tmp_name = strdup(arg); + } + + *name = tmp_name; + *file = tmp_file; + + return true; + +error: + free(tmp_name); + free(tmp_file); + return false; +} + /* register an include argument (-i) for later processing */ -int register_include_arg(struct layout_include_args **args, char *name) +int register_include_arg(struct layout_include_args **args, const char *arg) { struct layout_include_args *tmp; - if (name == NULL) { - msg_gerr("<NULL> is a bad region name.\n"); + char *name; + char *file; + + if (!parse_include_args(arg, &name, &file)) return 1; - } - tmp = *args; - while (tmp) { + for (tmp = *args; tmp; tmp = tmp->next) { if (!strcmp(tmp->name, name)) { msg_gerr("Duplicate region name: \"%s\".\n", name); - return 1; + goto error; } - tmp = tmp->next; } - tmp = malloc(sizeof(struct layout_include_args)); + tmp = malloc(sizeof(*tmp)); if (tmp == NULL) { - msg_gerr("Could not allocate memory"); - return 1; + msg_gerr("Out of memory\n"); + goto error; } tmp->name = name; + tmp->file = file; tmp->next = *args; *args = tmp; - return 0; + +error: + free(name); + free(file); + return 1; +} + +static char *sanitise_filename(char *filename) +{ + for (unsigned i = 0; filename[i]; i++) { + if (isspace((unsigned char)filename[i])) + filename[i] = '_'; + } + return filename; +} + +/* returns 0 to indicate success, 1 to indicate failure */ +static int include_region(struct flashrom_layout *const l, const char *name, + const char *file) +{ + struct romentry *const entry = _layout_entry_by_name(l, name); + if (entry) { + entry->included = true; + if (file) + entry->file = sanitise_filename(strdup(file)); + return 0; + } + return 1; +} + +/* returns 0 to indicate success, 1 to indicate failure */ +static int exclude_region(struct flashrom_layout *const l, const char *name) +{ + struct romentry *const entry = _layout_entry_by_name(l, name); + if (entry) { + entry->included = false; + return 0; + } + return 1; } /* returns -1 if an entry is not found, 0 if found. */ -static int find_romentry(struct flashrom_layout *const l, char *name) +static int romentry_exists(struct flashrom_layout *const l, char *name, char *file) { - if (l->num_entries == 0) + if (!l->head) return -1; msg_gspew("Looking for region \"%s\"... ", name); - if (flashrom_layout_include_region(l, name)) { + if (include_region(l, name, file)) { msg_gspew("not found.\n"); return -1; } @@ -161,8 +254,8 @@ int process_include_args(struct flashrom_layout *l, const struct layout_include_ if (args == NULL) return 0; - /* User has specified an area, but no layout file is loaded. */ - if (l->num_entries == 0) { + /* User has specified an include argument, but no layout is loaded. */ + if (!l || !l->head) { msg_gerr("Region requested (with -i \"%s\"), " "but no layout data is available.\n", args->name); @@ -171,7 +264,7 @@ int process_include_args(struct flashrom_layout *l, const struct layout_include_ tmp = args; while (tmp) { - if (find_romentry(l, tmp->name) < 0) { + if (romentry_exists(l, tmp->name, tmp->file) < 0) { msg_gerr("Invalid region specified: \"%s\".\n", tmp->name); return 1; @@ -180,10 +273,14 @@ int process_include_args(struct flashrom_layout *l, const struct layout_include_ found++; } - msg_ginfo("Using region%s:", found > 1 ? "s" : ""); + msg_ginfo("Using region%s: ", found > 1 ? "s" : ""); tmp = args; while (tmp) { - msg_ginfo(" \"%s\"%s", tmp->name, found > 1 ? "," : ""); + msg_ginfo("\"%s\"", tmp->name); + if (tmp->file) + msg_ginfo(":\"%s\"", tmp->file); + if (found > 1) + msg_ginfo(", "); found--; tmp = tmp->next; } @@ -191,43 +288,69 @@ int process_include_args(struct flashrom_layout *l, const struct layout_include_ return 0; } -void layout_cleanup(struct layout_include_args **args) +/* returns boolean 1 if any regions overlap, 0 otherwise */ +int included_regions_overlap(const struct flashrom_layout *const l) +{ + const struct romentry *lhs = NULL; + int overlap_detected = 0; + + while ((lhs = layout_next(l, lhs))) { + if (!lhs->included) + continue; + + const struct romentry *rhs = lhs; + while ((rhs = layout_next(l, rhs))) { + if (!rhs->included) + continue; + + const struct flash_region *rhsr = &rhs->region; + const struct flash_region *lhsr = &lhs->region; + + if (lhsr->start > rhsr->end) + continue; + + if (lhsr->end < rhsr->start) + continue; + + msg_gwarn("Regions %s [0x%08"PRIx32"-0x%08"PRIx32"] and %s [0x%08"PRIx32"-0x%08"PRIx32"] overlap\n", + lhsr->name, lhsr->start, lhsr->end, rhsr->name, rhsr->start, rhsr->end); + overlap_detected = 1; + } + } + return overlap_detected; +} + +void cleanup_include_args(struct layout_include_args **args) { - struct flashrom_layout *const layout = get_global_layout(); - unsigned int i; struct layout_include_args *tmp; while (*args) { tmp = (*args)->next; + free((*args)->name); + free((*args)->file); free(*args); *args = tmp; } - - for (i = 0; i < layout->num_entries; i++) { - free(layout->entries[i].name); - layout->entries[i].included = false; - } - layout->num_entries = 0; } -/* Validate and - if needed - normalize layout entries. */ -int normalize_romentries(const struct flashctx *flash) +int layout_sanity_checks(const struct flashrom_flashctx *const flash) { - struct flashrom_layout *const layout = get_global_layout(); - chipsize_t total_size = flash->chip->total_size * 1024; + const struct flashrom_layout *const layout = get_layout(flash); + const chipsize_t total_size = flash->chip->total_size * 1024; int ret = 0; - unsigned int i; - for (i = 0; i < layout->num_entries; i++) { - if (layout->entries[i].start >= total_size || layout->entries[i].end >= total_size) { - msg_gwarn("Warning: Address range of region \"%s\" exceeds the current chip's " - "address space.\n", layout->entries[i].name); - if (layout->entries[i].included) + const struct romentry *entry = NULL; + while ((entry = layout_next(layout, entry))) { + const struct flash_region *region = &entry->region; + if (region->start >= total_size || region->end >= total_size) { + msg_gwarn("Warning: Address range of region \"%s\" " + "exceeds the current chip's address space.\n", region->name); + if (entry->included) ret = 1; } - if (layout->entries[i].start > layout->entries[i].end) { + if (region->start > region->end) { msg_gerr("Error: Size of the address range of region \"%s\" is not positive.\n", - layout->entries[i].name); + region->name); ret = 1; } } @@ -235,19 +358,31 @@ int normalize_romentries(const struct flashctx *flash) return ret; } +void prepare_layout_for_extraction(struct flashctx *flash) +{ + const struct flashrom_layout *const l = get_layout(flash); + struct romentry *entry = NULL; + + while ((entry = mutable_layout_next(l, entry))) { + entry->included = true; + + if (!entry->file) + entry->file = sanitise_filename(strdup(entry->region.name)); + } +} + const struct romentry *layout_next_included_region( const struct flashrom_layout *const l, const chipoff_t where) { - unsigned int i; - const struct romentry *lowest = NULL; + const struct romentry *entry = NULL, *lowest = NULL; - for (i = 0; i < l->num_entries; ++i) { - if (!l->entries[i].included) + while ((entry = layout_next(l, entry))) { + if (!entry->included) continue; - if (l->entries[i].end < where) + if (entry->region.end < where) continue; - if (!lowest || lowest->start > l->entries[i].start) - lowest = &l->entries[i]; + if (!lowest || lowest->region.start > entry->region.start) + lowest = entry; } return lowest; @@ -256,62 +391,96 @@ const struct romentry *layout_next_included_region( const struct romentry *layout_next_included( const struct flashrom_layout *const layout, const struct romentry *iterator) { - const struct romentry *const end = layout->entries + layout->num_entries; + while ((iterator = layout_next(layout, iterator))) { + if (iterator->included) + break; + } + return iterator; +} - if (iterator) - ++iterator; - else - iterator = &layout->entries[0]; +const struct romentry *layout_next( + const struct flashrom_layout *const layout, const struct romentry *iterator) +{ + return iterator ? iterator->next : layout->head; +} - for (; iterator < end; ++iterator) { - if (!iterator->included) - continue; - return iterator; +int flashrom_layout_new(struct flashrom_layout **const layout) +{ + *layout = calloc(1, sizeof(**layout)); + if (!*layout) { + msg_gerr("Error creating layout: %s\n", strerror(errno)); + return 1; } - return NULL; + + return 0; } -/** - * @addtogroup flashrom-layout - * @{ - */ +int flashrom_layout_add_region( + struct flashrom_layout *const layout, + const size_t start, const size_t end, const char *const name) +{ + struct romentry *const entry = malloc(sizeof(*entry)); + if (!entry) + goto _err_ret; + + const struct romentry tmp = { + .next = layout->head, + .included = false, + .file = NULL, + .region = { + .start = start, + .end = end, + .name = strdup(name), + }, + }; + *entry = tmp; + if (!entry->region.name) + goto _err_ret; + + msg_gdbg("Added layout entry %08zx - %08zx named %s\n", start, end, name); + layout->head = entry; + return 0; + +_err_ret: + msg_gerr("Error adding layout entry: %s\n", strerror(errno)); + free(entry); + return 1; +} -/** - * @brief Mark given region as included. - * - * @param layout The layout to alter. - * @param name The name of the region to include. - * - * @return 0 on success, - * 1 if the given name can't be found. - */ int flashrom_layout_include_region(struct flashrom_layout *const layout, const char *name) { - size_t i; - for (i = 0; i < layout->num_entries; ++i) { - if (!strcmp(layout->entries[i].name, name)) { - layout->entries[i].included = true; - return 0; - } + return include_region(layout, name, NULL); +} + +int flashrom_layout_exclude_region(struct flashrom_layout *const layout, const char *name) +{ + return exclude_region(layout, name); +} + +int flashrom_layout_get_region_range(struct flashrom_layout *const l, const char *name, + unsigned int *start, unsigned int *len) +{ + const struct romentry *const entry = _layout_entry_by_name(l, name); + if (entry) { + const struct flash_region *region = &entry->region; + *start = region->start; + *len = region->end - region->start + 1; + return 0; } return 1; } -/** - * @brief Free a layout. - * - * @param layout Layout to free. - */ void flashrom_layout_release(struct flashrom_layout *const layout) { - unsigned int i; - - if (!layout || layout == get_global_layout()) + if (!layout) return; - for (i = 0; i < layout->num_entries; ++i) - free(layout->entries[i].name); + while (layout->head) { + struct romentry *const entry = layout->head; + layout->head = entry->next; + free(entry->file); + free(entry->region.name); + free(entry); + } free(layout); } - -/** @} */ /* end flashrom-layout */ |