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, .protect = at91sam7_protect,
.write = at91sam7_write, .write = at91sam7_write,
.probe = at91sam7_probe, .probe = at91sam7_probe,
.auto_probe = at91sam7_auto_probe, .auto_probe = at91sam7_probe,
.erase_check = at91sam7_erase_check, .erase_check = at91sam7_erase_check,
.protect_check = at91sam7_protect_check, .protect_check = at91sam7_protect_check,
.info = at91sam7_info .info = at91sam7_info
@ -145,7 +145,7 @@ u32 at91sam7_get_flash_status(flash_bank_t *bank, u8 flashplane)
return fsr; 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) void at91sam7_read_clock_info(flash_bank_t *bank)
{ {
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv; at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
@ -314,6 +314,9 @@ int at91sam7_read_part_info(struct flash_bank_s *bank)
u32 cidr, status; u32 cidr, status;
int sectornum; 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 */ /* Read and parse chip identification register */
target_read_u32(target, DBGU_CIDR, &cidr); target_read_u32(target, DBGU_CIDR, &cidr);
@ -554,7 +557,6 @@ int at91sam7_read_part_info(struct flash_bank_s *bank)
} }
WARNING("at91sam7 flash only tested for AT91SAM7Sxx series"); WARNING("at91sam7 flash only tested for AT91SAM7Sxx series");
return ERROR_OK; return ERROR_OK;
} }
@ -579,22 +581,16 @@ int at91sam7_protect_check(struct flash_bank_s *bank)
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv; 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) if (bank->target->state != TARGET_HALTED)
{ {
return ERROR_TARGET_NOT_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++) for (flashplane=0;flashplane<at91sam7_info->num_planes;flashplane++)
{ {
status = at91sam7_get_flash_status(bank, 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)); at91sam7_info = malloc(sizeof(at91sam7_flash_bank_t));
bank->driver_priv = at91sam7_info; bank->driver_priv = at91sam7_info;
at91sam7_info->probed = 0;
/* part wasn't probed for info yet */ /* part wasn't probed for info yet */
at91sam7_info->cidr = 0; 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; at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
u8 flashplane; u8 flashplane;
if (at91sam7_info->cidr == 0)
{
return ERROR_FLASH_BANK_NOT_PROBED;
}
if (bank->target->state != TARGET_HALTED) if (bank->target->state != TARGET_HALTED)
{ {
return ERROR_TARGET_NOT_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 < first) || (last >= bank->num_sectors))
{ {
if ((first == 0) && (last == (at91sam7_info->num_lockbits-1))) 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; 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) if (bank->target->state != TARGET_HALTED)
{ {
return ERROR_TARGET_NOT_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; 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); at91sam7_read_clock_info(bank);
for (lockregion=first;lockregion<=last;lockregion++) 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; u32 first_page, last_page, pagen, buffer_pos;
u8 flashplane; u8 flashplane;
if (at91sam7_info->cidr == 0)
{
return ERROR_FLASH_BANK_NOT_PROBED;
}
if (bank->target->state != TARGET_HALTED) if (bank->target->state != TARGET_HALTED)
{ {
return ERROR_TARGET_NOT_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) if (offset + count > bank->size)
return ERROR_FLASH_DST_OUT_OF_BANK; 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 * if this is an at91sam7, it has the configured flash
*/ */
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv; 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) if (bank->target->state != TARGET_HALTED)
{ {
return ERROR_TARGET_NOT_HALTED; return ERROR_TARGET_NOT_HALTED;
} }
if (at91sam7_info->cidr == 0) retval = at91sam7_read_part_info(bank);
{ if (retval != ERROR_OK)
at91sam7_read_part_info(bank); return retval;
}
if (at91sam7_info->cidr == 0)
{
WARNING("Cannot identify target as an AT91SAM");
return ERROR_FLASH_OPERATION_FAILED;
}
at91sam7_info->probed = 1;
return ERROR_OK; 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 at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size)
{ {
int printed, flashplane; int printed, flashplane;
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv; 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) if (at91sam7_info->cidr == 0)
{ {
printed = snprintf(buf, buf_size, "Cannot identify target as an AT91SAM\n"); return ERROR_FLASH_BANK_NOT_PROBED;
buf += printed;
buf_size -= printed;
return ERROR_FLASH_OPERATION_FAILED;
} }
printed = snprintf(buf, buf_size, "\nat91sam7 information: Chip is %s\n",at91sam7_info->target_name); 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; 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 += printed;
buf_size -= printed; buf_size -= printed;
@ -919,6 +874,7 @@ int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd,
u32 status; u32 status;
char *value; char *value;
at91sam7_flash_bank_t *at91sam7_info; at91sam7_flash_bank_t *at91sam7_info;
int retval;
if (argc < 3) if (argc < 3)
{ {
@ -926,38 +882,19 @@ int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd,
return ERROR_OK; 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]); bit = atoi(args[1]);
value = args[2]; value = args[2];
if (!bank) if (bank == NULL)
{ {
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); return ERROR_FLASH_BANK_INVALID;
return ERROR_OK;
} }
at91sam7_info = bank->driver_priv; if (bank->driver != &at91sam7_flash)
if (bank->target->state != TARGET_HALTED)
{ {
return ERROR_TARGET_NOT_HALTED; command_print(cmd_ctx, "not an at91sam7 flash bank '%s'", args[0]);
} return ERROR_FLASH_BANK_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;
}
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;
} }
if (strcmp(value, "set") == 0) 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; 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 */ /* Configure the flash controller timing */
at91sam7_read_clock_info(bank); at91sam7_read_clock_info(bank);
at91sam7_set_flash_mode(bank, 0, FMR_TIMING_NVBITS); at91sam7_set_flash_mode(bank, 0, FMR_TIMING_NVBITS);

View File

@ -60,8 +60,6 @@ typedef struct at91sam7_flash_bank_s
u8 mck_valid; u8 mck_valid;
u32 mck_freq; u32 mck_freq;
int probed;
} at91sam7_flash_bank_t; } at91sam7_flash_bank_t;
/* AT91SAM7 control registers */ /* 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); retval=bank->driver->write(bank, buffer, offset, count);
if (retval!=ERROR_OK) 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; 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); retval=bank->driver->erase(bank, first, last);
if (retval!=ERROR_OK) 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; 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); retval=bank->driver->protect(bank, set, first, last);
if (retval!=ERROR_OK) 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; return retval;
@ -311,6 +311,7 @@ int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char
flash_bank_t *p; flash_bank_t *p;
int i = 0; int i = 0;
int j = 0; int j = 0;
int retval;
if (argc != 1) 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); 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); 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) if (argc != 1)
{ {
return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_COMMAND_SYNTAX_ERROR;
} }
if (strcmp(args[0], "on") == 0) 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 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(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); extern flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr);
#define ERROR_FLASH_BANK_INVALID (-900) #define ERROR_FLASH_BANK_INVALID (-900)