From 5319ccd7eb4761f1481dcbb041b256848efc005e Mon Sep 17 00:00:00 2001 From: Spencer Oliver Date: Mon, 24 May 2010 11:41:50 +0100 Subject: [PATCH] flash: add virtual flash bank driver This adds a virtual flash bank driver that allows virtual banks to be defined that refer to an existing flash bank. For example the real address for bank0 on the pic32 is 0x1fc00000 but the user program will either be in kseg0 (0xbfc00000) or kseg1 (0x9fc00000). This also means that gdb will be aware of all the read only flash addresses. Signed-off-by: Spencer Oliver --- doc/openocd.texi | 20 ++++ src/flash/nor/Makefile.am | 3 +- src/flash/nor/drivers.c | 2 + src/flash/nor/virtual.c | 244 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 src/flash/nor/virtual.c diff --git a/doc/openocd.texi b/doc/openocd.texi index c95803ae7..a3ca12475 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4672,6 +4672,26 @@ the flash clock. @end deffn @end deffn +@deffn {Flash Driver} virtual +This is a special driver that maps a previously defined bank to another +address. All bank settings will be copied from the master physical bank. + +The @var{virtual} driver defines one mandatory parameters, + +@itemize +@item @var{master_bank} The bank that this virtual address refers to. +@end itemize + +So in the following example addresses 0xbfc00000 and 0x9fc00000 refer to +the flash bank defined at address 0x1fc00000. Any cmds executed on +the virtual banks are actually performed on the physical banks. +@example +flash bank $_FLASHNAME pic32mx 0x1fc00000 0 0 0 $_TARGETNAME +flash bank vbank0 virtual 0xbfc00000 0 0 0 $_TARGETNAME $_FLASHNAME +flash bank vbank1 virtual 0x9fc00000 0 0 0 $_TARGETNAME $_FLASHNAME +@end example +@end deffn + @subsection str9xpec driver @cindex str9xpec diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 5d0a4dfcb..eec6f5042 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -28,7 +28,8 @@ NOR_DRIVERS = \ str7x.c \ str9x.c \ str9xpec.c \ - tms470.c + tms470.c \ + virtual.c noinst_HEADERS = \ at91sam7.h \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 3e09a0045..68f2f88a5 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -39,6 +39,7 @@ extern struct flash_driver ocl_flash; extern struct flash_driver pic32mx_flash; extern struct flash_driver avr_flash; extern struct flash_driver faux_flash; +extern struct flash_driver virtual_flash; /** * The list of built-in flash drivers. @@ -63,6 +64,7 @@ static struct flash_driver *flash_drivers[] = { &pic32mx_flash, &avr_flash, &faux_flash, + &virtual_flash, NULL, }; diff --git a/src/flash/nor/virtual.c b/src/flash/nor/virtual.c new file mode 100644 index 000000000..4908c0c89 --- /dev/null +++ b/src/flash/nor/virtual.c @@ -0,0 +1,244 @@ +/*************************************************************************** + * Copyright (C) 2010 by Spencer Oliver * + * spen@spen-soft.co.uk * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" + +static struct flash_bank* virtual_get_master_bank(struct flash_bank *bank) +{ + struct flash_bank* master_bank; + + master_bank = get_flash_bank_by_name(bank->driver_priv); + if (master_bank == NULL) { + LOG_ERROR("master flash bank '%s' does not exist", (char*)bank->driver_priv); + } + + return master_bank; +} + +static void virtual_update_bank_info(struct flash_bank *bank) +{ + struct flash_bank *master_bank = virtual_get_master_bank(bank); + + if (master_bank == NULL) { + return; + } + + /* update the info we do not have */ + bank->size = master_bank->size; + bank->chip_width = master_bank->chip_width; + bank->bus_width = master_bank->bus_width; + bank->num_sectors = master_bank->num_sectors; + bank->sectors = master_bank->sectors; +} + +FLASH_BANK_COMMAND_HANDLER(virtual_flash_bank_command) +{ + if (CMD_ARGC < 7) + { + LOG_WARNING("incomplete flash_bank virtual configuration"); + return ERROR_FLASH_OPERATION_FAILED; + } + + /* get the master flash bank */ + const char *bank_name = CMD_ARGV[6]; + struct flash_bank *master_bank = get_flash_bank_by_name(bank_name); + + if (master_bank == NULL) + { + LOG_ERROR("master flash bank '%s' does not exist", bank_name); + return ERROR_FLASH_OPERATION_FAILED; + } + + /* save master bank name - use this to get settings later */ + bank->driver_priv = strdup(bank_name); + + return ERROR_OK; +} + +static int virtual_protect(struct flash_bank *bank, int set, int first, int last) +{ + struct flash_bank *master_bank = virtual_get_master_bank(bank); + int retval; + + if (master_bank == NULL) { + return ERROR_FLASH_OPERATION_FAILED; + } + + /* call master handler */ + if ((retval = master_bank->driver->protect(master_bank, set, + first, last)) != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int virtual_protect_check(struct flash_bank *bank) +{ + struct flash_bank *master_bank = virtual_get_master_bank(bank); + int retval; + + if (master_bank == NULL) { + return ERROR_FLASH_OPERATION_FAILED; + } + + /* call master handler */ + if ((retval = master_bank->driver->protect_check(master_bank)) != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int virtual_erase(struct flash_bank *bank, int first, int last) +{ + struct flash_bank *master_bank = virtual_get_master_bank(bank); + int retval; + + if (master_bank == NULL) { + return ERROR_FLASH_OPERATION_FAILED; + } + + /* call master handler */ + if ((retval = master_bank->driver->erase(master_bank, + first, last)) != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int virtual_write(struct flash_bank *bank, uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct flash_bank *master_bank = virtual_get_master_bank(bank); + int retval; + + if (master_bank == NULL) { + return ERROR_FLASH_OPERATION_FAILED; + } + + /* call master handler */ + if ((retval = master_bank->driver->write(master_bank, buffer, + offset, count)) != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int virtual_probe(struct flash_bank *bank) +{ + struct flash_bank *master_bank = virtual_get_master_bank(bank); + int retval; + + if (master_bank == NULL) { + return ERROR_FLASH_OPERATION_FAILED; + } + + /* call master handler */ + if ((retval = master_bank->driver->probe(master_bank)) != ERROR_OK) + return retval; + + /* update the info we do not have */ + virtual_update_bank_info(bank); + + return ERROR_OK; +} + +static int virtual_auto_probe(struct flash_bank *bank) +{ + struct flash_bank *master_bank = virtual_get_master_bank(bank); + int retval; + + if (master_bank == NULL) { + return ERROR_FLASH_OPERATION_FAILED; + } + + /* call master handler */ + if ((retval = master_bank->driver->auto_probe(master_bank)) != ERROR_OK) + return retval; + + /* update the info we do not have */ + virtual_update_bank_info(bank); + + return ERROR_OK; +} + +static int virtual_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct flash_bank *master_bank = virtual_get_master_bank(bank); + + if (master_bank == NULL) { + return ERROR_FLASH_OPERATION_FAILED; + } + + snprintf(buf, buf_size, "%s driver for flash bank %s at 0x%8.8" PRIx32 "", + bank->driver->name, master_bank->name, master_bank->base); + + return ERROR_OK; +} + +int virtual_blank_check(struct flash_bank *bank) +{ + struct flash_bank *master_bank = virtual_get_master_bank(bank); + int retval; + + if (master_bank == NULL) { + return ERROR_FLASH_OPERATION_FAILED; + } + + /* call master handler */ + if ((retval = master_bank->driver->erase_check(master_bank)) != ERROR_OK) + return retval; + + return ERROR_OK; +} + +int virtual_flash_read(struct flash_bank *bank, + uint8_t *buffer, uint32_t offset, uint32_t count) +{ + struct flash_bank *master_bank = virtual_get_master_bank(bank); + int retval; + + if (master_bank == NULL) { + return ERROR_FLASH_OPERATION_FAILED; + } + + /* call master handler */ + if ((retval = master_bank->driver->read(master_bank, buffer, + offset, count)) != ERROR_OK) + return retval; + + return ERROR_OK; +} + +struct flash_driver virtual_flash = { + .name = "virtual", + .flash_bank_command = virtual_flash_bank_command, + .erase = virtual_erase, + .protect = virtual_protect, + .write = virtual_write, + .read = virtual_flash_read, + .probe = virtual_probe, + .auto_probe = virtual_auto_probe, + .erase_check = virtual_blank_check, + .protect_check = virtual_protect_check, + .info = virtual_info, +};