/***************************************************************************
* Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> *
- * Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
+ * Copyright (C) 2007-2010 Øyvind Harboe <oyvind.harboe@zylin.com> *
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
* *
* primarily support access from Tcl scripts or from GDB.
*/
-struct flash_bank *flash_banks;
+static struct flash_bank *flash_banks;
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)
+ return ERROR_FAIL;
+
+ /* force "set" to 0/1 */
+ set = !!set;
+
+ /*
+ * Filter out what trivial nonsense we can, so drivers don't have to.
+ *
+ * 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.
+ *
+ * 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.
+ */
retval = bank->driver->protect(bank, set, first, last);
if (retval != ERROR_OK)
{
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)
{
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;
/* 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)
{
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++;
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)",
/* 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;
- 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 */
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;
+
+ /* 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, section, section_offset,
+ 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 */
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;
{
/* 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)
{
- 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;