summaryrefslogtreecommitdiff
path: root/src/flash
diff options
context:
space:
mode:
authoroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>2008-04-03 14:00:17 +0000
committeroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>2008-04-03 14:00:17 +0000
commitd3f0549f08d8aac36143bca9e7f7e1308383b7c2 (patch)
treeb1057d6e4ebd1e1dbe560bac2f2330f11d47827b /src/flash
parent349f62f74fdc1278efd00a0e6301e1a0199cc128 (diff)
downloadopenocd+libswd-d3f0549f08d8aac36143bca9e7f7e1308383b7c2.tar.gz
openocd+libswd-d3f0549f08d8aac36143bca9e7f7e1308383b7c2.tar.bz2
openocd+libswd-d3f0549f08d8aac36143bca9e7f7e1308383b7c2.tar.xz
openocd+libswd-d3f0549f08d8aac36143bca9e7f7e1308383b7c2.zip
- Work on fixing erase check. Many implementations are plain broken.
Wrote a default flash erase check fn which uses CFI's target algorithm w/fallback to memory reads. - "flash info" no longer prints erase status as it is stale. - "flash erase_check" now prints erase status. erase check can take a *long* time. Work in progress - arm7/9 with seperate srst & trst now supports reset init/halt after a power outage. arm7/9 no longer makes any assumptions about state of target when reset is asserted. - fixes for srst & trst capable arm7/9 with reset init/halt - prepare_reset_halt retired. This code needs to be inside assert_reset anyway - haven't been able to get stm32 write algorithm to work. Fallback flash write does work. Haven't found a version of openocd trunk where this works. - added target_free_all_working_areas_restore() which can let be of restoring backups. This is needed when asserting reset as the target must be assumed to be an unknown state. Added some comments to working areas API - str9 reset script fixes - some guidelines - fixed dangling callbacks upon reset timeout git-svn-id: svn://svn.berlios.de/openocd/trunk@536 b42882b7-edfa-0310-969c-e2dbd0fdcd60
Diffstat (limited to 'src/flash')
-rw-r--r--src/flash/cfi.c119
-rw-r--r--src/flash/cfi.h2
-rw-r--r--src/flash/flash.c264
-rw-r--r--src/flash/stm32x.c51
4 files changed, 241 insertions, 195 deletions
diff --git a/src/flash/cfi.c b/src/flash/cfi.c
index 6aad04a7..3d830709 100644
--- a/src/flash/cfi.c
+++ b/src/flash/cfi.c
@@ -45,7 +45,6 @@ int cfi_protect(struct flash_bank_s *bank, int set, int first, int last);
int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
int cfi_probe(struct flash_bank_s *bank);
int cfi_auto_probe(struct flash_bank_s *bank);
-int cfi_erase_check(struct flash_bank_s *bank);
int cfi_protect_check(struct flash_bank_s *bank);
int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size);
@@ -67,7 +66,7 @@ flash_driver_t cfi_flash =
.write = cfi_write,
.probe = cfi_probe,
.auto_probe = cfi_auto_probe,
- .erase_check = cfi_erase_check,
+ .erase_check = default_flash_blank_check,
.protect_check = cfi_protect_check,
.info = cfi_info
};
@@ -627,7 +626,6 @@ int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **
bank->driver_priv = cfi_info;
cfi_info->write_algorithm = NULL;
- cfi_info->erase_check_algorithm = NULL;
cfi_info->x16_as_x8 = 0;
cfi_info->jedec_probe = 0;
@@ -2092,121 +2090,6 @@ int cfi_auto_probe(struct flash_bank_s *bank)
return cfi_probe(bank);
}
-int cfi_erase_check(struct flash_bank_s *bank)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- target_t *target = bank->target;
- int i;
- int retval;
-
- if (bank->target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (!cfi_info->erase_check_algorithm)
- {
- u32 erase_check_code[] =
- {
- 0xe4d03001, /* ldrb r3, [r0], #1 */
- 0xe0022003, /* and r2, r2, r3 */
- 0xe2511001, /* subs r1, r1, #1 */
- 0x1afffffb, /* b -4 */
- 0xeafffffe /* b 0 */
- };
-
- /* make sure we have a working area */
- if (target_alloc_working_area(target, 20, &cfi_info->erase_check_algorithm) != ERROR_OK)
- {
- LOG_WARNING("no working area available, falling back to slow memory reads");
- }
- else
- {
- u8 erase_check_code_buf[5 * 4];
-
- for (i = 0; i < 5; i++)
- target_buffer_set_u32(target, erase_check_code_buf + (i*4), erase_check_code[i]);
-
- /* write algorithm code to working area */
- target->type->write_memory(target, cfi_info->erase_check_algorithm->address, 4, 5, erase_check_code_buf);
- }
- }
-
- if (!cfi_info->erase_check_algorithm)
- {
- u32 *buffer = malloc(4096);
-
- for (i = 0; i < bank->num_sectors; i++)
- {
- u32 address = bank->base + bank->sectors[i].offset;
- u32 size = bank->sectors[i].size;
- u32 check = 0xffffffffU;
- int erased = 1;
-
- while (size > 0)
- {
- u32 thisrun_size = (size > 4096) ? 4096 : size;
- int j;
-
- target->type->read_memory(target, address, 4, thisrun_size / 4, (u8*)buffer);
-
- for (j = 0; j < thisrun_size / 4; j++)
- check &= buffer[j];
-
- if (check != 0xffffffff)
- {
- erased = 0;
- break;
- }
-
- size -= thisrun_size;
- address += thisrun_size;
- }
-
- bank->sectors[i].is_erased = erased;
- }
-
- free(buffer);
- }
- else
- {
- for (i = 0; i < bank->num_sectors; i++)
- {
- u32 address = bank->base + bank->sectors[i].offset;
- u32 size = bank->sectors[i].size;
-
- reg_param_t reg_params[3];
- armv4_5_algorithm_t armv4_5_info;
-
- armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
- armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
- armv4_5_info.core_state = ARMV4_5_STATE_ARM;
-
- init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
- buf_set_u32(reg_params[0].value, 0, 32, address);
-
- init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
- buf_set_u32(reg_params[1].value, 0, 32, size);
-
- init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
- buf_set_u32(reg_params[2].value, 0, 32, 0xff);
-
- if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params, cfi_info->erase_check_algorithm->address, cfi_info->erase_check_algorithm->address + 0x10, 10000, &armv4_5_info)) != ERROR_OK)
- return ERROR_FLASH_OPERATION_FAILED;
-
- if (buf_get_u32(reg_params[2].value, 0, 32) == 0xff)
- bank->sectors[i].is_erased = 1;
- else
- bank->sectors[i].is_erased = 0;
-
- destroy_reg_param(&reg_params[0]);
- destroy_reg_param(&reg_params[1]);
- destroy_reg_param(&reg_params[2]);
- }
- }
-
- return ERROR_OK;
-}
int cfi_intel_protect_check(struct flash_bank_s *bank)
{
diff --git a/src/flash/cfi.h b/src/flash/cfi.h
index 8099c4ea..803678d4 100644
--- a/src/flash/cfi.h
+++ b/src/flash/cfi.h
@@ -26,7 +26,7 @@
typedef struct cfi_flash_bank_s
{
working_area_t *write_algorithm;
- working_area_t *erase_check_algorithm;
+
int x16_as_x8;
int jedec_probe;
diff --git a/src/flash/flash.c b/src/flash/flash.c
index d5159b97..96077258 100644
--- a/src/flash/flash.c
+++ b/src/flash/flash.c
@@ -28,6 +28,10 @@
#include "fileio.h"
#include "image.h"
#include "log.h"
+#include "armv4_5.h"
+#include "algorithm.h"
+#include "binarybuffer.h"
+#include "armv7m.h"
#include <string.h>
#include <unistd.h>
@@ -336,22 +340,12 @@ int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char
/* attempt auto probe */
if ((retval = p->driver->auto_probe(p)) != ERROR_OK)
return retval;
-
- if ((retval = p->driver->erase_check(p)) != ERROR_OK)
- return retval;
command_print(cmd_ctx, "#%i: %s at 0x%8.8x, size 0x%8.8x, buswidth %i, chipwidth %i",
i, p->driver->name, p->base, p->size, p->bus_width, p->chip_width);
for (j = 0; j < p->num_sectors; j++)
{
- char *erase_state, *protect_state;
-
- if (p->sectors[j].is_erased == 0)
- erase_state = "not erased";
- else if (p->sectors[j].is_erased == 1)
- erase_state = "erased";
- else
- erase_state = "erase state unknown";
+ char *protect_state;
if (p->sectors[j].is_protected == 0)
protect_state = "not protected";
@@ -360,9 +354,9 @@ int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char
else
protect_state = "protection state unknown";
- command_print(cmd_ctx, "\t#%i: 0x%8.8x (0x%x %ikB) %s, %s",
+ command_print(cmd_ctx, "\t#%i: 0x%8.8x (0x%x %ikB) %s",
j, p->sectors[j].offset, p->sectors[j].size, p->sectors[j].size>>10,
- erase_state, protect_state);
+ protect_state);
}
*buf = '\0'; /* initialize buffer, otherwise it migh contain garbage if driver function fails */
@@ -425,6 +419,7 @@ int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cm
p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
if (p)
{
+ int j;
if ((retval = p->driver->erase_check(p)) == ERROR_OK)
{
command_print(cmd_ctx, "successfully checked erase state", p->driver->name, p->base);
@@ -434,6 +429,23 @@ int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cm
command_print(cmd_ctx, "unknown error when checking erase state of flash bank #%s at 0x%8.8x",
args[0], p->base);
}
+
+ for (j = 0; j < p->num_sectors; j++)
+ {
+ char *erase_state;
+
+ if (p->sectors[j].is_erased == 0)
+ erase_state = "not erased";
+ else if (p->sectors[j].is_erased == 1)
+ erase_state = "erased";
+ else
+ erase_state = "erase state unknown";
+
+ command_print(cmd_ctx, "\t#%i: 0x%8.8x (0x%x %ikB) %s",
+ j, p->sectors[j].offset, p->sectors[j].size, p->sectors[j].size>>10,
+ erase_state);
+ }
+
}
return ERROR_OK;
@@ -1068,32 +1080,224 @@ int default_flash_blank_check(struct flash_bank_s *bank)
return ERROR_TARGET_NOT_HALTED;
}
+ int retval;
+ int fast_check=0;
+ working_area_t *erase_check_algorithm;
+#if 0
+ /* FIX! doesn't work yet... */
+ /*
+ char test(char *a, int len, char t)
+ {
+ int i=0;
+
+ for (i=0; i<len; i++)
+ {
+ t&=a[i];
+
+ }
+ }
+
+ $ arm-elf-gcc -c -mthumb -O3 test.c
+
+ $ arm-elf-objdump --disassemble test.o
- for (i = 0; i < bank->num_sectors; i++)
+ test.o: file format elf32-littlearm
+
+ Disassembly of section .text:
+
+ 00000000 <test>:
+ 0: b510 push {r4, lr}
+ 2: 0612 lsl r2, r2, #24
+ 4: 1c04 mov r4, r0 (add r4, r0, #0)
+ 6: 0e10 lsr r0, r2, #24
+ 8: 2200 mov r2, #0
+ a: 2900 cmp r1, #0
+ c: dd04 ble 18 <test+0x18>
+ e: 5ca3 ldrb r3, [r4, r2]
+ 10: 3201 add r2, #1
+ 12: 4018 and r0, r3
+ 14: 428a cmp r2, r1
+ 16: dbfa blt e <test+0xe>
+ 18: bd10 pop {r4, pc}
+ 1a: 46c0 nop (mov r8, r8)
+
+
+ */
+ u16 erase_check_code[] =
{
- int j;
- bank->sectors[i].is_erased = 1;
+ 0x0612,// lsl r2, r2, #24
+ 0x1c04,// mov r4, r0 (add r4, r0, #0)
+ 0x0e10,// lsr r0, r2, #24
+ 0x2200,// mov r2, #0
+ 0x2900,// cmp r1, #0
+ 0xdd04,// ble 18 <test+0x18>
+ 0x5ca3,// ldrb r3, [r4, r2]
+ 0x3201,// add r2, #1
+ 0x4018,// and r0, r3
+ 0x428a,// cmp r2, r1
+ 0xdbfa,// blt e <test+0xe>
+ 0x46c0,// nop (mov r8, r8)
+
+ };
+
+
+
+ /* make sure we have a working area */
+ if (target_alloc_working_area(target, ((sizeof(erase_check_code)+3)/4)*4, &erase_check_algorithm) != ERROR_OK)
+ {
+ erase_check_algorithm = NULL;
+ }
+
+ if (erase_check_algorithm)
+ {
+ u8 erase_check_code_buf[((sizeof(erase_check_code)+3)/4)*4];
+ LOG_DEBUG("Running fast flash erase check");
- for (j=0; j<bank->sectors[i].size; j+=buffer_size)
+ for (i = 0; i < sizeof(erase_check_code)/sizeof(*erase_check_code); i++)
+ target_buffer_set_u16(target, erase_check_code_buf + (i*2), erase_check_code[i]);
+
+ /* write algorithm code to working area */
+ if ((retval=target->type->write_memory(target, erase_check_algorithm->address, 2, sizeof(erase_check_code)/sizeof(*erase_check_code), erase_check_code_buf))==ERROR_OK)
{
- int chunk;
- int retval;
- chunk=buffer_size;
- if (chunk>(j-bank->sectors[i].size))
+ for (i = 0; i < bank->num_sectors; i++)
{
- chunk=(j-bank->sectors[i].size);
+ u32 address = bank->base + bank->sectors[i].offset;
+ u32 size = bank->sectors[i].size;
+
+ reg_param_t reg_params[3];
+ armv7m_algorithm_t arm_info;
+
+ arm_info.common_magic = ARMV7M_COMMON_MAGIC;
+ arm_info.core_mode = ARMV7M_MODE_ANY;
+ arm_info.core_state = ARMV7M_STATE_THUMB;
+
+ init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+ buf_set_u32(reg_params[0].value, 0, 32, address);
+
+ init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+ buf_set_u32(reg_params[1].value, 0, 32, size);
+
+ init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
+ buf_set_u32(reg_params[2].value, 0, 32, 0xff);
+
+ if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params, erase_check_algorithm->address,
+ erase_check_algorithm->address + sizeof(erase_check_code) - 2, 10000, &arm_info)) != ERROR_OK)
+ break;
+
+ if (buf_get_u32(reg_params[2].value, 0, 32) == 0xff)
+ bank->sectors[i].is_erased = 1;
+ else
+ bank->sectors[i].is_erased = 0;
+
+ destroy_reg_param(&reg_params[0]);
+ destroy_reg_param(&reg_params[1]);
+ destroy_reg_param(&reg_params[2]);
+ }
+ if (i == bank->num_sectors)
+ {
+ fast_check = 1;
}
+ }
+ target_free_working_area(target, erase_check_algorithm);
+ }
+#endif
+ if (!fast_check)
+ {
+ /* try ARM7 instead */
+
+ u32 erase_check_code[] =
+ {
+ 0xe4d03001, /* ldrb r3, [r0], #1 */
+ 0xe0022003, /* and r2, r2, r3 */
+ 0xe2511001, /* subs r1, r1, #1 */
+ 0x1afffffb, /* b -4 */
+ 0xeafffffe /* b 0 */
+ };
+
+ /* make sure we have a working area */
+ if (target_alloc_working_area(target, 20, &erase_check_algorithm) == ERROR_OK)
+ {
+ u8 erase_check_code_buf[5 * 4];
+
+ for (i = 0; i < 5; i++)
+ target_buffer_set_u32(target, erase_check_code_buf + (i*4), erase_check_code[i]);
+
+ /* write algorithm code to working area */
+ if ((retval=target->type->write_memory(target, erase_check_algorithm->address, 4, 5, erase_check_code_buf))==ERROR_OK)
+ {
+ for (i = 0; i < bank->num_sectors; i++)
+ {
+ u32 address = bank->base + bank->sectors[i].offset;
+ u32 size = bank->sectors[i].size;
- retval=target->type->read_memory(target, bank->base + bank->sectors[i].offset, 4, chunk/4, buffer);
- if (retval!=ERROR_OK)
- return retval;
-
- for (nBytes = 0; nBytes < chunk; nBytes++)
+ reg_param_t reg_params[3];
+ armv4_5_algorithm_t armv4_5_info;
+
+ armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
+ armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
+ armv4_5_info.core_state = ARMV4_5_STATE_ARM;
+
+ init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+ buf_set_u32(reg_params[0].value, 0, 32, address);
+
+ init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+ buf_set_u32(reg_params[1].value, 0, 32, size);
+
+ init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
+ buf_set_u32(reg_params[2].value, 0, 32, 0xff);
+
+ if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params,
+ erase_check_algorithm->address, erase_check_algorithm->address + 0x10, 10000, &armv4_5_info)) != ERROR_OK)
+ break;
+
+ if (buf_get_u32(reg_params[2].value, 0, 32) == 0xff)
+ bank->sectors[i].is_erased = 1;
+ else
+ bank->sectors[i].is_erased = 0;
+
+ destroy_reg_param(&reg_params[0]);
+ destroy_reg_param(&reg_params[1]);
+ destroy_reg_param(&reg_params[2]);
+ }
+ if (i == bank->num_sectors)
+ {
+ fast_check = 1;
+ }
+ }
+ target_free_working_area(target, erase_check_algorithm);
+ }
+ }
+
+
+ if (!fast_check)
+ {
+ LOG_USER("Running slow fallback erase check - add working memory");
+ for (i = 0; i < bank->num_sectors; i++)
+ {
+ int j;
+ bank->sectors[i].is_erased = 1;
+
+ for (j=0; j<bank->sectors[i].size; j+=buffer_size)
{
- if (buffer[nBytes] != 0xFF)
+ int chunk;
+ int retval;
+ chunk=buffer_size;
+ if (chunk>(j-bank->sectors[i].size))
{
- bank->sectors[i].is_erased = 0;
- break;
+ chunk=(j-bank->sectors[i].size);
+ }
+
+ retval=target->type->read_memory(target, bank->base + bank->sectors[i].offset + j, 4, chunk/4, buffer);
+ if (retval!=ERROR_OK)
+ return retval;
+
+ for (nBytes = 0; nBytes < chunk; nBytes++)
+ {
+ if (buffer[nBytes] != 0xFF)
+ {
+ bank->sectors[i].is_erased = 0;
+ break;
+ }
}
}
}
diff --git a/src/flash/stm32x.c b/src/flash/stm32x.c
index 7e26ece3..e981310a 100644
--- a/src/flash/stm32x.c
+++ b/src/flash/stm32x.c
@@ -43,7 +43,6 @@ int stm32x_probe(struct flash_bank_s *bank);
int stm32x_auto_probe(struct flash_bank_s *bank);
int stm32x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int stm32x_protect_check(struct flash_bank_s *bank);
-int stm32x_erase_check(struct flash_bank_s *bank);
int stm32x_info(struct flash_bank_s *bank, char *buf, int buf_size);
int stm32x_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
@@ -62,7 +61,7 @@ flash_driver_t stm32x_flash =
.write = stm32x_write,
.probe = stm32x_probe,
.auto_probe = stm32x_auto_probe,
- .erase_check = stm32x_erase_check,
+ .erase_check = default_flash_blank_check,
.protect_check = stm32x_protect_check,
.info = stm32x_info
};
@@ -278,43 +277,6 @@ int stm32x_write_options(struct flash_bank_s *bank)
return ERROR_OK;
}
-int stm32x_blank_check(struct flash_bank_s *bank, int first, int last)
-{
- target_t *target = bank->target;
- u8 *buffer;
- int i;
- int nBytes;
-
- if ((first < 0) || (last > bank->num_sectors))
- return ERROR_FLASH_SECTOR_INVALID;
-
- if (target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- buffer = malloc(256);
-
- for (i = first; i <= last; i++)
- {
- bank->sectors[i].is_erased = 1;
-
- target->type->read_memory(target, bank->base + bank->sectors[i].offset, 4, 256/4, buffer);
-
- for (nBytes = 0; nBytes < 256; nBytes++)
- {
- if (buffer[nBytes] != 0xFF)
- {
- bank->sectors[i].is_erased = 0;
- break;
- }
- }
- }
-
- free(buffer);
-
- return ERROR_OK;
-}
int stm32x_protect_check(struct flash_bank_s *bank)
{
@@ -477,7 +439,8 @@ int stm32x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 co
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
};
- target_write_buffer(target, stm32x_info->write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code);
+ if ((retval=target_write_buffer(target, stm32x_info->write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code))!=ERROR_OK)
+ return retval;
/* memory buffer */
while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
@@ -507,7 +470,8 @@ int stm32x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 co
{
u32 thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
- target_write_buffer(target, source->address, thisrun_count * 2, buffer);
+ if ((retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer))!=ERROR_OK)
+ break;
buf_set_u32(reg_params[0].value, 0, 32, source->address);
buf_set_u32(reg_params[1].value, 0, 32, address);
@@ -707,11 +671,6 @@ int stm32x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd,
return ERROR_OK;
}
-int stm32x_erase_check(struct flash_bank_s *bank)
-{
- return stm32x_blank_check(bank, 0, bank->num_sectors - 1);
-}
-
int stm32x_info(struct flash_bank_s *bank, char *buf, int buf_size)
{
snprintf(buf, buf_size, "stm32x flash driver info" );