diff options
author | Øyvind Harboe <oyvind.harboe@zylin.com> | 2010-04-29 17:42:47 +0200 |
---|---|---|
committer | Øyvind Harboe <oyvind.harboe@zylin.com> | 2010-04-29 18:39:48 +0200 |
commit | 5e79f999bcc898d94a2d7751831e9f7aee24fbd5 (patch) | |
tree | d76fb4bf92542115bb6ebd6d72479c9998cc8e2e /src/flash/nor | |
parent | 78248f1df67d1b4feefd8ac4e459acd7599d6af2 (diff) | |
download | openocd+libswd-5e79f999bcc898d94a2d7751831e9f7aee24fbd5.tar.gz openocd+libswd-5e79f999bcc898d94a2d7751831e9f7aee24fbd5.tar.bz2 openocd+libswd-5e79f999bcc898d94a2d7751831e9f7aee24fbd5.tar.xz openocd+libswd-5e79f999bcc898d94a2d7751831e9f7aee24fbd5.zip |
flash: write_image would fail for certain images
Fix a bug where write_image would fail if the sections
in the image were not in ascending order. This has previously
been fixed in gdb load.
Solved by sorting the image sections before running flash
write_image erase unlock foo.elf.
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
Diffstat (limited to 'src/flash/nor')
-rw-r--r-- | src/flash/nor/core.c | 69 |
1 files changed, 55 insertions, 14 deletions
diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c index 1ff41937..9a773537 100644 --- a/src/flash/nor/core.c +++ b/src/flash/nor/core.c @@ -509,6 +509,25 @@ static int flash_unlock_address_range(struct target *target, uint32_t addr, uint addr, length, &flash_driver_unprotect); } +static int compare_section (const void * a, const void * b) +{ + struct imageection *b1, *b2; + b1=*((struct imageection **)a); + b2=*((struct imageection **)b); + + if (b1->base_address == b2->base_address) + { + return 0; + } else if (b1->base_address > b2->base_address) + { + return 1; + } else + { + return -1; + } +} + + int flash_write_unlock(struct target *target, struct image *image, uint32_t *written, int erase, bool unlock) { @@ -536,6 +555,19 @@ int flash_write_unlock(struct target *target, struct image *image, /* allocate padding array */ padding = calloc(image->num_sections, sizeof(*padding)); + /* This fn requires all sections to be in ascending order of addresses, + * whereas an image can have sections out of order. */ + struct imageection **sections = malloc(sizeof(struct imageection *) * + image->num_sections); + int i; + for (i = 0; i < image->num_sections; i++) + { + sections[i] = &image->sections[i]; + } + + qsort(sections, image->num_sections, sizeof(struct imageection *), + compare_section); + /* loop until we reach end of the image */ while (section < image->num_sections) { @@ -543,11 +575,11 @@ int flash_write_unlock(struct target *target, struct image *image, uint8_t *buffer; int section_first; int section_last; - uint32_t run_address = image->sections[section].base_address + section_offset; - uint32_t run_size = image->sections[section].size - section_offset; + uint32_t run_address = sections[section]->base_address + section_offset; + uint32_t run_size = sections[section]->size - section_offset; int pad_bytes = 0; - if (image->sections[section].size == 0) + if (sections[section]->size == 0) { LOG_WARNING("empty section %d", section); section++; @@ -570,7 +602,7 @@ int flash_write_unlock(struct target *target, struct image *image, while ((run_address + run_size - 1 < c->base + c->size - 1) && (section_last + 1 < image->num_sections)) { - if (image->sections[section_last + 1].base_address < (run_address + run_size)) + if (sections[section_last + 1]->base_address < (run_address + run_size)) { LOG_DEBUG("section %d out of order " "(surprising, but supported)", @@ -598,11 +630,11 @@ int flash_write_unlock(struct target *target, struct image *image, /* if we have multiple sections within our image, * flash programming could fail due to alignment issues * attempt to rebuild a consecutive buffer for the flash loader */ - pad_bytes = (image->sections[section_last + 1].base_address) - (run_address + run_size); + pad_bytes = (sections[section_last + 1]->base_address) - (run_address + run_size); if ((run_address + run_size + pad_bytes) > (c->base + c->size)) break; padding[section_last] = pad_bytes; - run_size += image->sections[++section_last].size; + run_size += sections[++section_last]->size; run_size += pad_bytes; if (pad_bytes > 0) @@ -651,15 +683,21 @@ int flash_write_unlock(struct target *target, struct image *image, size_t size_read; size_read = run_size - buffer_size; - if (size_read > image->sections[section].size - section_offset) - size_read = image->sections[section].size - section_offset; + if (size_read > sections[section]->size - section_offset) + size_read = sections[section]->size - section_offset; - if ((retval = image_read_section(image, section, section_offset, + /* KLUDGE! + * + * #¤%#"%¤% we have to figure out the section # from the sorted + * list of pointers to sections to invoke image_read_section()... + */ + int t_section_num = (sections[section] - image->sections) / sizeof(struct imageection); + + if ((retval = image_read_section(image, t_section_num, section_offset, size_read, buffer + buffer_size, &size_read)) != ERROR_OK || size_read == 0) { free(buffer); - free(padding); - return retval; + goto done; } /* see if we need to pad the section */ @@ -669,7 +707,7 @@ int flash_write_unlock(struct target *target, struct image *image, buffer_size += size_read; section_offset += size_read; - if (section_offset >= image->sections[section].size) + if (section_offset >= sections[section]->size) { section++; section_offset = 0; @@ -702,14 +740,17 @@ int flash_write_unlock(struct target *target, struct image *image, if (retval != ERROR_OK) { - free(padding); - return retval; /* abort operation */ + /* abort operation */ + goto done; } if (written != NULL) *written += run_size; /* add run size to total written counter */ } + +done: + free(sections); free(padding); return retval; |