]> git.sur5r.net Git - openocd/blob - src/flash/nor/core.c
flash: Constify write buffer
[openocd] / src / flash / nor / core.c
1 /***************************************************************************
2  *   Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de>              *
3  *   Copyright (C) 2007-2010 Øyvind Harboe <oyvind.harboe@zylin.com>       *
4  *   Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk>           *
5  *   Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net>             *
6  *   Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com>       *
7  *                                                                         *
8  *   This program is free software; you can redistribute it and/or modify  *
9  *   it under the terms of the GNU General Public License as published by  *
10  *   the Free Software Foundation; either version 2 of the License, or     *
11  *   (at your option) any later version.                                   *
12  *                                                                         *
13  *   This program is distributed in the hope that it will be useful,       *
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
16  *   GNU General Public License for more details.                          *
17  *                                                                         *
18  *   You should have received a copy of the GNU General Public License     *
19  *   along with this program; if not, write to the                         *
20  *   Free Software Foundation, Inc.,                                       *
21  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
22  ***************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 #include <flash/common.h>
28 #include <flash/nor/core.h>
29 #include <flash/nor/imp.h>
30 #include <target/image.h>
31
32 /**
33  * @file
34  * Upper level of NOR flash framework.
35  * The lower level interfaces are to drivers.  These upper level ones
36  * primarily support access from Tcl scripts or from GDB.
37  */
38
39 static struct flash_bank *flash_banks;
40
41 int flash_driver_erase(struct flash_bank *bank, int first, int last)
42 {
43         int retval;
44
45         retval = bank->driver->erase(bank, first, last);
46         if (retval != ERROR_OK)
47                 LOG_ERROR("failed erasing sectors %d to %d", first, last);
48
49         return retval;
50 }
51
52 int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
53 {
54         int retval;
55
56         /* callers may not supply illegal parameters ... */
57         if (first < 0 || first > last || last >= bank->num_sectors) {
58                 LOG_ERROR("illegal sector range");
59                 return ERROR_FAIL;
60         }
61
62         /* force "set" to 0/1 */
63         set = !!set;
64
65         /* DANGER!
66          *
67          * We must not use any cached information about protection state!!!!
68          *
69          * There are a million things that could change the protect state:
70          *
71          * the target could have reset, power cycled, been hot plugged,
72          * the application could have run, etc.
73          *
74          * Drivers only receive valid sector range.
75          */
76         retval = bank->driver->protect(bank, set, first, last);
77         if (retval != ERROR_OK)
78                 LOG_ERROR("failed setting protection for areas %d to %d", first, last);
79
80         return retval;
81 }
82
83 int flash_driver_write(struct flash_bank *bank,
84         uint8_t *buffer, uint32_t offset, uint32_t count)
85 {
86         int retval;
87
88         retval = bank->driver->write(bank, buffer, offset, count);
89         if (retval != ERROR_OK) {
90                 LOG_ERROR(
91                         "error writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32,
92                         bank->base,
93                         offset);
94         }
95
96         return retval;
97 }
98
99 int flash_driver_read(struct flash_bank *bank,
100         uint8_t *buffer, uint32_t offset, uint32_t count)
101 {
102         int retval;
103
104         LOG_DEBUG("call flash_driver_read()");
105
106         retval = bank->driver->read(bank, buffer, offset, count);
107         if (retval != ERROR_OK) {
108                 LOG_ERROR(
109                         "error reading to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32,
110                         bank->base,
111                         offset);
112         }
113
114         return retval;
115 }
116
117 int default_flash_read(struct flash_bank *bank,
118         uint8_t *buffer, uint32_t offset, uint32_t count)
119 {
120         return target_read_buffer(bank->target, offset + bank->base, count, buffer);
121 }
122
123 void flash_bank_add(struct flash_bank *bank)
124 {
125         /* put flash bank in linked list */
126         unsigned bank_num = 0;
127         if (flash_banks) {
128                 /* find last flash bank */
129                 struct flash_bank *p = flash_banks;
130                 while (NULL != p->next) {
131                         bank_num += 1;
132                         p = p->next;
133                 }
134                 p->next = bank;
135                 bank_num += 1;
136         } else
137                 flash_banks = bank;
138
139         bank->bank_number = bank_num;
140 }
141
142 struct flash_bank *flash_bank_list(void)
143 {
144         return flash_banks;
145 }
146
147 struct flash_bank *get_flash_bank_by_num_noprobe(int num)
148 {
149         struct flash_bank *p;
150         int i = 0;
151
152         for (p = flash_banks; p; p = p->next) {
153                 if (i++ == num)
154                         return p;
155         }
156         LOG_ERROR("flash bank %d does not exist", num);
157         return NULL;
158 }
159
160 int flash_get_bank_count(void)
161 {
162         struct flash_bank *p;
163         int i = 0;
164         for (p = flash_banks; p; p = p->next)
165                 i++;
166         return i;
167 }
168
169 struct flash_bank *get_flash_bank_by_name_noprobe(const char *name)
170 {
171         unsigned requested = get_flash_name_index(name);
172         unsigned found = 0;
173
174         struct flash_bank *bank;
175         for (bank = flash_banks; NULL != bank; bank = bank->next) {
176                 if (strcmp(bank->name, name) == 0)
177                         return bank;
178                 if (!flash_driver_name_matches(bank->driver->name, name))
179                         continue;
180                 if (++found < requested)
181                         continue;
182                 return bank;
183         }
184         return NULL;
185 }
186
187 int get_flash_bank_by_name(const char *name, struct flash_bank **bank_result)
188 {
189         struct flash_bank *bank;
190         int retval;
191
192         bank = get_flash_bank_by_name_noprobe(name);
193         if (bank != NULL) {
194                 retval = bank->driver->auto_probe(bank);
195
196                 if (retval != ERROR_OK) {
197                         LOG_ERROR("auto_probe failed");
198                         return retval;
199                 }
200         }
201
202         *bank_result = bank;
203         return ERROR_OK;
204 }
205
206 int get_flash_bank_by_num(int num, struct flash_bank **bank)
207 {
208         struct flash_bank *p = get_flash_bank_by_num_noprobe(num);
209         int retval;
210
211         if (p == NULL)
212                 return ERROR_FAIL;
213
214         retval = p->driver->auto_probe(p);
215
216         if (retval != ERROR_OK) {
217                 LOG_ERROR("auto_probe failed");
218                 return retval;
219         }
220         *bank = p;
221         return ERROR_OK;
222 }
223
224 /* lookup flash bank by address, bank not found is success, but
225  * result_bank is set to NULL. */
226 int get_flash_bank_by_addr(struct target *target,
227         uint32_t addr,
228         bool check,
229         struct flash_bank **result_bank)
230 {
231         struct flash_bank *c;
232
233         /* cycle through bank list */
234         for (c = flash_banks; c; c = c->next) {
235                 if (c->target != target)
236                         continue;
237
238                 int retval;
239                 retval = c->driver->auto_probe(c);
240
241                 if (retval != ERROR_OK) {
242                         LOG_ERROR("auto_probe failed");
243                         return retval;
244                 }
245                 /* check whether address belongs to this flash bank */
246                 if ((addr >= c->base) && (addr <= c->base + (c->size - 1))) {
247                         *result_bank = c;
248                         return ERROR_OK;
249                 }
250         }
251         *result_bank = NULL;
252         if (check) {
253                 LOG_ERROR("No flash at address 0x%08" PRIx32, addr);
254                 return ERROR_FAIL;
255         }
256         return ERROR_OK;
257 }
258
259 static int default_flash_mem_blank_check(struct flash_bank *bank)
260 {
261         struct target *target = bank->target;
262         const int buffer_size = 1024;
263         int i;
264         uint32_t nBytes;
265         int retval = ERROR_OK;
266
267         if (bank->target->state != TARGET_HALTED) {
268                 LOG_ERROR("Target not halted");
269                 return ERROR_TARGET_NOT_HALTED;
270         }
271
272         uint8_t *buffer = malloc(buffer_size);
273
274         for (i = 0; i < bank->num_sectors; i++) {
275                 uint32_t j;
276                 bank->sectors[i].is_erased = 1;
277
278                 for (j = 0; j < bank->sectors[i].size; j += buffer_size) {
279                         uint32_t chunk;
280                         chunk = buffer_size;
281                         if (chunk > (j - bank->sectors[i].size))
282                                 chunk = (j - bank->sectors[i].size);
283
284                         retval = target_read_memory(target,
285                                         bank->base + bank->sectors[i].offset + j,
286                                         4,
287                                         chunk/4,
288                                         buffer);
289                         if (retval != ERROR_OK)
290                                 goto done;
291
292                         for (nBytes = 0; nBytes < chunk; nBytes++) {
293                                 if (buffer[nBytes] != 0xFF) {
294                                         bank->sectors[i].is_erased = 0;
295                                         break;
296                                 }
297                         }
298                 }
299         }
300
301 done:
302         free(buffer);
303
304         return retval;
305 }
306
307 int default_flash_blank_check(struct flash_bank *bank)
308 {
309         struct target *target = bank->target;
310         int i;
311         int retval;
312         int fast_check = 0;
313         uint32_t blank;
314
315         if (bank->target->state != TARGET_HALTED) {
316                 LOG_ERROR("Target not halted");
317                 return ERROR_TARGET_NOT_HALTED;
318         }
319
320         for (i = 0; i < bank->num_sectors; i++) {
321                 uint32_t address = bank->base + bank->sectors[i].offset;
322                 uint32_t size = bank->sectors[i].size;
323
324                 retval = target_blank_check_memory(target, address, size, &blank);
325                 if (retval != ERROR_OK) {
326                         fast_check = 0;
327                         break;
328                 }
329                 if (blank == 0xFF)
330                         bank->sectors[i].is_erased = 1;
331                 else
332                         bank->sectors[i].is_erased = 0;
333                 fast_check = 1;
334         }
335
336         if (!fast_check) {
337                 LOG_USER("Running slow fallback erase check - add working memory");
338                 return default_flash_mem_blank_check(bank);
339         }
340
341         return ERROR_OK;
342 }
343
344 /* Manipulate given flash region, selecting the bank according to target
345  * and address.  Maps an address range to a set of sectors, and issues
346  * the callback() on that set ... e.g. to erase or unprotect its members.
347  *
348  * (Note a current bad assumption:  that protection operates on the same
349  * size sectors as erase operations use.)
350  *
351  * The "pad_reason" parameter is a kind of boolean:  when it's NULL, the
352  * range must fit those sectors exactly.  This is clearly safe; it can't
353  * erase data which the caller said to leave alone, for example.  If it's
354  * non-NULL, rather than failing, extra data in the first and/or last
355  * sectors will be added to the range, and that reason string is used when
356  * warning about those additions.
357  */
358 static int flash_iterate_address_range_inner(struct target *target,
359         char *pad_reason, uint32_t addr, uint32_t length,
360         int (*callback)(struct flash_bank *bank, int first, int last))
361 {
362         struct flash_bank *c;
363         uint32_t last_addr = addr + length;     /* first address AFTER end */
364         int first = -1;
365         int last = -1;
366         int i;
367
368         int retval = get_flash_bank_by_addr(target, addr, true, &c);
369         if (retval != ERROR_OK)
370                 return retval;
371
372         if (c->size == 0 || c->num_sectors == 0) {
373                 LOG_ERROR("Bank is invalid");
374                 return ERROR_FLASH_BANK_INVALID;
375         }
376
377         if (length == 0) {
378                 /* special case, erase whole bank when length is zero */
379                 if (addr != c->base) {
380                         LOG_ERROR("Whole bank access must start at beginning of bank.");
381                         return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
382                 }
383
384                 return callback(c, 0, c->num_sectors - 1);
385         }
386
387         /* check whether it all fits in this bank */
388         if (addr + length - 1 > c->base + c->size - 1) {
389                 LOG_ERROR("Flash access does not fit into bank.");
390                 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
391         }
392
393         /** @todo: handle erasures that cross into adjacent banks */
394
395         addr -= c->base;
396         last_addr -= c->base;
397
398         for (i = 0; i < c->num_sectors; i++) {
399                 struct flash_sector *f = c->sectors + i;
400                 uint32_t end = f->offset + f->size;
401
402                 /* start only on a sector boundary */
403                 if (first < 0) {
404                         /* scanned past the first sector? */
405                         if (addr < f->offset)
406                                 break;
407
408                         /* is this the first sector? */
409                         if (addr == f->offset)
410                                 first = i;
411
412                         /* Does this need head-padding?  If so, pad and warn;
413                          * or else force an error.
414                          *
415                          * Such padding can make trouble, since *WE* can't
416                          * ever know if that data was in use.  The warning
417                          * should help users sort out messes later.
418                          */
419                         else if (addr < end && pad_reason) {
420                                 /* FIXME say how many bytes (e.g. 80 KB) */
421                                 LOG_WARNING("Adding extra %s range, "
422                                         "%#8.8x to %#8.8x",
423                                         pad_reason,
424                                         (unsigned) f->offset,
425                                         (unsigned) addr - 1);
426                                 first = i;
427                         } else
428                                 continue;
429                 }
430
431                 /* is this (also?) the last sector? */
432                 if (last_addr == end) {
433                         last = i;
434                         break;
435                 }
436
437                 /* Does this need tail-padding?  If so, pad and warn;
438                  * or else force an error.
439                  */
440                 if (last_addr < end && pad_reason) {
441                         /* FIXME say how many bytes (e.g. 80 KB) */
442                         LOG_WARNING("Adding extra %s range, "
443                                 "%#8.8x to %#8.8x",
444                                 pad_reason,
445                                 (unsigned) last_addr,
446                                 (unsigned) end - 1);
447                         last = i;
448                         break;
449                 }
450
451                 /* MUST finish on a sector boundary */
452                 if (last_addr <= f->offset)
453                         break;
454         }
455
456         /* invalid start or end address? */
457         if (first == -1 || last == -1) {
458                 LOG_ERROR("address range 0x%8.8x .. 0x%8.8x "
459                         "is not sector-aligned",
460                         (unsigned) (c->base + addr),
461                         (unsigned) (c->base + last_addr - 1));
462                 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
463         }
464
465         /* The NOR driver may trim this range down, based on what
466          * sectors are already erased/unprotected.  GDB currently
467          * blocks such optimizations.
468          */
469         return callback(c, first, last);
470 }
471
472 /* The inner fn only handles a single bank, we could be spanning
473  * multiple chips.
474  */
475 static int flash_iterate_address_range(struct target *target,
476         char *pad_reason, uint32_t addr, uint32_t length,
477         int (*callback)(struct flash_bank *bank, int first, int last))
478 {
479         struct flash_bank *c;
480         int retval = ERROR_OK;
481
482         /* Danger! zero-length iterations means entire bank! */
483         do {
484                 retval = get_flash_bank_by_addr(target, addr, true, &c);
485                 if (retval != ERROR_OK)
486                         return retval;
487
488                 uint32_t cur_length = length;
489                 /* check whether it all fits in this bank */
490                 if (addr + length - 1 > c->base + c->size - 1) {
491                         LOG_DEBUG("iterating over more than one flash bank.");
492                         cur_length = c->base + c->size - addr;
493                 }
494                 retval = flash_iterate_address_range_inner(target,
495                                 pad_reason, addr, cur_length,
496                                 callback);
497                 if (retval != ERROR_OK)
498                         break;
499
500                 length -= cur_length;
501                 addr += cur_length;
502         } while (length > 0);
503
504         return retval;
505 }
506
507 int flash_erase_address_range(struct target *target,
508         bool pad, uint32_t addr, uint32_t length)
509 {
510         return flash_iterate_address_range(target, pad ? "erase" : NULL,
511                 addr, length, &flash_driver_erase);
512 }
513
514 static int flash_driver_unprotect(struct flash_bank *bank, int first, int last)
515 {
516         return flash_driver_protect(bank, 0, first, last);
517 }
518
519 int flash_unlock_address_range(struct target *target, uint32_t addr, uint32_t length)
520 {
521         /* By default, pad to sector boundaries ... the real issue here
522          * is that our (only) caller *permanently* removes protection,
523          * and doesn't restore it.
524          */
525         return flash_iterate_address_range(target, "unprotect",
526                 addr, length, &flash_driver_unprotect);
527 }
528
529 static int compare_section(const void *a, const void *b)
530 {
531         struct imagesection *b1, *b2;
532         b1 = *((struct imagesection **)a);
533         b2 = *((struct imagesection **)b);
534
535         if (b1->base_address == b2->base_address)
536                 return 0;
537         else if (b1->base_address > b2->base_address)
538                 return 1;
539         else
540                 return -1;
541 }
542
543 int flash_write_unlock(struct target *target, struct image *image,
544         uint32_t *written, int erase, bool unlock)
545 {
546         int retval = ERROR_OK;
547
548         int section;
549         uint32_t section_offset;
550         struct flash_bank *c;
551         int *padding;
552
553         section = 0;
554         section_offset = 0;
555
556         if (written)
557                 *written = 0;
558
559         if (erase) {
560                 /* assume all sectors need erasing - stops any problems
561                  * when flash_write is called multiple times */
562
563                 flash_set_dirty();
564         }
565
566         /* allocate padding array */
567         padding = calloc(image->num_sections, sizeof(*padding));
568
569         /* This fn requires all sections to be in ascending order of addresses,
570          * whereas an image can have sections out of order. */
571         struct imagesection **sections = malloc(sizeof(struct imagesection *) *
572                         image->num_sections);
573         int i;
574         for (i = 0; i < image->num_sections; i++)
575                 sections[i] = &image->sections[i];
576
577         qsort(sections, image->num_sections, sizeof(struct imagesection *),
578                 compare_section);
579
580         /* loop until we reach end of the image */
581         while (section < image->num_sections) {
582                 uint32_t buffer_size;
583                 uint8_t *buffer;
584                 int section_last;
585                 uint32_t run_address = sections[section]->base_address + section_offset;
586                 uint32_t run_size = sections[section]->size - section_offset;
587                 int pad_bytes = 0;
588
589                 if (sections[section]->size ==  0) {
590                         LOG_WARNING("empty section %d", section);
591                         section++;
592                         section_offset = 0;
593                         continue;
594                 }
595
596                 /* find the corresponding flash bank */
597                 retval = get_flash_bank_by_addr(target, run_address, false, &c);
598                 if (retval != ERROR_OK)
599                         goto done;
600                 if (c == NULL) {
601                         LOG_WARNING("no flash bank found for address %" PRIx32, run_address);
602                         section++;      /* and skip it */
603                         section_offset = 0;
604                         continue;
605                 }
606
607                 /* collect consecutive sections which fall into the same bank */
608                 section_last = section;
609                 padding[section] = 0;
610                 while ((run_address + run_size - 1 < c->base + c->size - 1) &&
611                                 (section_last + 1 < image->num_sections)) {
612                         /* sections are sorted */
613                         assert(sections[section_last + 1]->base_address >= c->base);
614                         if (sections[section_last + 1]->base_address >= (c->base + c->size)) {
615                                 /* Done with this bank */
616                                 break;
617                         }
618
619                         /* FIXME This needlessly touches sectors BETWEEN the
620                          * sections it's writing.  Without auto erase, it just
621                          * writes ones.  That WILL INVALIDATE data in cases
622                          * like Stellaris Tempest chips, corrupting internal
623                          * ECC codes; and at least FreeScale suggests issues
624                          * with that approach (in HC11 documentation).
625                          *
626                          * With auto erase enabled, data in those sectors will
627                          * be needlessly destroyed; and some of the limited
628                          * number of flash erase cycles will be wasted...
629                          *
630                          * In both cases, the extra writes slow things down.
631                          */
632
633                         /* if we have multiple sections within our image,
634                          * flash programming could fail due to alignment issues
635                          * attempt to rebuild a consecutive buffer for the flash loader */
636                         pad_bytes = (sections[section_last + 1]->base_address) - (run_address + run_size);
637                         padding[section_last] = pad_bytes;
638                         run_size += sections[++section_last]->size;
639                         run_size += pad_bytes;
640
641                         if (pad_bytes > 0)
642                                 LOG_INFO("Padding image section %d with %d bytes",
643                                         section_last-1,
644                                         pad_bytes);
645                 }
646
647                 if (run_address + run_size - 1 > c->base + c->size - 1) {
648                         /* If we have more than one flash chip back to back, then we limit
649                          * the current write operation to the current chip.
650                          */
651                         LOG_DEBUG("Truncate flash run size to the current flash chip.");
652
653                         run_size = c->base + c->size - run_address;
654                         assert(run_size > 0);
655                 }
656
657                 /* If we're applying any sector automagic, then pad this
658                  * (maybe-combined) segment to the end of its last sector.
659                  */
660                 if (unlock || erase) {
661                         int sector;
662                         uint32_t offset_start = run_address - c->base;
663                         uint32_t offset_end = offset_start + run_size;
664                         uint32_t end = offset_end, delta;
665
666                         for (sector = 0; sector < c->num_sectors; sector++) {
667                                 end = c->sectors[sector].offset
668                                         + c->sectors[sector].size;
669                                 if (offset_end <= end)
670                                         break;
671                         }
672
673                         delta = end - offset_end;
674                         padding[section_last] += delta;
675                         run_size += delta;
676                 }
677
678                 /* allocate buffer */
679                 buffer = malloc(run_size);
680                 if (buffer == NULL) {
681                         LOG_ERROR("Out of memory for flash bank buffer");
682                         retval = ERROR_FAIL;
683                         goto done;
684                 }
685                 buffer_size = 0;
686
687                 /* read sections to the buffer */
688                 while (buffer_size < run_size) {
689                         size_t size_read;
690
691                         size_read = run_size - buffer_size;
692                         if (size_read > sections[section]->size - section_offset)
693                                 size_read = sections[section]->size - section_offset;
694
695                         /* KLUDGE!
696                          *
697                          * #¤%#"%¤% we have to figure out the section # from the sorted
698                          * list of pointers to sections to invoke image_read_section()...
699                          */
700                         intptr_t diff = (intptr_t)sections[section] - (intptr_t)image->sections;
701                         int t_section_num = diff / sizeof(struct imagesection);
702
703                         LOG_DEBUG("image_read_section: section = %d, t_section_num = %d, "
704                                         "section_offset = %d, buffer_size = %d, size_read = %d",
705                                 (int)section, (int)t_section_num, (int)section_offset,
706                                 (int)buffer_size, (int)size_read);
707                         retval = image_read_section(image, t_section_num, section_offset,
708                                         size_read, buffer + buffer_size, &size_read);
709                         if (retval != ERROR_OK || size_read == 0) {
710                                 free(buffer);
711                                 goto done;
712                         }
713
714                         /* see if we need to pad the section */
715                         while (padding[section]--)
716                                 (buffer + buffer_size)[size_read++] = c->default_padded_value;
717
718                         buffer_size += size_read;
719                         section_offset += size_read;
720
721                         if (section_offset >= sections[section]->size) {
722                                 section++;
723                                 section_offset = 0;
724                         }
725                 }
726
727                 retval = ERROR_OK;
728
729                 if (unlock)
730                         retval = flash_unlock_address_range(target, run_address, run_size);
731                 if (retval == ERROR_OK) {
732                         if (erase) {
733                                 /* calculate and erase sectors */
734                                 retval = flash_erase_address_range(target,
735                                                 true, run_address, run_size);
736                         }
737                 }
738
739                 if (retval == ERROR_OK) {
740                         /* write flash sectors */
741                         retval = flash_driver_write(c, buffer, run_address - c->base, run_size);
742                 }
743
744                 free(buffer);
745
746                 if (retval != ERROR_OK) {
747                         /* abort operation */
748                         goto done;
749                 }
750
751                 if (written != NULL)
752                         *written += run_size;   /* add run size to total written counter */
753         }
754
755 done:
756         free(sections);
757         free(padding);
758
759         return retval;
760 }
761
762 int flash_write(struct target *target, struct image *image,
763         uint32_t *written, int erase)
764 {
765         return flash_write_unlock(target, image, written, erase, false);
766 }