Pavel Chromy: memory leak in at91sam7 flash driver, possible incorrect pointer conversion in gpnvm command handling,

uninitialized buffer issue in handle_flash_info_command in flash.c, some formatting.

git-svn-id: svn://svn.berlios.de/openocd/trunk@446 b42882b7-edfa-0310-969c-e2dbd0fdcd60
This commit is contained in:
oharboe 2008-03-05 13:27:50 +00:00
parent 6d95014674
commit f14f84ca1e
5 changed files with 123 additions and 162 deletions

View File

@ -77,7 +77,7 @@ flash_driver_t at91sam7_flash =
.protect = at91sam7_protect,
.write = at91sam7_write,
.probe = at91sam7_probe,
.auto_probe = at91sam7_auto_probe,
.auto_probe = at91sam7_probe,
.erase_check = at91sam7_erase_check,
.protect_check = at91sam7_protect_check,
.info = at91sam7_info
@ -145,7 +145,7 @@ u32 at91sam7_get_flash_status(flash_bank_t *bank, u8 flashplane)
return fsr;
}
/** Read clock configuration and set at91sam7_info->usec_clocks*/
/* Read clock configuration and set at91sam7_info->usec_clocks*/
void at91sam7_read_clock_info(flash_bank_t *bank)
{
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
@ -180,7 +180,7 @@ void at91sam7_read_clock_info(flash_bank_t *bank)
case 2: /* Reserved */
break;
case 3: /* PLL Clock */
case 3: /* PLL Clock */
if (mcfr & CKGR_MCFR_MAINRDY)
{
target_read_u32(target, CKGR_PLLR, &pllr);
@ -313,6 +313,9 @@ int at91sam7_read_part_info(struct flash_bank_s *bank)
target_t *target = bank->target;
u32 cidr, status;
int sectornum;
if (at91sam7_info->cidr != 0)
return ERROR_OK; /* already probed, multiple probes may cause memory leak, not allowed */
/* Read and parse chip identification register */
target_read_u32(target, DBGU_CIDR, &cidr);
@ -553,9 +556,8 @@ int at91sam7_read_part_info(struct flash_bank_s *bank)
return ERROR_OK;
}
WARNING("at91sam7 flash only tested for AT91SAM7Sxx series");
return ERROR_OK;
WARNING("at91sam7 flash only tested for AT91SAM7Sxx series");
return ERROR_OK;
}
int at91sam7_erase_check(struct flash_bank_s *bank)
@ -579,22 +581,16 @@ int at91sam7_protect_check(struct flash_bank_s *bank)
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
if (at91sam7_info->cidr == 0)
{
return ERROR_FLASH_BANK_NOT_PROBED;
}
if (bank->target->state != TARGET_HALTED)
{
return ERROR_TARGET_NOT_HALTED;
}
if (at91sam7_info->cidr == 0)
{
at91sam7_read_part_info(bank);
}
if (at91sam7_info->cidr == 0)
{
WARNING("Cannot identify target as an AT91SAM");
return ERROR_FLASH_OPERATION_FAILED;
}
for (flashplane=0;flashplane<at91sam7_info->num_planes;flashplane++)
{
status = at91sam7_get_flash_status(bank, flashplane);
@ -619,7 +615,6 @@ int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, ch
at91sam7_info = malloc(sizeof(at91sam7_flash_bank_t));
bank->driver_priv = at91sam7_info;
at91sam7_info->probed = 0;
/* part wasn't probed for info yet */
at91sam7_info->cidr = 0;
@ -634,22 +629,16 @@ int at91sam7_erase(struct flash_bank_s *bank, int first, int last)
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
u8 flashplane;
if (at91sam7_info->cidr == 0)
{
return ERROR_FLASH_BANK_NOT_PROBED;
}
if (bank->target->state != TARGET_HALTED)
{
return ERROR_TARGET_NOT_HALTED;
}
if (at91sam7_info->cidr == 0)
{
at91sam7_read_part_info(bank);
}
if (at91sam7_info->cidr == 0)
{
WARNING("Cannot identify target as an AT91SAM");
return ERROR_FLASH_OPERATION_FAILED;
}
if ((first < 0) || (last < first) || (last >= bank->num_sectors))
{
if ((first == 0) && (last == (at91sam7_info->num_lockbits-1)))
@ -683,6 +672,11 @@ int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last)
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
if (at91sam7_info->cidr == 0)
{
return ERROR_FLASH_BANK_NOT_PROBED;
}
if (bank->target->state != TARGET_HALTED)
{
return ERROR_TARGET_NOT_HALTED;
@ -693,17 +687,6 @@ int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last)
return ERROR_FLASH_SECTOR_INVALID;
}
if (at91sam7_info->cidr == 0)
{
at91sam7_read_part_info(bank);
}
if (at91sam7_info->cidr == 0)
{
WARNING("Cannot identify target as an AT91SAM");
return ERROR_FLASH_OPERATION_FAILED;
}
at91sam7_read_clock_info(bank);
for (lockregion=first;lockregion<=last;lockregion++)
@ -738,22 +721,16 @@ int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
u32 first_page, last_page, pagen, buffer_pos;
u8 flashplane;
if (at91sam7_info->cidr == 0)
{
return ERROR_FLASH_BANK_NOT_PROBED;
}
if (bank->target->state != TARGET_HALTED)
{
return ERROR_TARGET_NOT_HALTED;
}
if (at91sam7_info->cidr == 0)
{
at91sam7_read_part_info(bank);
}
if (at91sam7_info->cidr == 0)
{
WARNING("Cannot identify target as an AT91SAM");
return ERROR_FLASH_OPERATION_FAILED;
}
if (offset + count > bank->size)
return ERROR_FLASH_DST_OUT_OF_BANK;
@ -809,56 +786,34 @@ int at91sam7_probe(struct flash_bank_s *bank)
* if this is an at91sam7, it has the configured flash
*/
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
at91sam7_info->probed = 0;
int retval;
if (at91sam7_info->cidr != 0)
{
return ERROR_OK; /* already probed */
}
if (bank->target->state != TARGET_HALTED)
{
return ERROR_TARGET_NOT_HALTED;
}
if (at91sam7_info->cidr == 0)
{
at91sam7_read_part_info(bank);
}
if (at91sam7_info->cidr == 0)
{
WARNING("Cannot identify target as an AT91SAM");
return ERROR_FLASH_OPERATION_FAILED;
}
at91sam7_info->probed = 1;
retval = at91sam7_read_part_info(bank);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
int at91sam7_auto_probe(struct flash_bank_s *bank)
{
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
if (at91sam7_info->probed)
return ERROR_OK;
return at91sam7_probe(bank);
}
int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size)
{
int printed, flashplane;
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
if (bank->target->state != TARGET_HALTED)
{
return ERROR_TARGET_NOT_HALTED;
}
at91sam7_read_part_info(bank);
if (at91sam7_info->cidr == 0)
{
printed = snprintf(buf, buf_size, "Cannot identify target as an AT91SAM\n");
buf += printed;
buf_size -= printed;
return ERROR_FLASH_OPERATION_FAILED;
return ERROR_FLASH_BANK_NOT_PROBED;
}
printed = snprintf(buf, buf_size, "\nat91sam7 information: Chip is %s\n",at91sam7_info->target_name);
@ -894,7 +849,7 @@ int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size)
buf_size -= printed;
}
printed = snprintf(buf, buf_size, "securitybit: %i, nvmbits: 0x%1.1x\n", at91sam7_info->securitybit, at91sam7_info->nvmbits);
printed = snprintf(buf, buf_size, "securitybit: %i, nvmbits(%i): 0x%1.1x\n", at91sam7_info->securitybit, at91sam7_info->num_nvmbits, at91sam7_info->nvmbits);
buf += printed;
buf_size -= printed;
@ -919,6 +874,7 @@ int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd,
u32 status;
char *value;
at91sam7_flash_bank_t *at91sam7_info;
int retval;
if (argc < 3)
{
@ -926,38 +882,19 @@ int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd,
return ERROR_OK;
}
bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
bank = get_flash_bank_by_num_noprobe(strtoul(args[0], NULL, 0));
bit = atoi(args[1]);
value = args[2];
if (!bank)
if (bank == NULL)
{
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
return ERROR_OK;
return ERROR_FLASH_BANK_INVALID;
}
at91sam7_info = bank->driver_priv;
if (bank->target->state != TARGET_HALTED)
if (bank->driver != &at91sam7_flash)
{
return ERROR_TARGET_NOT_HALTED;
}
if (at91sam7_info->cidr == 0)
{
at91sam7_read_part_info(bank);
}
if (at91sam7_info->cidr == 0)
{
WARNING("Cannot identify target as an AT91SAM");
return ERROR_FLASH_OPERATION_FAILED;
}
if ((bit<0) || (at91sam7_info->num_nvmbits <= bit))
{
command_print(cmd_ctx, "gpnvm bit '#%s' is out of bounds for target %s", args[1],at91sam7_info->target_name);
return ERROR_OK;
command_print(cmd_ctx, "not an at91sam7 flash bank '%s'", args[0]);
return ERROR_FLASH_BANK_INVALID;
}
if (strcmp(value, "set") == 0)
@ -973,6 +910,28 @@ int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd,
return ERROR_COMMAND_SYNTAX_ERROR;
}
at91sam7_info = bank->driver_priv;
if (bank->target->state != TARGET_HALTED)
{
ERROR("target has to be halted to perform flash operation");
return ERROR_TARGET_NOT_HALTED;
}
if (at91sam7_info->cidr == 0)
{
retval = at91sam7_read_part_info(bank);
if (retval != ERROR_OK) {
return retval;
}
}
if ((bit<0) || (at91sam7_info->num_nvmbits <= bit))
{
command_print(cmd_ctx, "gpnvm bit '#%s' is out of bounds for target %s", args[1],at91sam7_info->target_name);
return ERROR_OK;
}
/* Configure the flash controller timing */
at91sam7_read_clock_info(bank);
at91sam7_set_flash_mode(bank, 0, FMR_TIMING_NVBITS);

View File

@ -59,9 +59,7 @@ typedef struct at91sam7_flash_bank_s
/* main clock status */
u8 mck_valid;
u32 mck_freq;
int probed;
} at91sam7_flash_bank_t;
/* AT91SAM7 control registers */

View File

@ -93,7 +93,7 @@ static int flash_driver_write(struct flash_bank_s *bank, u8 *buffer, u32 offset,
retval=bank->driver->write(bank, buffer, offset, count);
if (retval!=ERROR_OK)
{
ERROR("error writing to flash at address 0x%08x at offset 0x%8.8x", bank->base, offset);
ERROR("error writing to flash at address 0x%08x at offset 0x%8.8x (%d)", bank->base, offset, retval);
}
return retval;
@ -106,7 +106,7 @@ static int flash_driver_erase(struct flash_bank_s *bank, int first, int last)
retval=bank->driver->erase(bank, first, last);
if (retval!=ERROR_OK)
{
ERROR("failed erasing sectors %d to %d", first, last);
ERROR("failed erasing sectors %d to %d (%d)", first, last, retval);
}
return retval;
@ -119,7 +119,7 @@ int flash_driver_protect(struct flash_bank_s *bank, int set, int first, int last
retval=bank->driver->protect(bank, set, first, last);
if (retval!=ERROR_OK)
{
ERROR("failed setting protection for areas %d to %d", first, last);
ERROR("failed setting protection for areas %d to %d (%d)", first, last, retval);
}
return retval;
@ -311,6 +311,7 @@ int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char
flash_bank_t *p;
int i = 0;
int j = 0;
int retval;
if (argc != 1)
{
@ -351,8 +352,11 @@ int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char
erase_state, protect_state);
}
p->driver->info(p, buf, 1024);
*buf = '\0'; /* initialize buffer, otherwise it migh contain garbage if driver function fails */
retval = p->driver->info(p, buf, sizeof(buf));
command_print(cmd_ctx, "%s", buf);
if (retval != ERROR_OK)
ERROR("error retrieving flash info (%d)", retval);
}
}
@ -918,7 +922,6 @@ int handle_flash_auto_erase_command(struct command_context_s *cmd_ctx, char *cmd
if (argc != 1)
{
return ERROR_COMMAND_SYNTAX_ERROR;
}
if (strcmp(args[0], "on") == 0)

View File

@ -80,6 +80,7 @@ extern void flash_set_dirty(void);
extern int flash_get_bank_count();
extern flash_bank_t *get_flash_bank_by_num(int num);
extern flash_bank_t *get_flash_bank_by_num_noprobe(int num);
extern flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr);
#define ERROR_FLASH_BANK_INVALID (-900)

View File

@ -77,7 +77,7 @@ flash_driver_t stellaris_flash =
struct {
u32 partno;
char *partname;
char *partname;
} StellarisParts[] =
{
{0x01,"LM3S101"},
@ -269,9 +269,9 @@ int stellaris_info(struct flash_bank_s *bank, char *buf, int buf_size)
{
device_class = 0;
}
printed = snprintf(buf, buf_size, "\nLMI Stellaris information: Chip is class %i(%s) %s v%c.%i\n",
device_class, StellarisClassname[device_class], stellaris_info->target_name,
'A' + (stellaris_info->did0>>8)&0xFF, (stellaris_info->did0)&0xFF);
printed = snprintf(buf, buf_size, "\nLMI Stellaris information: Chip is class %i(%s) %s v%c.%i\n",
device_class, StellarisClassname[device_class], stellaris_info->target_name,
'A' + (stellaris_info->did0>>8)&0xFF, (stellaris_info->did0)&0xFF);
buf += printed;
buf_size -= printed;
@ -352,7 +352,7 @@ void stellaris_read_clock_info(flash_bank_t *bank)
stellaris_info->mck_freq = mainfreq;
/* Forget old flash timing */
stellaris_set_flash_mode(bank,0);
stellaris_set_flash_mode(bank,0);
}
/* Setup the timimg registers */
@ -407,7 +407,7 @@ int stellaris_read_part_info(struct flash_bank_s *bank)
{
stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
target_t *target = bank->target;
u32 did0,did1, ver, fam, status;
u32 did0,did1, ver, fam, status;
int i;
/* Read and parse chip identification register */
@ -417,10 +417,10 @@ int stellaris_read_part_info(struct flash_bank_s *bank)
target_read_u32(target, SCB_BASE|DC1, &stellaris_info->dc1);
DEBUG("did0 0x%x, did1 0x%x, dc0 0x%x, dc1 0x%x",did0, did1, stellaris_info->dc0,stellaris_info->dc1);
ver = did0 >> 28;
if((ver != 0) && (ver != 1))
ver = did0 >> 28;
if((ver != 0) && (ver != 1))
{
WARNING("Unknown did0 version, cannot identify target");
WARNING("Unknown did0 version, cannot identify target");
return ERROR_FLASH_OPERATION_FAILED;
}
@ -430,11 +430,11 @@ int stellaris_read_part_info(struct flash_bank_s *bank)
return ERROR_FLASH_OPERATION_FAILED;
}
ver = did1 >> 28;
fam = (did1 >> 24) & 0xF;
if(((ver != 0) && (ver != 1)) || (fam != 0))
ver = did1 >> 28;
fam = (did1 >> 24) & 0xF;
if(((ver != 0) && (ver != 1)) || (fam != 0))
{
WARNING("Unknown did1 version/family, cannot positively identify target as a Stellaris");
WARNING("Unknown did1 version/family, cannot positively identify target as a Stellaris");
}
for (i=0;StellarisParts[i].partno;i++)
@ -464,7 +464,7 @@ int stellaris_read_part_info(struct flash_bank_s *bank)
}
/***************************************************************************
* flash operations *
* flash operations *
***************************************************************************/
int stellaris_erase_check(struct flash_bank_s *bank)
@ -527,7 +527,7 @@ int stellaris_erase(struct flash_bank_s *bank, int first, int last)
if (stellaris_info->did1 == 0)
{
WARNING("Cannot identify target as Stellaris");
WARNING("Cannot identify target as Stellaris");
return ERROR_FLASH_OPERATION_FAILED;
}
@ -546,7 +546,7 @@ int stellaris_erase(struct flash_bank_s *bank, int first, int last)
if ((first == 0) && (last == (stellaris_info->num_pages-1)))
{
target_write_u32(target, FLASH_FMA, 0);
target_write_u32(target, FLASH_FMA, 0);
target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);
/* Wait until erase complete */
do
@ -555,18 +555,18 @@ int stellaris_erase(struct flash_bank_s *bank, int first, int last)
}
while(flash_fmc & FMC_MERASE);
/* if device has > 128k, then second erase cycle is needed */
if(stellaris_info->num_pages * stellaris_info->pagesize > 0x20000)
{
target_write_u32(target, FLASH_FMA, 0x20000);
target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);
/* Wait until erase complete */
do
{
target_read_u32(target, FLASH_FMC, &flash_fmc);
}
while(flash_fmc & FMC_MERASE);
}
/* if device has > 128k, then second erase cycle is needed */
if(stellaris_info->num_pages * stellaris_info->pagesize > 0x20000)
{
target_write_u32(target, FLASH_FMA, 0x20000);
target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);
/* Wait until erase complete */
do
{
target_read_u32(target, FLASH_FMC, &flash_fmc);
}
while(flash_fmc & FMC_MERASE);
}
return ERROR_OK;
}
@ -687,26 +687,26 @@ u8 stellaris_write_code[] =
r6 = bytes written
r7 = temp reg
*/
0x07,0x4B, /* ldr r3,pFLASH_CTRL_BASE */
0x08,0x4C, /* ldr r4,FLASHWRITECMD */
0x01,0x25, /* movs r5, 1 */
0x00,0x26, /* movs r6, #0 */
0x07,0x4B, /* ldr r3,pFLASH_CTRL_BASE */
0x08,0x4C, /* ldr r4,FLASHWRITECMD */
0x01,0x25, /* movs r5, 1 */
0x00,0x26, /* movs r6, #0 */
/* mainloop: */
0x19,0x60, /* str r1, [r3, #0] */
0x87,0x59, /* ldr r7, [r0, r6] */
0x5F,0x60, /* str r7, [r3, #4] */
0x9C,0x60, /* str r4, [r3, #8] */
0x19,0x60, /* str r1, [r3, #0] */
0x87,0x59, /* ldr r7, [r0, r6] */
0x5F,0x60, /* str r7, [r3, #4] */
0x9C,0x60, /* str r4, [r3, #8] */
/* waitloop: */
0x9F,0x68, /* ldr r7, [r3, #8] */
0x2F,0x42, /* tst r7, r5 */
0xFC,0xD1, /* bne waitloop */
0x04,0x31, /* adds r1, r1, #4 */
0x04,0x36, /* adds r6, r6, #4 */
0x96,0x42, /* cmp r6, r2 */
0xF4,0xD1, /* bne mainloop */
0x00,0xBE, /* bkpt #0 */
0x9F,0x68, /* ldr r7, [r3, #8] */
0x2F,0x42, /* tst r7, r5 */
0xFC,0xD1, /* bne waitloop */
0x04,0x31, /* adds r1, r1, #4 */
0x04,0x36, /* adds r6, r6, #4 */
0x96,0x42, /* cmp r6, r2 */
0xF4,0xD1, /* bne mainloop */
0x00,0xBE, /* bkpt #0 */
/* pFLASH_CTRL_BASE: */
0x00,0xD0,0x0F,0x40, /* .word 0x400FD000 */
0x00,0xD0,0x0F,0x40, /* .word 0x400FD000 */
/* FLASHWRITECMD: */
0x01,0x00,0x42,0xA4 /* .word 0xA4420001 */
};