X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fcore.c;h=7a62ba1c76223d03f130d109ead872d7d6ff6a82;hp=15e460a1b0f9469c17979895d2ba016809ab9117;hb=refs%2Fchanges%2F45%2F3545%2F6;hpb=620310bcc64a0ba9103c4c05300fe9d25cc92b12 diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c index 15e460a1b0..7a62ba1c76 100644 --- a/src/flash/nor/core.c +++ b/src/flash/nor/core.c @@ -1,8 +1,9 @@ /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * - * Copyright (C) 2007,2008 Øyvind Harboe * + * Copyright (C) 2007-2010 Øyvind Harboe * * Copyright (C) 2008 by Spencer Oliver * * Copyright (C) 2009 Zachary T Welch * + * Copyright (C) 2010 by Antonio Borneo * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -15,9 +16,7 @@ * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * along with this program. If not, see . * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -28,7 +27,6 @@ #include #include - /** * @file * Upper level of NOR flash framework. @@ -44,9 +42,7 @@ int flash_driver_erase(struct flash_bank *bank, int first, int last) retval = bank->driver->erase(bank, first, last); if (retval != ERROR_OK) - { - LOG_ERROR("failed erasing sectors %d to %d (%d)", first, last, retval); - } + LOG_ERROR("failed erasing sectors %d to %d", first, last); return retval; } @@ -54,116 +50,88 @@ int flash_driver_erase(struct flash_bank *bank, int first, int last) int flash_driver_protect(struct flash_bank *bank, int set, int first, int last) { int retval; - bool updated = false; - - /* NOTE: "first == last" means (un?)protect just that sector. - code including Lower level ddrivers may rely on this "first <= last" - * invariant. - */ /* callers may not supply illegal parameters ... */ - if (first < 0 || first > last || last >= bank->num_sectors) + if (first < 0 || first > last || last >= bank->num_sectors) { + LOG_ERROR("illegal sector range"); return ERROR_FAIL; + } /* force "set" to 0/1 */ set = !!set; - /* - * Filter out what trivial nonsense we can, so drivers don't have to. + /* DANGER! * - * Don't tell drivers to change to the current state... it's needless, - * and reducing the amount of work to be done (potentially to nothing) - * speeds at least some things up. - */ -scan: - for (int i = first; i <= last; i++) { - struct flash_sector *sector = bank->sectors + i; - - /* Only filter requests to protect the already-protected, or - * to unprotect the already-unprotected. Changing from the - * unknown state (-1) to a known one is unwise but allowed; - * protection status is best checked first. - */ - if (sector->is_protected != set) - continue; - - /* Shrink this range of sectors from the start; don't overrun - * the end. Also shrink from the end; don't overun the start. - * - * REVISIT we could handle discontiguous regions by issuing - * more than one driver request. How much would that matter? - */ - if (i == first && i != last) { - updated = true; - first++; - } else if (i == last && i != first) { - updated = true; - last--; - } - } - - /* updating the range affects the tests in the scan loop above; so - * re-scan, to make sure we didn't miss anything. - */ - if (updated) { - updated = false; - goto scan; - } - - /* Single sector, already protected? Nothing to do! - * We may have trimmed our parameters into this degenerate case. + * We must not use any cached information about protection state!!!! * - * FIXME repeating the "is_protected==set" test is a giveaway that - * this fast-exit belongs earlier, in the trim-it-down loop; mve. - * */ - if (first == last && bank->sectors[first].is_protected == set) - return ERROR_OK; - - - /* Note that we don't pass illegal parameters to drivers; any - * trimming just turns one valid range into another one. + * There are a million things that could change the protect state: + * + * the target could have reset, power cycled, been hot plugged, + * the application could have run, etc. + * + * Drivers only receive valid sector range. */ retval = bank->driver->protect(bank, set, first, last); if (retval != ERROR_OK) - { - LOG_ERROR("failed setting protection for areas %d to %d (%d)", first, last, retval); - } + LOG_ERROR("failed setting protection for areas %d to %d", first, last); return retval; } int flash_driver_write(struct flash_bank *bank, - uint8_t *buffer, uint32_t offset, uint32_t count) + uint8_t *buffer, uint32_t offset, uint32_t count) { int retval; retval = bank->driver->write(bank, buffer, offset, count); - if (retval != ERROR_OK) - { - LOG_ERROR("error writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32 " (%d)", - bank->base, offset, retval); + if (retval != ERROR_OK) { + LOG_ERROR( + "error writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32, + bank->base, + offset); + } + + return retval; +} + +int flash_driver_read(struct flash_bank *bank, + uint8_t *buffer, uint32_t offset, uint32_t count) +{ + int retval; + + LOG_DEBUG("call flash_driver_read()"); + + retval = bank->driver->read(bank, buffer, offset, count); + if (retval != ERROR_OK) { + LOG_ERROR( + "error reading to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32, + bank->base, + offset); } return retval; } +int default_flash_read(struct flash_bank *bank, + uint8_t *buffer, uint32_t offset, uint32_t count) +{ + return target_read_buffer(bank->target, offset + bank->base, count, buffer); +} + void flash_bank_add(struct flash_bank *bank) { /* put flash bank in linked list */ unsigned bank_num = 0; - if (flash_banks) - { + if (flash_banks) { /* find last flash bank */ struct flash_bank *p = flash_banks; - while (NULL != p->next) - { + while (NULL != p->next) { bank_num += 1; p = p->next; } p->next = bank; bank_num += 1; - } - else + } else flash_banks = bank; bank->bank_number = bank_num; @@ -179,12 +147,9 @@ struct flash_bank *get_flash_bank_by_num_noprobe(int num) struct flash_bank *p; int i = 0; - for (p = flash_banks; p; p = p->next) - { + for (p = flash_banks; p; p = p->next) { if (i++ == num) - { return p; - } } LOG_ERROR("flash bank %d does not exist", num); return NULL; @@ -195,20 +160,17 @@ int flash_get_bank_count(void) struct flash_bank *p; int i = 0; for (p = flash_banks; p; p = p->next) - { i++; - } return i; } -struct flash_bank *get_flash_bank_by_name(const char *name) +struct flash_bank *get_flash_bank_by_name_noprobe(const char *name) { unsigned requested = get_flash_name_index(name); unsigned found = 0; struct flash_bank *bank; - for (bank = flash_banks; NULL != bank; bank = bank->next) - { + for (bank = flash_banks; NULL != bank; bank = bank->next) { if (strcmp(bank->name, name) == 0) return bank; if (!flash_driver_name_matches(bank->driver->name, name)) @@ -220,49 +182,79 @@ struct flash_bank *get_flash_bank_by_name(const char *name) return NULL; } -struct flash_bank *get_flash_bank_by_num(int num) +int get_flash_bank_by_name(const char *name, struct flash_bank **bank_result) +{ + struct flash_bank *bank; + int retval; + + bank = get_flash_bank_by_name_noprobe(name); + if (bank != NULL) { + retval = bank->driver->auto_probe(bank); + + if (retval != ERROR_OK) { + LOG_ERROR("auto_probe failed"); + return retval; + } + } + + *bank_result = bank; + return ERROR_OK; +} + +int get_flash_bank_by_num(int num, struct flash_bank **bank) { struct flash_bank *p = get_flash_bank_by_num_noprobe(num); int retval; if (p == NULL) - return NULL; + return ERROR_FAIL; retval = p->driver->auto_probe(p); - if (retval != ERROR_OK) - { - LOG_ERROR("auto_probe failed %d\n", retval); - return NULL; + if (retval != ERROR_OK) { + LOG_ERROR("auto_probe failed"); + return retval; } - return p; + *bank = p; + return ERROR_OK; } -/* lookup flash bank by address */ -struct flash_bank *get_flash_bank_by_addr(struct target *target, uint32_t addr) +/* lookup flash bank by address, bank not found is success, but + * result_bank is set to NULL. */ +int get_flash_bank_by_addr(struct target *target, + uint32_t addr, + bool check, + struct flash_bank **result_bank) { struct flash_bank *c; /* cycle through bank list */ - for (c = flash_banks; c; c = c->next) - { + for (c = flash_banks; c; c = c->next) { + if (c->target != target) + continue; + int retval; retval = c->driver->auto_probe(c); - if (retval != ERROR_OK) - { - LOG_ERROR("auto_probe failed %d\n", retval); - return NULL; + if (retval != ERROR_OK) { + LOG_ERROR("auto_probe failed"); + return retval; } /* check whether address belongs to this flash bank */ - if ((addr >= c->base) && (addr <= c->base + (c->size - 1)) && target == c->target) - return c; + if ((addr >= c->base) && (addr <= c->base + (c->size - 1))) { + *result_bank = c; + return ERROR_OK; + } } - LOG_ERROR("No flash at address 0x%08" PRIx32 "\n", addr); - return NULL; + *result_bank = NULL; + if (check) { + LOG_ERROR("No flash at address 0x%08" PRIx32, addr); + return ERROR_FAIL; + } + return ERROR_OK; } -int default_flash_mem_blank_check(struct flash_bank *bank) +static int default_flash_mem_blank_check(struct flash_bank *bank) { struct target *target = bank->target; const int buffer_size = 1024; @@ -270,38 +262,33 @@ int default_flash_mem_blank_check(struct flash_bank *bank) uint32_t nBytes; int retval = ERROR_OK; - if (bank->target->state != TARGET_HALTED) - { + if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } uint8_t *buffer = malloc(buffer_size); - for (i = 0; i < bank->num_sectors; i++) - { + for (i = 0; i < bank->num_sectors; i++) { uint32_t j; bank->sectors[i].is_erased = 1; - for (j = 0; j < bank->sectors[i].size; j += buffer_size) - { + for (j = 0; j < bank->sectors[i].size; j += buffer_size) { uint32_t chunk; chunk = buffer_size; if (chunk > (j - bank->sectors[i].size)) - { chunk = (j - bank->sectors[i].size); - } - retval = target_read_memory(target, bank->base + bank->sectors[i].offset + j, 4, chunk/4, buffer); + retval = target_read_memory(target, + bank->base + bank->sectors[i].offset + j, + 4, + chunk/4, + buffer); if (retval != ERROR_OK) - { goto done; - } - for (nBytes = 0; nBytes < chunk; nBytes++) - { - if (buffer[nBytes] != 0xFF) - { + for (nBytes = 0; nBytes < chunk; nBytes++) { + if (buffer[nBytes] != 0xFF) { bank->sectors[i].is_erased = 0; break; } @@ -309,7 +296,7 @@ int default_flash_mem_blank_check(struct flash_bank *bank) } } - done: +done: free(buffer); return retval; @@ -323,19 +310,17 @@ int default_flash_blank_check(struct flash_bank *bank) int fast_check = 0; uint32_t blank; - if (bank->target->state != TARGET_HALTED) - { + if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - for (i = 0; i < bank->num_sectors; i++) - { + for (i = 0; i < bank->num_sectors; i++) { uint32_t address = bank->base + bank->sectors[i].offset; uint32_t size = bank->sectors[i].size; - if ((retval = target_blank_check_memory(target, address, size, &blank)) != ERROR_OK) - { + retval = target_blank_check_memory(target, address, size, &blank); + if (retval != ERROR_OK) { fast_check = 0; break; } @@ -346,8 +331,7 @@ int default_flash_blank_check(struct flash_bank *bank) fast_check = 1; } - if (!fast_check) - { + if (!fast_check) { LOG_USER("Running slow fallback erase check - add working memory"); return default_flash_mem_blank_check(bank); } @@ -359,8 +343,9 @@ int default_flash_blank_check(struct flash_bank *bank) * and address. Maps an address range to a set of sectors, and issues * the callback() on that set ... e.g. to erase or unprotect its members. * - * (Note a current bad assumption: that protection operates on the same - * size sectors as erase operations use.) + * Parameter iterate_protect_blocks switches iteration of protect block + * instead of erase sectors. If there is no protect blocks array, sectors + * are used in iteration, so compatibility for old flash drivers is retained. * * The "pad_reason" parameter is a kind of boolean: when it's NULL, the * range must fit those sectors exactly. This is clearly safe; it can't @@ -369,30 +354,31 @@ int default_flash_blank_check(struct flash_bank *bank) * sectors will be added to the range, and that reason string is used when * warning about those additions. */ -static int flash_iterate_address_range(struct target *target, - char *pad_reason, uint32_t addr, uint32_t length, - int (*callback)(struct flash_bank *bank, int first, int last)) +static int flash_iterate_address_range_inner(struct target *target, + char *pad_reason, uint32_t addr, uint32_t length, + bool iterate_protect_blocks, + int (*callback)(struct flash_bank *bank, int first, int last)) { struct flash_bank *c; + struct flash_sector *block_array; uint32_t last_addr = addr + length; /* first address AFTER end */ int first = -1; int last = -1; int i; + int num_blocks; - if ((c = get_flash_bank_by_addr(target, addr)) == NULL) - return ERROR_FLASH_DST_OUT_OF_BANK; /* no corresponding bank found */ + int retval = get_flash_bank_by_addr(target, addr, true, &c); + if (retval != ERROR_OK) + return retval; - if (c->size == 0 || c->num_sectors == 0) - { + if (c->size == 0 || c->num_sectors == 0) { LOG_ERROR("Bank is invalid"); return ERROR_FLASH_BANK_INVALID; } - if (length == 0) - { + if (length == 0) { /* special case, erase whole bank when length is zero */ - if (addr != c->base) - { + if (addr != c->base) { LOG_ERROR("Whole bank access must start at beginning of bank."); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } @@ -401,20 +387,26 @@ static int flash_iterate_address_range(struct target *target, } /* check whether it all fits in this bank */ - if (addr + length - 1 > c->base + c->size - 1) - { + if (addr + length - 1 > c->base + c->size - 1) { LOG_ERROR("Flash access does not fit into bank."); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } - /** @todo: handle erasures that cross into adjacent banks */ - addr -= c->base; last_addr -= c->base; - for (i = 0; i < c->num_sectors; i++) - { - struct flash_sector *f = c->sectors + i; + if (iterate_protect_blocks && c->prot_blocks && c->num_prot_blocks) { + block_array = c->prot_blocks; + num_blocks = c->num_prot_blocks; + } else { + block_array = c->sectors; + num_blocks = c->num_sectors; + iterate_protect_blocks = false; + } + + + for (i = 0; i < num_blocks; i++) { + struct flash_sector *f = &block_array[i]; uint32_t end = f->offset + f->size; /* start only on a sector boundary */ @@ -437,7 +429,7 @@ static int flash_iterate_address_range(struct target *target, else if (addr < end && pad_reason) { /* FIXME say how many bytes (e.g. 80 KB) */ LOG_WARNING("Adding extra %s range, " - "%#8.8x to %#8.8x", + "%#8.8x to %#8.8x", pad_reason, (unsigned) f->offset, (unsigned) addr - 1); @@ -458,7 +450,7 @@ static int flash_iterate_address_range(struct target *target, if (last_addr < end && pad_reason) { /* FIXME say how many bytes (e.g. 80 KB) */ LOG_WARNING("Adding extra %s range, " - "%#8.8x to %#8.8x", + "%#8.8x to %#8.8x", pad_reason, (unsigned) last_addr, (unsigned) end - 1); @@ -474,9 +466,9 @@ static int flash_iterate_address_range(struct target *target, /* invalid start or end address? */ if (first == -1 || last == -1) { LOG_ERROR("address range 0x%8.8x .. 0x%8.8x " - "is not sector-aligned", - (unsigned) (c->base + addr), - (unsigned) (c->base + last_addr - 1)); + "is not sector-aligned", + (unsigned) (c->base + addr), + (unsigned) (c->base + last_addr - 1)); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } @@ -487,11 +479,48 @@ static int flash_iterate_address_range(struct target *target, return callback(c, first, last); } +/* The inner fn only handles a single bank, we could be spanning + * multiple chips. + */ +static int flash_iterate_address_range(struct target *target, + char *pad_reason, uint32_t addr, uint32_t length, + bool iterate_protect_blocks, + int (*callback)(struct flash_bank *bank, int first, int last)) +{ + struct flash_bank *c; + int retval = ERROR_OK; + + /* Danger! zero-length iterations means entire bank! */ + do { + retval = get_flash_bank_by_addr(target, addr, true, &c); + if (retval != ERROR_OK) + return retval; + + uint32_t cur_length = length; + /* check whether it all fits in this bank */ + if (addr + length - 1 > c->base + c->size - 1) { + LOG_DEBUG("iterating over more than one flash bank."); + cur_length = c->base + c->size - addr; + } + retval = flash_iterate_address_range_inner(target, + pad_reason, addr, cur_length, + iterate_protect_blocks, + callback); + if (retval != ERROR_OK) + break; + + length -= cur_length; + addr += cur_length; + } while (length > 0); + + return retval; +} + int flash_erase_address_range(struct target *target, - bool pad, uint32_t addr, uint32_t length) + bool pad, uint32_t addr, uint32_t length) { return flash_iterate_address_range(target, pad ? "erase" : NULL, - addr, length, &flash_driver_erase); + addr, length, false, &flash_driver_erase); } static int flash_driver_unprotect(struct flash_bank *bank, int first, int last) @@ -499,18 +528,32 @@ static int flash_driver_unprotect(struct flash_bank *bank, int first, int last) return flash_driver_protect(bank, 0, first, last); } -static int flash_unlock_address_range(struct target *target, uint32_t addr, uint32_t length) +int flash_unlock_address_range(struct target *target, uint32_t addr, uint32_t length) { /* By default, pad to sector boundaries ... the real issue here * is that our (only) caller *permanently* removes protection, * and doesn't restore it. */ return flash_iterate_address_range(target, "unprotect", - addr, length, &flash_driver_unprotect); + addr, length, true, &flash_driver_unprotect); +} + +static int compare_section(const void *a, const void *b) +{ + struct imagesection *b1, *b2; + b1 = *((struct imagesection **)a); + b2 = *((struct imagesection **)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) + uint32_t *written, int erase, bool unlock) { int retval = ERROR_OK; @@ -519,20 +562,13 @@ int flash_write_unlock(struct target *target, struct image *image, struct flash_bank *c; int *padding; - /* REVISIT do_pad should perhaps just be another parameter. - * GDB wouldn't ever need it, since it erases separately. - * But "flash write_image" commands might want that option. - */ - bool do_pad = false; - section = 0; section_offset = 0; if (written) *written = 0; - if (erase) - { + if (erase) { /* assume all sectors need erasing - stops any problems * when flash_write is called multiple times */ @@ -542,19 +578,27 @@ 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 imagesection **sections = malloc(sizeof(struct imagesection *) * + 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 imagesection *), + compare_section); + /* loop until we reach end of the image */ - while (section < image->num_sections) - { + while (section < image->num_sections) { uint32_t buffer_size; 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++; section_offset = 0; @@ -562,28 +606,25 @@ int flash_write_unlock(struct target *target, struct image *image, } /* find the corresponding flash bank */ - if ((c = get_flash_bank_by_addr(target, run_address)) == NULL) - { - section++; /* and skip it */ + retval = get_flash_bank_by_addr(target, run_address, false, &c); + if (retval != ERROR_OK) + goto done; + if (c == NULL) { + LOG_WARNING("no flash bank found for address %" PRIx32, run_address); + section++; /* and skip it */ section_offset = 0; continue; } /* collect consecutive sections which fall into the same bank */ - section_first = section; section_last = section; padding[section] = 0; - 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)) - { - LOG_DEBUG("section %d out of order " - "(surprising, but supported)", - section_last + 1); - /* REVISIT this can break with autoerase ... - * clobbering data after it's written. - */ + while ((run_address + run_size - 1 < c->base + c->size - 1) && + (section_last + 1 < image->num_sections)) { + /* sections are sorted */ + assert(sections[section_last + 1]->base_address >= c->base); + if (sections[section_last + 1]->base_address >= (c->base + c->size)) { + /* Done with this bank */ break; } @@ -604,25 +645,25 @@ 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); - if ((run_address + run_size + pad_bytes) > (c->base + c->size)) - break; + pad_bytes = (sections[section_last + 1]->base_address) - (run_address + run_size); padding[section_last] = pad_bytes; - run_size += image->sections[++section_last].size; + run_size += sections[++section_last]->size; run_size += pad_bytes; - LOG_INFO("Padding image section %d with %d bytes", section_last-1, pad_bytes); + if (pad_bytes > 0) + LOG_INFO("Padding image section %d with %d bytes", + section_last-1, + pad_bytes); } - /* fit the run into bank constraints */ - if (run_address + run_size - 1 > c->base + c->size - 1) - { - /* REVISIT isn't this superfluous, given the while() - * loop conditions above?? + if (run_address + run_size - 1 > c->base + c->size - 1) { + /* If we have more than one flash chip back to back, then we limit + * the current write operation to the current chip. */ - LOG_WARNING("writing %d bytes only - as image section is %d bytes and bank is only %d bytes", \ - (int)(c->base + c->size - run_address), (int)(run_size), (int)(c->size)); + LOG_DEBUG("Truncate flash run size to the current flash chip."); + run_size = c->base + c->size - run_address; + assert(run_size > 0); } /* If we're applying any sector automagic, then pad this @@ -636,7 +677,7 @@ int flash_write_unlock(struct target *target, struct image *image, for (sector = 0; sector < c->num_sectors; sector++) { end = c->sectors[sector].offset - + c->sectors[sector].size; + + c->sectors[sector].size; if (offset_end <= end) break; } @@ -648,34 +689,48 @@ int flash_write_unlock(struct target *target, struct image *image, /* allocate buffer */ buffer = malloc(run_size); + if (buffer == NULL) { + LOG_ERROR("Out of memory for flash bank buffer"); + retval = ERROR_FAIL; + goto done; + } buffer_size = 0; /* read sections to the buffer */ - while (buffer_size < run_size) - { + while (buffer_size < run_size) { 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, - size_read, buffer + buffer_size, &size_read)) != ERROR_OK || size_read == 0) - { + /* KLUDGE! + * + * #¤%#"%¤% we have to figure out the section # from the sorted + * list of pointers to sections to invoke image_read_section()... + */ + intptr_t diff = (intptr_t)sections[section] - (intptr_t)image->sections; + int t_section_num = diff / sizeof(struct imagesection); + + LOG_DEBUG("image_read_section: section = %d, t_section_num = %d, " + "section_offset = %d, buffer_size = %d, size_read = %d", + (int)section, (int)t_section_num, (int)section_offset, + (int)buffer_size, (int)size_read); + retval = image_read_section(image, t_section_num, section_offset, + size_read, buffer + buffer_size, &size_read); + if (retval != ERROR_OK || size_read == 0) { free(buffer); - free(padding); - return retval; + goto done; } /* see if we need to pad the section */ while (padding[section]--) - (buffer + buffer_size)[size_read++] = 0xff; + (buffer + buffer_size)[size_read++] = c->default_padded_value; 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; } @@ -684,75 +739,59 @@ int flash_write_unlock(struct target *target, struct image *image, retval = ERROR_OK; if (unlock) - { retval = flash_unlock_address_range(target, run_address, run_size); - } - if (retval == ERROR_OK) - { - if (erase) - { + if (retval == ERROR_OK) { + if (erase) { /* calculate and erase sectors */ retval = flash_erase_address_range(target, - do_pad, run_address, run_size); + true, run_address, run_size); } } - if (retval == ERROR_OK) - { + if (retval == ERROR_OK) { /* write flash sectors */ retval = flash_driver_write(c, buffer, run_address - c->base, run_size); } free(buffer); - if (retval != ERROR_OK) - { - free(padding); - return retval; /* abort operation */ + if (retval != ERROR_OK) { + /* abort operation */ + goto done; } if (written != NULL) - *written += run_size; /* add run size to total written counter */ + *written += run_size; /* add run size to total written counter */ } +done: + free(sections); free(padding); return retval; } int flash_write(struct target *target, struct image *image, - uint32_t *written, int erase) + uint32_t *written, int erase) { return flash_write_unlock(target, image, written, erase, false); } -/** - * Invalidates cached flash state which a target can change as it runs. - * - * @param target The target being resumed - * - * OpenOCD caches some flash state for brief periods. For example, a sector - * that is protected must be unprotected before OpenOCD tries to write it, - * Also, a sector that's not erased must be erased before it's written. - * - * As a rule, OpenOCD and target firmware can both modify the flash, so when - * a target starts running, OpenOCD needs to invalidate its cached state. - */ -void nor_resume(struct target *target) +struct flash_sector *alloc_block_array(uint32_t offset, uint32_t size, int num_blocks) { - struct flash_bank *bank; - - for (bank = flash_banks; bank; bank = bank->next) { - int i; - - if (bank->target != target) - continue; + int i; - for (i = 0; i < bank->num_sectors; i++) { - struct flash_sector *sector = bank->sectors + i; + struct flash_sector *array = calloc(num_blocks, sizeof(struct flash_sector)); + if (array == NULL) + return NULL; - sector->is_erased = -1; - sector->is_protected = -1; - } + for (i = 0; i < num_blocks; i++) { + array[i].offset = offset; + array[i].size = size; + array[i].is_erased = -1; + array[i].is_protected = -1; + offset += size; } + + return array; }