NOR: add FIXMEs for writing ones
[openocd.git] / src / flash / nor / core.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> *
3 * Copyright (C) 2007,2008 √ė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 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 #include <flash/common.h>
27 #include <flash/nor/core.h>
28 #include <flash/nor/imp.h>
29 #include <target/image.h>
30
31
32 struct flash_bank *flash_banks;
33
34 int flash_driver_erase(struct flash_bank *bank, int first, int last)
35 {
36 int retval;
37
38 retval = bank->driver->erase(bank, first, last);
39 if (retval != ERROR_OK)
40 {
41 LOG_ERROR("failed erasing sectors %d to %d (%d)", first, last, retval);
42 }
43
44 return retval;
45 }
46
47 int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
48 {
49 int retval;
50
51 retval = bank->driver->protect(bank, set, first, last);
52 if (retval != ERROR_OK)
53 {
54 LOG_ERROR("failed setting protection for areas %d to %d (%d)", first, last, retval);
55 }
56
57 return retval;
58 }
59
60 int flash_driver_write(struct flash_bank *bank,
61 uint8_t *buffer, uint32_t offset, uint32_t count)
62 {
63 int retval;
64
65 retval = bank->driver->write(bank, buffer, offset, count);
66 if (retval != ERROR_OK)
67 {
68 LOG_ERROR("error writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32 " (%d)",
69 bank->base, offset, retval);
70 }
71
72 return retval;
73 }
74
75 void flash_bank_add(struct flash_bank *bank)
76 {
77 /* put flash bank in linked list */
78 unsigned bank_num = 0;
79 if (flash_banks)
80 {
81 /* find last flash bank */
82 struct flash_bank *p = flash_banks;
83 while (NULL != p->next)
84 {
85 bank_num += 1;
86 p = p->next;
87 }
88 p->next = bank;
89 bank_num += 1;
90 }
91 else
92 flash_banks = bank;
93
94 bank->bank_number = bank_num;
95 }
96
97 struct flash_bank *flash_bank_list(void)
98 {
99 return flash_banks;
100 }
101
102 struct flash_bank *get_flash_bank_by_num_noprobe(int num)
103 {
104 struct flash_bank *p;
105 int i = 0;
106
107 for (p = flash_banks; p; p = p->next)
108 {
109 if (i++ == num)
110 {
111 return p;
112 }
113 }
114 LOG_ERROR("flash bank %d does not exist", num);
115 return NULL;
116 }
117
118 int flash_get_bank_count(void)
119 {
120 struct flash_bank *p;
121 int i = 0;
122 for (p = flash_banks; p; p = p->next)
123 {
124 i++;
125 }
126 return i;
127 }
128
129 struct flash_bank *get_flash_bank_by_name(const char *name)
130 {
131 unsigned requested = get_flash_name_index(name);
132 unsigned found = 0;
133
134 struct flash_bank *bank;
135 for (bank = flash_banks; NULL != bank; bank = bank->next)
136 {
137 if (strcmp(bank->name, name) == 0)
138 return bank;
139 if (!flash_driver_name_matches(bank->driver->name, name))
140 continue;
141 if (++found < requested)
142 continue;
143 return bank;
144 }
145 return NULL;
146 }
147
148 struct flash_bank *get_flash_bank_by_num(int num)
149 {
150 struct flash_bank *p = get_flash_bank_by_num_noprobe(num);
151 int retval;
152
153 if (p == NULL)
154 return NULL;
155
156 retval = p->driver->auto_probe(p);
157
158 if (retval != ERROR_OK)
159 {
160 LOG_ERROR("auto_probe failed %d\n", retval);
161 return NULL;
162 }
163 return p;
164 }
165
166 /* lookup flash bank by address */
167 struct flash_bank *get_flash_bank_by_addr(struct target *target, uint32_t addr)
168 {
169 struct flash_bank *c;
170
171 /* cycle through bank list */
172 for (c = flash_banks; c; c = c->next)
173 {
174 int retval;
175 retval = c->driver->auto_probe(c);
176
177 if (retval != ERROR_OK)
178 {
179 LOG_ERROR("auto_probe failed %d\n", retval);
180 return NULL;
181 }
182 /* check whether address belongs to this flash bank */
183 if ((addr >= c->base) && (addr <= c->base + (c->size - 1)) && target == c->target)
184 return c;
185 }
186 LOG_ERROR("No flash at address 0x%08" PRIx32 "\n", addr);
187 return NULL;
188 }
189
190 int default_flash_mem_blank_check(struct flash_bank *bank)
191 {
192 struct target *target = bank->target;
193 const int buffer_size = 1024;
194 int i;
195 uint32_t nBytes;
196 int retval = ERROR_OK;
197
198 if (bank->target->state != TARGET_HALTED)
199 {
200 LOG_ERROR("Target not halted");
201 return ERROR_TARGET_NOT_HALTED;
202 }
203
204 uint8_t *buffer = malloc(buffer_size);
205
206 for (i = 0; i < bank->num_sectors; i++)
207 {
208 uint32_t j;
209 bank->sectors[i].is_erased = 1;
210
211 for (j = 0; j < bank->sectors[i].size; j += buffer_size)
212 {
213 uint32_t chunk;
214 chunk = buffer_size;
215 if (chunk > (j - bank->sectors[i].size))
216 {
217 chunk = (j - bank->sectors[i].size);
218 }
219
220 retval = target_read_memory(target, bank->base + bank->sectors[i].offset + j, 4, chunk/4, buffer);
221 if (retval != ERROR_OK)
222 {
223 goto done;
224 }
225
226 for (nBytes = 0; nBytes < chunk; nBytes++)
227 {
228 if (buffer[nBytes] != 0xFF)
229 {
230 bank->sectors[i].is_erased = 0;
231 break;
232 }
233 }
234 }
235 }
236
237 done:
238 free(buffer);
239
240 return retval;
241 }
242
243 int default_flash_blank_check(struct flash_bank *bank)
244 {
245 struct target *target = bank->target;
246 int i;
247 int retval;
248 int fast_check = 0;
249 uint32_t blank;
250
251 if (bank->target->state != TARGET_HALTED)
252 {
253 LOG_ERROR("Target not halted");
254 return ERROR_TARGET_NOT_HALTED;
255 }
256
257 for (i = 0; i < bank->num_sectors; i++)
258 {
259 uint32_t address = bank->base + bank->sectors[i].offset;
260 uint32_t size = bank->sectors[i].size;
261
262 if ((retval = target_blank_check_memory(target, address, size, &blank)) != ERROR_OK)
263 {
264 fast_check = 0;
265 break;
266 }
267 if (blank == 0xFF)
268 bank->sectors[i].is_erased = 1;
269 else
270 bank->sectors[i].is_erased = 0;
271 fast_check = 1;
272 }
273
274 if (!fast_check)
275 {
276 LOG_USER("Running slow fallback erase check - add working memory");
277 return default_flash_mem_blank_check(bank);
278 }
279
280 return ERROR_OK;
281 }
282
283 /* erase given flash region, selects proper bank according to target and address */
284 static int flash_iterate_address_range(struct target *target,
285 uint32_t addr, uint32_t length,
286 int (*callback)(struct flash_bank *bank, int first, int last))
287 {
288 struct flash_bank *c;
289 uint32_t last_addr = addr + length; /* first address AFTER end */
290 int first = -1;
291 int last = -1;
292 int i;
293
294 if ((c = get_flash_bank_by_addr(target, addr)) == NULL)
295 return ERROR_FLASH_DST_OUT_OF_BANK; /* no corresponding bank found */
296
297 if (c->size == 0 || c->num_sectors == 0)
298 {
299 LOG_ERROR("Bank is invalid");
300 return ERROR_FLASH_BANK_INVALID;
301 }
302
303 if (length == 0)
304 {
305 /* special case, erase whole bank when length is zero */
306 if (addr != c->base)
307 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
308
309 return callback(c, 0, c->num_sectors - 1);
310 }
311
312 /* check whether it all fits in this bank */
313 if (addr + length - 1 > c->base + c->size - 1)
314 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
315
316 /** @todo: handle erasures that cross into adjacent banks */
317
318 addr -= c->base;
319 last_addr -= c->base;
320
321 for (i = 0; i < c->num_sectors; i++)
322 {
323 struct flash_sector *f = c->sectors + i;
324
325 /* start only on a sector boundary */
326 if (first < 0) {
327 /* is this the first sector? */
328 if (addr == f->offset)
329 first = i;
330 else if (addr < f->offset)
331 break;
332 }
333
334 /* is this (also?) the last sector? */
335 if (last_addr == f->offset + f->size) {
336 last = i;
337 break;
338 }
339
340 /* MUST finish on a sector boundary */
341 if (last_addr <= f->offset)
342 break;
343 }
344
345 /* invalid start or end address? */
346 if (first == -1 || last == -1) {
347 LOG_ERROR("address range 0x%8.8x .. 0x%8.8x "
348 "is not sector-aligned",
349 (unsigned) (c->base + addr),
350 (unsigned) (last_addr - 1));
351 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
352 }
353
354 /* The NOR driver may trim this range down, based on
355 * whether or not a given sector is already erased.
356 *
357 * REVISIT should *we* trim it... ?
358 */
359 return callback(c, first, last);
360 }
361
362 int flash_erase_address_range(struct target *target,
363 uint32_t addr, uint32_t length)
364 {
365 return flash_iterate_address_range(target,
366 addr, length, &flash_driver_erase);
367 }
368
369 static int flash_driver_unprotect(struct flash_bank *bank, int first, int last)
370 {
371 return flash_driver_protect(bank, 0, first, last);
372 }
373
374 static int flash_unlock_address_range(struct target *target, uint32_t addr, uint32_t length)
375 {
376 return flash_iterate_address_range(target,
377 addr, length, &flash_driver_unprotect);
378 }
379
380 int flash_write_unlock(struct target *target, struct image *image,
381 uint32_t *written, int erase, bool unlock)
382 {
383 int retval = ERROR_OK;
384
385 int section;
386 uint32_t section_offset;
387 struct flash_bank *c;
388 int *padding;
389
390 section = 0;
391 section_offset = 0;
392
393 if (written)
394 *written = 0;
395
396 if (erase)
397 {
398 /* assume all sectors need erasing - stops any problems
399 * when flash_write is called multiple times */
400
401 flash_set_dirty();
402 }
403
404 /* allocate padding array */
405 padding = calloc(image->num_sections, sizeof(*padding));
406
407 /* loop until we reach end of the image */
408 while (section < image->num_sections)
409 {
410 uint32_t buffer_size;
411 uint8_t *buffer;
412 int section_first;
413 int section_last;
414 uint32_t run_address = image->sections[section].base_address + section_offset;
415 uint32_t run_size = image->sections[section].size - section_offset;
416 int pad_bytes = 0;
417
418 if (image->sections[section].size == 0)
419 {
420 LOG_WARNING("empty section %d", section);
421 section++;
422 section_offset = 0;
423 continue;
424 }
425
426 /* find the corresponding flash bank */
427 if ((c = get_flash_bank_by_addr(target, run_address)) == NULL)
428 {
429 section++; /* and skip it */
430 section_offset = 0;
431 continue;
432 }
433
434 /* collect consecutive sections which fall into the same bank */
435 section_first = section;
436 section_last = section;
437 padding[section] = 0;
438 while ((run_address + run_size - 1 < c->base + c->size - 1)
439 && (section_last + 1 < image->num_sections))
440 {
441 if (image->sections[section_last + 1].base_address < (run_address + run_size))
442 {
443 LOG_DEBUG("section %d out of order "
444 "(surprising, but supported)",
445 section_last + 1);
446 /* REVISIT this can break with autoerase ...
447 * clobbering data after it's written.
448 */
449 break;
450 }
451
452 /* FIXME This needlessly touches sectors BETWEEN the
453 * sections it's writing. Without auto erase, it just
454 * writes ones. That WILL INVALIDATE data in cases
455 * like Stellaris Tempest chips, corrupting internal
456 * ECC codes; and at least FreeScale suggests issues
457 * with that approach (in HC11 documentation).
458 *
459 * With auto erase enabled, data in those sectors will
460 * be needlessly destroyed; and some of the limited
461 * number of flash erase cycles will be wasted...
462 *
463 * In both cases, the extra writes slow things down.
464 */
465
466 /* if we have multiple sections within our image, flash programming could fail due to alignment issues
467 * attempt to rebuild a consecutive buffer for the flash loader */
468 pad_bytes = (image->sections[section_last + 1].base_address) - (run_address + run_size);
469 if ((run_address + run_size + pad_bytes) > (c->base + c->size))
470 break;
471 padding[section_last] = pad_bytes;
472 run_size += image->sections[++section_last].size;
473 run_size += pad_bytes;
474
475 LOG_INFO("Padding image section %d with %d bytes", section_last-1, pad_bytes);
476 }
477
478 /* fit the run into bank constraints */
479 if (run_address + run_size - 1 > c->base + c->size - 1)
480 {
481 /* REVISIT isn't this superfluous, given the while()
482 * loop conditions above??
483 */
484 LOG_WARNING("writing %d bytes only - as image section is %d bytes and bank is only %d bytes", \
485 (int)(c->base + c->size - run_address), (int)(run_size), (int)(c->size));
486 run_size = c->base + c->size - run_address;
487 }
488
489 /* If we're applying any sector automagic, then pad this
490 * (maybe-combined) segment to the end of its last sector.
491 */
492 if (unlock || erase) {
493 int sector;
494 uint32_t offset_start = run_address - c->base;
495 uint32_t offset_end = offset_start + run_size;
496 uint32_t end = offset_end, delta;
497
498 for (sector = 0; sector < c->num_sectors; sector++) {
499 end = c->sectors[sector].offset
500 + c->sectors[sector].size;
501 if (offset_end <= end)
502 break;
503 }
504
505 delta = end - offset_end;
506 padding[section_last] += delta;
507 run_size += delta;
508 }
509
510 /* allocate buffer */
511 buffer = malloc(run_size);
512 buffer_size = 0;
513
514 /* read sections to the buffer */
515 while (buffer_size < run_size)
516 {
517 size_t size_read;
518
519 size_read = run_size - buffer_size;
520 if (size_read > image->sections[section].size - section_offset)
521 size_read = image->sections[section].size - section_offset;
522
523 if ((retval = image_read_section(image, section, section_offset,
524 size_read, buffer + buffer_size, &size_read)) != ERROR_OK || size_read == 0)
525 {
526 free(buffer);
527 free(padding);
528 return retval;
529 }
530
531 /* see if we need to pad the section */
532 while (padding[section]--)
533 (buffer + buffer_size)[size_read++] = 0xff;
534
535 buffer_size += size_read;
536 section_offset += size_read;
537
538 if (section_offset >= image->sections[section].size)
539 {
540 section++;
541 section_offset = 0;
542 }
543 }
544
545 retval = ERROR_OK;
546
547 if (unlock)
548 {
549 retval = flash_unlock_address_range(target, run_address, run_size);
550 }
551 if (retval == ERROR_OK)
552 {
553 if (erase)
554 {
555 /* calculate and erase sectors */
556 retval = flash_erase_address_range(target, run_address, run_size);
557 }
558 }
559
560 if (retval == ERROR_OK)
561 {
562 /* write flash sectors */
563 retval = flash_driver_write(c, buffer, run_address - c->base, run_size);
564 }
565
566 free(buffer);
567
568 if (retval != ERROR_OK)
569 {
570 free(padding);
571 return retval; /* abort operation */
572 }
573
574 if (written != NULL)
575 *written += run_size; /* add run size to total written counter */
576 }
577
578 free(padding);
579
580 return retval;
581 }
582
583 int flash_write(struct target *target, struct image *image,
584 uint32_t *written, int erase)
585 {
586 return flash_write_unlock(target, image, written, erase, false);
587 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)