Signed-off-by: Stefan Tauner stefan.tauner@student.tuwien.ac.at --- flashrom.8.tmpl | 9 ++++++++- layout.c | 57 +++++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 51 insertions(+), 15 deletions(-)
diff --git a/flashrom.8.tmpl b/flashrom.8.tmpl index 06282f6..765d7f6 100644 --- a/flashrom.8.tmpl +++ b/flashrom.8.tmpl @@ -222,7 +222,14 @@ a region). One entry per line is allowed with the following syntax: .sp .BR "startaddr " "and " "endaddr " are addresses within the ROM image representing the flash ROM contents. They are interpreted in the 'usual' form -i.e.\ a leading 0 means octal, leading 0x or 0X means hexadecimal, everything else is just decimal. +i.e.\ a leading 0 means octal, leading 0x or 0X means hexadecimal, everything else is just decimal. Negative +numbers are interpreted as addresses aligned to the top of the current chip's address space, for example +.sp + 0:-0 "whole chip" +.sp +will always describe the complete flash space no matter which chip is used. This syntax is useful for specifying +"the top 1MB" (-0x100000:-0) etc. +.sp .BR "regionname " "is the name for the region from " "startaddr " "to " "endaddr " "(both addresses included)." If the name contains spaces it has to be written in double quotes, or else only the part before the first space will be used. diff --git a/layout.c b/layout.c index 6150e7e..d94cbe0 100644 --- a/layout.c +++ b/layout.c @@ -37,6 +37,8 @@ typedef struct { chipoff_t start; chipoff_t end; + bool start_topalign; + bool end_topalign; bool included; char *name; char *file; @@ -146,14 +148,15 @@ static int parse_entry(char *file_name, unsigned int linecnt, char *buf, romentr "Could not convert start address in "%s".\n", file_name, linecnt, buf); return -1; } - if (tmp_addr < 0 || tmp_addr > FL_MAX_CHIPADDR) { + bool start_topalign = (tmp_str[0] == '-'); + if (llabs(tmp_addr) > FL_MAX_CHIPADDR) { msg_gerr("Error parsing version 2 layout entry in file "%s" at line %d:\n" "Start address (%s0x%llx) in "%s" is beyond the supported range (max 0x%" - PRIxCHIPADDR ").\n", file_name, linecnt, (tmp_addr < 0) ? "-" : "", + PRIxCHIPADDR ").\n", file_name, linecnt, start_topalign ? "-" : "", llabs(tmp_addr), buf, FL_MAX_CHIPADDR); return -1; } - chipoff_t start = (chipoff_t)tmp_addr; + chipoff_t start = (chipoff_t)llabs(tmp_addr);
tmp_str = endptr + strspn(endptr, WHITESPACE_CHARS); if (*tmp_str != ':') { @@ -172,14 +175,15 @@ static int parse_entry(char *file_name, unsigned int linecnt, char *buf, romentr "Could not convert end address in "%s".\n", file_name, linecnt, buf); return -1; } - if (tmp_addr < 0 || tmp_addr > FL_MAX_CHIPADDR) { + bool end_topalign = (tmp_str[0] == '-'); + if (llabs(tmp_addr) > FL_MAX_CHIPADDR) { msg_gerr("Error parsing version 2 layout entry in file "%s" at line %d:\n" "End address (%s0x%llx) in "%s" is beyond the supported range (max 0x%" - PRIxCHIPADDR ").\n", file_name, linecnt, (tmp_addr < 0) ? "-" : "", + PRIxCHIPADDR ").\n", file_name, linecnt, end_topalign ? "-" : "", llabs(tmp_addr), buf, FL_MAX_CHIPADDR); return -1; } - chipoff_t end = (chipoff_t)tmp_addr; + chipoff_t end = (chipoff_t)llabs(tmp_addr);
size_t skip = strspn(endptr, WHITESPACE_CHARS); if (skip == 0) { @@ -197,10 +201,15 @@ static int parse_entry(char *file_name, unsigned int linecnt, char *buf, romentr return -1; }
- msg_gdbg2("Parsed entry: 0x%" PRIxCHIPADDR " - 0x%" PRIxCHIPADDR " named "%s"\n", - start, end, tmp_str); + msg_gdbg2("Parsed entry: 0x%" PRIxCHIPADDR " (%s) : 0x%" PRIxCHIPADDR " (%s) named "%s"\n", + start, start_topalign ? "top-aligned" : "bottom-aligned", + end, end_topalign ? "top-aligned" : "bottom-aligned", tmp_str);
- if (start >= end) { + /* We can only check address ranges if the chip size is available in case one address is relative to + * the top and the other to the bottom. But if they are both relative to the same end we can without + * knowing the complete size. This allows us to bail out before probing. */ + if ((!start_topalign && !end_topalign && start > end) || + (start_topalign && end_topalign && start < end)) { msg_gerr("Error parsing version 2 layout entry in file "%s" at line %d:\n" "Length of region "%s" is not positive.\n", file_name, linecnt, tmp_str); return -1; @@ -218,6 +227,7 @@ static int parse_entry(char *file_name, unsigned int linecnt, char *buf, romentr "Region name "%s" is not followed by white space only.\n", file_name, linecnt, tmp_str);
+ if (entry != NULL) { entry->name = strdup(tmp_str); if (entry->name == NULL) { @@ -228,6 +238,8 @@ static int parse_entry(char *file_name, unsigned int linecnt, char *buf, romentr entry->start = start; entry->end = end; entry->included = 0; + entry->start_topalign = start_topalign; + entry->end_topalign = end_topalign; entry->file = NULL; } return 0; @@ -496,15 +508,32 @@ int normalize_romentries(const struct flashctx *flash)
int i; for (i = 0; i < num_rom_entries; i++) { - if (rom_entries[i].start >= total_size || rom_entries[i].end >= total_size) { + romentry_t *cur = &rom_entries[i]; + /* Normalize top-aligned address. */ + if (cur->start_topalign || cur->end_topalign) { + if (cur->start_topalign) { + cur->start = total_size - cur->start - 1; + cur->start_topalign = 0; + } + + if (cur->end_topalign) { + cur->end = total_size - cur->end - 1; + cur->end_topalign = 0; + } + + msg_gspew("Normalized entry %d "%s": 0x%" PRIxCHIPADDR " - 0x%" PRIxCHIPADDR "\n", + i, cur->name, cur->start, cur->end); + } + + if (cur->start >= total_size || cur->end >= total_size) { msg_gwarn("Warning: Address range of region "%s" exceeds the current chip's " - "address space.\n", rom_entries[i].name); - if (rom_entries[i].included) + "address space.\n", cur->name); + if (cur->included) ret = 1; } - if (rom_entries[i].start > rom_entries[i].end) { + if (cur->start > cur->end) { msg_gerr("Error: Size of the address range of region "%s" is not positive.\n", - rom_entries[i].name); + cur->name); ret = 1; } }