summaryrefslogtreecommitdiffstats
path: root/layout.c
diff options
context:
space:
mode:
Diffstat (limited to 'layout.c')
-rw-r--r--layout.c407
1 files changed, 288 insertions, 119 deletions
diff --git a/layout.c b/layout.c
index 272912c68..e46e61ae5 100644
--- a/layout.c
+++ b/layout.c
@@ -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 */