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)
+ {
+ 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)
return NULL;
}
-struct flash_bank *get_flash_bank_by_num(int num)
+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;
+ return retval;
}
- return p;
+ *bank = p;
+ return ERROR_OK;
}
/* lookup flash bank by address */
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,
while ((run_address + run_size - 1 < c->base + c->size - 1)
&& (section_last + 1 < image->num_sections))
{
- if (sections[section_last + 1]->base_address < (run_address + run_size))
+ /* sections are sorted */
+ assert(sections[section_last + 1]->base_address >= c->base);
+ if (sections[section_last + 1]->base_address >= (c->base + c->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.
- */
- break;
+ /* Done with this bank */
+ break;
}
/* FIXME This needlessly touches sectors BETWEEN the
* flash programming could fail due to alignment issues
* attempt to rebuild a consecutive buffer for the flash loader */
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 += sections[++section_last]->size;
run_size += pad_bytes;
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??
- */
- 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));
- run_size = c->base + c->size - run_address;
- }
+ assert (run_address + run_size - 1 <= c->base + c->size - 1);
/* If we're applying any sector automagic, then pad this
* (maybe-combined) segment to the end of its last sector.
* #¤%#"%¤% 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);
+ intptr_t diff = (intptr_t)sections[section] - (intptr_t)image->sections;
+ int t_section_num = diff / sizeof(struct imageection);
+ 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);
if ((retval = image_read_section(image, t_section_num, section_offset,
size_read, buffer + buffer_size, &size_read)) != ERROR_OK || size_read == 0)
{
{
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_bank *bank;
-
- for (bank = flash_banks; bank; bank = bank->next) {
- int i;
-
- if (bank->target != target)
- continue;
-
- for (i = 0; i < bank->num_sectors; i++) {
- struct flash_sector *sector = bank->sectors + i;
-
- sector->is_erased = -1;
- sector->is_protected = -1;
- }
- }
-}