- str9x flash support (Thanks to Spencer Oliver)
authordrath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Thu, 28 Sep 2006 10:41:43 +0000 (10:41 +0000)
committerdrath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Thu, 28 Sep 2006 10:41:43 +0000 (10:41 +0000)
- str75x flash support (Thanks to Spencer Oliver)
- correct reporting of T-Bit in CPSR (Thanks to John Hartman for reporting this)
- core-state (ARM/Thumb) can be switched by modifying CPSR
- fixed bug in gdb_server register handling
- register values > 32-bit should now be supported
- several minor fixes and enhancements

git-svn-id: svn://svn.berlios.de/openocd/trunk@100 b42882b7-edfa-0310-969c-e2dbd0fdcd60

21 files changed:
src/flash/Makefile.am
src/flash/cfi.c
src/flash/flash.c
src/flash/str7x.c
src/flash/str9x.c [new file with mode: 0644]
src/flash/str9x.h [new file with mode: 0644]
src/helper/binarybuffer.c
src/helper/binarybuffer.h
src/helper/interpreter.c
src/jtag/jtag.c
src/server/gdb_server.c
src/target/arm966e.c
src/target/arm9tdmi.c
src/target/armv4_5.c
src/target/embeddedice.c
src/target/embeddedice.h
src/target/etm.c
src/target/etm.h
src/target/register.c
src/target/register.h
src/target/target.c

index 61e363c92266834a6d749783332a9955f779884c..65692e3a2e620b51ec9baca7b3140ebae84cb7eb 100644 (file)
@@ -1,5 +1,5 @@
 INCLUDES = -I$(top_srcdir)/src/helper -I$(top_srcdir)/src/jtag -I$(top_srcdir)/src/target $(all_includes)
 METASOURCES = AUTO
 noinst_LIBRARIES = libflash.a
-libflash_a_SOURCES = flash.c lpc2000.c cfi.c at91sam7.c str7x.c
-noinst_HEADERS = flash.h lpc2000.h cfi.h at91sam7.h str7x.h
+libflash_a_SOURCES = flash.c lpc2000.c cfi.c at91sam7.c str7x.c str9x.c
+noinst_HEADERS = flash.h lpc2000.h cfi.h at91sam7.h str7x.h str9x.h
index a90093f4288a6bdac05792d52bae53326c151b00..bb548c22d1d51160312886ef67f995293f92a8b0 100644 (file)
@@ -685,6 +685,8 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
                count -= thisrun_count;
        }
        
+       target_free_working_area(target, source);
+       
        destroy_reg_param(&reg_params[0]);
        destroy_reg_param(&reg_params[1]);
        destroy_reg_param(&reg_params[2]);
@@ -882,6 +884,8 @@ int cfi_probe(struct flash_bank_s *bank)
        cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11);
        cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12);
        
+       DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2]);
+       
        if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y'))
        {
                cfi_command(bank, 0xf0, command);
index 7d199cfccf68f36bacc964ee5b630aca3d97d7c2..736d3fca12484243e5831e5f0a85645448d293a3 100644 (file)
@@ -51,6 +51,7 @@ extern flash_driver_t lpc2000_flash;
 extern flash_driver_t cfi_flash;
 extern flash_driver_t at91sam7_flash;
 extern flash_driver_t str7x_flash;
+extern flash_driver_t str9x_flash;
 
 flash_driver_t *flash_drivers[] =
 {
@@ -58,6 +59,7 @@ flash_driver_t *flash_drivers[] =
        &cfi_flash,
        &at91sam7_flash,
        &str7x_flash,
+       &str9x_flash,
        NULL,
 };
 
@@ -366,6 +368,10 @@ int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, cha
                int last = strtoul(args[2], NULL, 0);
                int retval;
                flash_bank_t *p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
+               struct timeval start, end, duration;
+
+               gettimeofday(&start, NULL);
+       
                if (!p)
                {
                        command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
@@ -398,6 +404,13 @@ int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, cha
                                        command_print(cmd_ctx, "unknown error");
                        }
                }
+               else
+               {
+                       gettimeofday(&end, NULL);       
+                       timeval_subtract(&duration, &end, &start);
+               
+                       command_print(cmd_ctx, "erased sectors %i through %i on flash bank %i in %is %ius", first, last, strtoul(args[0], 0, 0), duration.tv_sec, duration.tv_usec);
+               }
        }
        else
        {
index 0419394e753bbfdc67c0be63ce91a5ec0e6006d7..62acba38744bba69f9b80428af79d5573e981c64 100644 (file)
@@ -183,6 +183,15 @@ int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char
                        bank->base = 0x80000000;
                }
        }
+       else if (strcmp(args[5], "STR75x") == 0)
+       {
+               str7x_info->bank1 = 1;
+               if (bank->base != 0x20000000)
+               {
+                       WARNING("overriding flash base address for STR75x device with 0x20000000");
+                       bank->base = 0x20000000;
+               }
+       }
        else
        {
                ERROR("unknown STR7x variant");
diff --git a/src/flash/str9x.c b/src/flash/str9x.c
new file mode 100644 (file)
index 0000000..054f5d0
--- /dev/null
@@ -0,0 +1,635 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   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 "replacements.h"
+
+#include "str9x.h"
+#include "flash.h"
+#include "target.h"
+#include "log.h"
+#include "armv4_5.h"
+#include "algorithm.h"
+#include "binarybuffer.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+str9x_mem_layout_t mem_layout_str9[] = {
+       {0x00000000, 0x10000, 0x01},
+       {0x00010000, 0x10000, 0x02},
+       {0x00020000, 0x10000, 0x04},
+       {0x00030000, 0x10000, 0x08},
+       {0x00040000, 0x10000, 0x10},
+       {0x00050000, 0x10000, 0x20},
+       {0x00060000, 0x10000, 0x40},
+       {0x00070000, 0x10000, 0x80},
+       {0x00080000, 0x02000, 0x100},
+       {0x00082000, 0x02000, 0x200},
+       {0x00084000, 0x02000, 0x400},
+       {0x00086000, 0x02000, 0x800}
+};
+
+int str9x_register_commands(struct command_context_s *cmd_ctx);
+int str9x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
+int str9x_erase(struct flash_bank_s *bank, int first, int last);
+int str9x_protect(struct flash_bank_s *bank, int set, int first, int last);
+int str9x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
+int str9x_probe(struct flash_bank_s *bank);
+int str9x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int str9x_protect_check(struct flash_bank_s *bank);
+int str9x_erase_check(struct flash_bank_s *bank);
+int str9x_info(struct flash_bank_s *bank, char *buf, int buf_size);
+
+int str9x_handle_flash_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+flash_driver_t str9x_flash =
+{
+       .name = "str9x",
+       .register_commands = str9x_register_commands,
+       .flash_bank_command = str9x_flash_bank_command,
+       .erase = str9x_erase,
+       .protect = str9x_protect,
+       .write = str9x_write,
+       .probe = str9x_probe,
+       .erase_check = str9x_erase_check,
+       .protect_check = str9x_protect_check,
+       .info = str9x_info
+};
+
+int str9x_register_commands(struct command_context_s *cmd_ctx)
+{
+       command_t *str9x_cmd = register_command(cmd_ctx, NULL, "str9x", NULL, COMMAND_ANY, NULL);
+       
+       register_command(cmd_ctx, str9x_cmd, "flash_config", str9x_handle_flash_config_command, COMMAND_EXEC,
+                                        "configure str9 flash controller");
+                                        
+       return ERROR_OK;
+}
+
+int str9x_build_block_list(struct flash_bank_s *bank)
+{
+       str9x_flash_bank_t *str9x_info = bank->driver_priv;
+       
+       int i;
+       int num_sectors = 0, b0_sectors = 0;
+               
+       switch (bank->size)
+       {
+               case 256 * 1024:
+                       b0_sectors = 4;
+                       break;
+               case 512 * 1024:
+                       b0_sectors = 8;
+                       break;
+               default:
+                       ERROR("BUG: unknown bank->size encountered");
+                       exit(-1);
+       }
+       
+       num_sectors = b0_sectors + 2;
+       
+       bank->num_sectors = num_sectors;
+       bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
+       str9x_info->sector_bits = malloc(sizeof(u32) * num_sectors);
+       
+       num_sectors = 0;
+       
+       for (i = 0; i < b0_sectors; i++)
+       {
+               bank->sectors[num_sectors].offset = mem_layout_str9[i].sector_start;
+               bank->sectors[num_sectors].size = mem_layout_str9[i].sector_size;
+               bank->sectors[num_sectors].is_erased = -1;
+               bank->sectors[num_sectors].is_protected = 1;
+               str9x_info->sector_bits[num_sectors++] = mem_layout_str9[i].sector_bit;
+       }
+       
+       for (i = 8; i < 12; i++)
+       {
+               bank->sectors[num_sectors].offset = mem_layout_str9[i].sector_start;
+               bank->sectors[num_sectors].size = mem_layout_str9[i].sector_size;
+               bank->sectors[num_sectors].is_erased = -1;
+               bank->sectors[num_sectors].is_protected = 1;
+               str9x_info->sector_bits[num_sectors++] = mem_layout_str9[i].sector_bit;
+       }
+       
+       return ERROR_OK;
+}
+
+/* flash bank str9x <base> <size> 0 0 <target#>
+ */
+int str9x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
+{
+       str9x_flash_bank_t *str9x_info;
+       
+       if (argc < 6)
+       {
+               WARNING("incomplete flash_bank str9x configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+       
+       str9x_info = malloc(sizeof(str9x_flash_bank_t));
+       bank->driver_priv = str9x_info;
+       
+       if (bank->base != 0x00000000)
+       {
+               WARNING("overriding flash base address for STR91x device with 0x00000000");
+               bank->base = 0x00000000;
+       }
+       
+       str9x_info->target = get_target_by_num(strtoul(args[5], NULL, 0));
+       if (!str9x_info->target)
+       {
+               ERROR("no target '%s' configured", args[5]);
+               exit(-1);
+       }
+
+       str9x_build_block_list(bank);
+       
+       str9x_info->write_algorithm = NULL;
+       
+       return ERROR_OK;
+}
+
+int str9x_blank_check(struct flash_bank_s *bank, int first, int last)
+{
+       str9x_flash_bank_t *str9x_info = bank->driver_priv;
+       target_t *target = str9x_info->target;
+       u8 *buffer;
+       int i;
+       int nBytes;
+       
+       if ((first < 0) || (last > bank->num_sectors))
+               return ERROR_FLASH_SECTOR_INVALID;
+
+       if (str9x_info->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 str9x_protect_check(struct flash_bank_s *bank)
+{
+       str9x_flash_bank_t *str9x_info = bank->driver_priv;
+       target_t *target = str9x_info->target;
+       
+       int i;
+       u32 adr;
+       u16 status;
+
+       if (str9x_info->target->state != TARGET_HALTED)
+       {
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* read level one protection */
+       
+       adr = mem_layout_str9[10].sector_start + 4;
+       
+       target_write_u32(target, adr, 0x90);
+       target_read_u16(target, adr, &status);
+       target_write_u32(target, adr, 0xFF);
+       
+       for (i = 0; i < bank->num_sectors; i++)
+       {
+               if (status & str9x_info->sector_bits[i])
+                       bank->sectors[i].is_protected = 1;
+               else
+                       bank->sectors[i].is_protected = 0;
+       }
+       
+       return ERROR_OK;
+}
+
+int str9x_erase(struct flash_bank_s *bank, int first, int last)
+{
+       str9x_flash_bank_t *str9x_info = bank->driver_priv;
+       target_t *target = str9x_info->target;
+       int i;
+       u32 adr;
+       u8 status;
+       
+       if (str9x_info->target->state != TARGET_HALTED)
+       {
+               return ERROR_TARGET_NOT_HALTED;
+       }
+    
+       for (i = first; i <= last; i++)
+       {
+               adr = bank->sectors[i].offset;
+               
+       /* erase sectors */
+               target_write_u16(target, adr, 0x20);
+               target_write_u16(target, adr, 0xD0);
+               
+               /* get status */
+               target_write_u16(target, adr, 0x70);
+               
+               while (1) {
+                       target_read_u8(target, adr, &status);
+                       if( status & 0x80 )
+                               break;
+                       usleep(1000);
+               }
+               
+               /* clear status, also clear read array */
+               target_write_u16(target, adr, 0x50);
+               
+               /* read array command */
+               target_write_u16(target, adr, 0xFF);
+               
+               if( status & 0x22 )
+               {
+                       ERROR("error erasing flash bank, status: 0x%x", status);
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+       }
+       
+       for (i = first; i <= last; i++)
+               bank->sectors[i].is_erased = 1;
+
+       return ERROR_OK;
+}
+
+int str9x_protect(struct flash_bank_s *bank, int set, int first, int last)
+{
+       str9x_flash_bank_t *str9x_info = bank->driver_priv;
+       target_t *target = str9x_info->target;
+       int i;
+       u32 adr;
+       u8 status;
+       
+       if (str9x_info->target->state != TARGET_HALTED)
+       {
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       for (i = first; i <= last; i++)
+       {
+               /* Level One Protection */
+       
+               adr = bank->sectors[i].offset;
+               
+               target_write_u16(target, adr, 0x60);
+               if( set )
+                       target_write_u16(target, adr, 0x01);
+               else
+                       target_write_u16(target, adr, 0xD0);
+               
+               /* query status */
+               target_read_u8(target, adr, &status);
+       }
+       
+       return ERROR_OK;
+}
+
+int str9x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
+{
+       str9x_flash_bank_t *str9x_info = bank->driver_priv;
+       target_t *target = str9x_info->target;
+       u32 buffer_size = 8192;
+       working_area_t *source;
+       u32 address = bank->base + offset;
+       reg_param_t reg_params[4];
+       armv4_5_algorithm_t armv4_5_info;
+       int retval;
+       
+       u32 str9x_flash_write_code[] = {
+                                       /* write:                               */
+               0xe3c14003,     /*      bic     r4, r1, #3              */
+               0xe3a03040,     /*      mov     r3, #0x40               */
+               0xe1c430b0,     /*      strh r3, [r4, #0]       */
+               0xe0d030b2,     /*      ldrh r3, [r0], #2       */
+               0xe0c130b2,     /*      strh r3, [r1], #2       */
+               0xe3a03070,     /*      mov r3, #0x70           */
+               0xe1c430b0,     /*      strh r3, [r4, #0]       */
+                                       /* busy:                                */
+               0xe5d43000,     /*      ldrb r3, [r4, #0]       */
+               0xe3130080,     /*      tst r3, #0x80           */
+               0x0afffffc,     /*      beq busy                        */
+               0xe3a05050,     /*      mov     r5, #0x50               */
+               0xe1c450b0,     /*      strh r5, [r4, #0]       */
+               0xe3a050ff,     /*      mov     r5, #0xFF               */
+               0xe1c450b0,     /*      strh r5, [r4, #0]       */
+               0xe3130012,     /*      tst     r3, #0x12               */
+               0x1a000001,     /*      bne exit                        */
+               0xe2522001,     /*      subs r2, r2, #1         */
+               0x1affffed,     /*      bne write                       */
+                                       /* exit:                                */
+               0xeafffffe,     /*      b exit                          */
+       };
+       
+       u8 str9x_flash_write_code_buf[76];
+       int i;
+       
+       /* flash write code */
+       if (!str9x_info->write_algorithm)
+       {
+               if (target_alloc_working_area(target, 4 * 19, &str9x_info->write_algorithm) != ERROR_OK)
+               {
+                       WARNING("no working area available, can't do block memory writes");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               };
+
+               /* convert flash writing code into a buffer in target endianness */
+               for (i = 0; i < 19; i++)
+                       target_buffer_set_u32(target, str9x_flash_write_code_buf + i*4, str9x_flash_write_code[i]);
+                       
+               target_write_buffer(target, str9x_info->write_algorithm->address, 19 * 4, str9x_flash_write_code_buf);
+       }
+
+       /* memory buffer */
+       while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
+       {
+               buffer_size /= 2;
+               if (buffer_size <= 256)
+               {
+                       /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
+                       if (str9x_info->write_algorithm)
+                               target_free_working_area(target, str9x_info->write_algorithm);
+                       
+                       WARNING("no large enough working area available, can't do block memory writes");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+       };
+       
+       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);
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);
+       
+       while (count > 0)
+       {
+               u32 thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
+               
+               target_write_buffer(target, source->address, thisrun_count * 2, buffer);
+               
+               buf_set_u32(reg_params[0].value, 0, 32, source->address);
+               buf_set_u32(reg_params[1].value, 0, 32, address);
+               buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
+
+               if ((retval = target->type->run_algorithm(target, 0, NULL, 4, reg_params, str9x_info->write_algorithm->address, str9x_info->write_algorithm->address + (18 * 4), 10000, &armv4_5_info)) != ERROR_OK)
+               {
+                       ERROR("error executing str9x flash write algorithm");
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+       
+               if (buf_get_u32(reg_params[3].value, 0, 32) != 0x80)
+               {
+                       return ERROR_FLASH_OPERATION_FAILED;
+               }
+               
+               buffer += thisrun_count * 2;
+               address += thisrun_count * 2;
+               count -= thisrun_count;
+       }
+       
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+       
+       return ERROR_OK;
+}
+
+int str9x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
+{
+       str9x_flash_bank_t *str9x_info = bank->driver_priv;
+       target_t *target = str9x_info->target;
+       u32 words_remaining = (count / 2);
+       u32 bytes_remaining = (count & 0x00000001);
+       u32 address = bank->base + offset;
+       u32 bytes_written = 0;
+       u8 status;
+       u32 retval;
+       u32 check_address = offset;
+       u32 bank_adr;
+       int i;
+       
+       if (str9x_info->target->state != TARGET_HALTED)
+       {
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       if (offset & 0x1)
+       {
+               WARNING("offset 0x%x breaks required 2-byte alignment", offset);
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       }
+       
+       for (i = 0; i < bank->num_sectors; i++)
+       {
+               u32 sec_start = bank->sectors[i].offset;
+               u32 sec_end = sec_start + bank->sectors[i].size;
+               
+               /* check if destination falls within the current sector */
+               if ((check_address >= sec_start) && (check_address < sec_end))
+               {
+                       /* check if destination ends in the current sector */
+                       if (offset + count < sec_end)
+                               check_address = offset + count;
+                       else
+                               check_address = sec_end;
+               }
+       }
+       
+       if (check_address != offset + count)
+               return ERROR_FLASH_DST_OUT_OF_BANK;
+       
+       /* multiple half words (2-byte) to be programmed? */
+       if (words_remaining > 0) 
+       {
+               /* try using a block write */
+               if ((retval = str9x_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
+               {
+                       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
+                       {
+                               /* if block write failed (no sufficient working area),
+                                * we use normal (slow) single dword accesses */ 
+                               WARNING("couldn't use block writes, falling back to single memory accesses");
+                       }
+                       else if (retval == ERROR_FLASH_OPERATION_FAILED)
+                       {
+                               ERROR("flash writing failed with error code: 0x%x", retval);
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+               }
+               else
+               {
+                       buffer += words_remaining * 2;
+                       address += words_remaining * 2;
+                       words_remaining = 0;
+               }
+       }
+
+       while (words_remaining > 0)
+       {
+               bank_adr = address & 0x03;
+               
+               /* write data command */
+               target_write_u16(target, bank_adr, 0x40);
+               target->type->write_memory(target, address, 2, 1, buffer + bytes_written);
+               
+               /* get status command */
+               target_write_u16(target, bank_adr, 0x70);
+               
+               while (1) {
+                       target_read_u8(target, bank_adr, &status);
+                       if( status & 0x80 )
+                               break;
+                       usleep(1000);
+               }
+               
+               /* clear status reg and read array */
+               target_write_u16(target, bank_adr, 0x50);
+               target_write_u16(target, bank_adr, 0xFF);
+               
+               if (status & 0x10)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               else if (status & 0x02)
+                       return ERROR_FLASH_OPERATION_FAILED;
+
+               bytes_written += 2;
+               words_remaining--;
+               address += 2;
+       }
+       
+       if (bytes_remaining)
+       {
+               u8 last_halfword[2] = {0xff, 0xff};
+               int i = 0;
+                               
+               while(bytes_remaining > 0)
+               {
+                       last_halfword[i++] = *(buffer + bytes_written); 
+                       bytes_remaining--;
+                       bytes_written++;
+               }
+               
+               bank_adr = address & 0x03;
+               
+               /* write data comamnd */
+               target_write_u16(target, bank_adr, 0x40);
+               target->type->write_memory(target, address, 2, 1, last_halfword);
+               
+               /* query status command */
+               target_write_u16(target, bank_adr, 0x70);
+               
+               while (1) {
+                       target_read_u8(target, bank_adr, &status);
+                       if( status & 0x80 )
+                               break;
+                       usleep(1000);
+               }
+               
+               /* clear status reg and read array */
+               target_write_u16(target, bank_adr, 0x50);
+               target_write_u16(target, bank_adr, 0xFF);
+               
+               if (status & 0x10)
+                       return ERROR_FLASH_OPERATION_FAILED;
+               else if (status & 0x02)
+                       return ERROR_FLASH_OPERATION_FAILED;
+       }
+               
+       return ERROR_OK;
+}
+
+int str9x_probe(struct flash_bank_s *bank)
+{
+       return ERROR_OK;
+}
+
+int str9x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       return ERROR_OK;
+}
+
+int str9x_erase_check(struct flash_bank_s *bank)
+{
+       return str9x_blank_check(bank, 0, bank->num_sectors - 1);
+}
+
+int str9x_info(struct flash_bank_s *bank, char *buf, int buf_size)
+{
+       snprintf(buf, buf_size, "str9x flash driver info" );
+       return ERROR_OK;
+}
+
+int str9x_handle_flash_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       str9x_flash_bank_t *str9x_info;
+       flash_bank_t *bank;
+       target_t *target = NULL;
+       
+       if (argc < 4)
+       {
+               command_print(cmd_ctx, "usage: str9x flash_config b0size b1size b0start b1start");
+               return ERROR_OK;
+       }
+       
+       bank = get_flash_bank_by_num(0);
+       str9x_info = bank->driver_priv;
+       target = str9x_info->target;
+       
+       if (str9x_info->target->state != TARGET_HALTED)
+       {
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       
+       /* config flash controller */
+       target_write_u32(target, FLASH_BBSR, strtoul(args[0], NULL, 0));
+       target_write_u32(target, FLASH_NBBSR, strtoul(args[1], NULL, 0));
+    target_write_u32(target, FLASH_BBADR, (strtoul(args[2], NULL, 0) >> 2));
+    target_write_u32(target, FLASH_NBBADR, (strtoul(args[3], NULL, 0) >> 2));
+
+       /* enable flash bank 1 */
+    target_write_u32(target, FLASH_CR, 0x18);
+       return ERROR_OK;
+}
diff --git a/src/flash/str9x.h b/src/flash/str9x.h
new file mode 100644 (file)
index 0000000..0cd1f19
--- /dev/null
@@ -0,0 +1,85 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+#ifndef STR9X_H
+#define STR9X_H
+
+#include "flash.h"
+#include "target.h"
+
+typedef struct str9x_flash_bank_s
+{
+       struct target_s *target;
+       u32 *sector_bits;
+       working_area_t *write_algorithm;
+} str9x_flash_bank_t;
+
+enum str9x_status_codes
+{
+       STR9X_CMD_SUCCESS = 0,
+       STR9X_INVALID_COMMAND = 1,
+       STR9X_SRC_ADDR_ERROR = 2,
+       STR9X_DST_ADDR_ERROR = 3,
+       STR9X_SRC_ADDR_NOT_MAPPED = 4,
+       STR9X_DST_ADDR_NOT_MAPPED = 5,
+       STR9X_COUNT_ERROR = 6,
+       STR9X_INVALID_SECTOR = 7,
+       STR9X_SECTOR_NOT_BLANK = 8,
+       STR9X_SECTOR_NOT_PREPARED = 9,
+       STR9X_COMPARE_ERROR = 10,
+       STR9X_BUSY = 11
+};
+
+/* FMI sectors */
+
+#define FMI_BANK_0     (0x5400000C << 2)                       /* FMI Bank 0 */
+#define FMI_BANK_1     (0x54000010 << 2)                       /* FMI Bank 1 */
+
+#define FMI_B0S0       (0x00000000 + FMI_BANK_0)       /* Bank 0 sector 0 */
+#define FMI_B0S1       (0x00010000 + FMI_BANK_0)       /* Bank 0 sector 1 */
+#define FMI_B0S2       (0x00020000 + FMI_BANK_0)       /* Bank 0 sector 2 */
+#define FMI_B0S3       (0x00030000 + FMI_BANK_0)       /* Bank 0 sector 3 */
+#define FMI_B0S4       (0x00040000 + FMI_BANK_0)       /* Bank 0 sector 4 */
+#define FMI_B0S5       (0x00050000 + FMI_BANK_0)       /* Bank 0 sector 5 */
+#define FMI_B0S6       (0x00060000 + FMI_BANK_0)       /* Bank 0 sector 6 */
+#define FMI_B0S7       (0x00070000 + FMI_BANK_0)       /* Bank 0 sector 7 */
+
+#define FMI_B1S0       (0x00000000 + FMI_BANK_1)       /* Bank 1 sector 0 */
+#define FMI_B1S1       (0x00002000 + FMI_BANK_1)       /* Bank 1 sector 1 */
+#define FMI_B1S2       (0x00004000 + FMI_BANK_1)       /* Bank 1 sector 2 */
+#define FMI_B1S3       (0x00006000 + FMI_BANK_1)       /* Bank 1 sector 3 */
+
+/*  Flash registers */
+
+#define FLASH_BBSR             0x54000000              /* Boot Bank Size Register                */
+#define FLASH_NBBSR            0x54000004              /* Non-Boot Bank Size Register            */
+#define FLASH_BBADR            0x5400000C              /* Boot Bank Base Address Register        */
+#define FLASH_NBBADR   0x54000010              /* Non-Boot Bank Base Address Register    */
+#define FLASH_CR               0x54000018              /* Control Register                       */
+#define FLASH_SR               0x5400001C              /* Status Register                        */
+#define FLASH_BCE5ADDR 0x54000020              /* BC Fifth Entry Target Address Register */
+
+typedef struct str9x_mem_layout_s {
+       u32 sector_start;
+       u32 sector_size;
+       u32 sector_bit;
+} str9x_mem_layout_t;
+
+#endif /* STR9X_H */
+
index ce33f138f7a1a7ed4f25418edc65b714e6650558..6afd6e593c23902da97705de2f3f6b20172b1e17 100644 (file)
@@ -208,56 +208,156 @@ u32 flip_u32(u32 value, unsigned int num)
        return c;
 }
 
-char* buf_to_char(u8 *buf, int size)
+int ceil_f_to_u32(float x)
 {
-       int char_len = CEIL(size, 8) * 2;
-       char *char_buf = malloc(char_len + 1);
-       int i;
-       int bits_left = size;
+       u32 y;
+       
+       if (x < 0)      /* return zero for negative numbers */
+               return 0;
        
-       char_buf[char_len] = 0;
+       y = x;  /* cut off fraction */
        
-       for (i = 0; i < CEIL(size, 8); i++)
+       if ((x - y) > 0.0) /* if there was a fractional part, increase by one */
+               y++;
+       
+       return y;
+}
+
+char* buf_to_str(u8 *buf, int buf_len, int radix)
+{
+       const char *DIGITS = "0123456789abcdef";
+       float factor;
+       char *str;
+       int str_len;
+       int b256_len = CEIL(buf_len, 8);
+       u32 tmp;
+
+       int j; /* base-256 digits */
+       int i; /* output digits (radix) */
+       
+       if (radix == 16)
        {
-               if (bits_left < 8)
-               {
-                       buf[i] &= ((1 << bits_left) - 1);
-               }
-               
-               if (((buf[i] & 0x0f) >= 0) && ((buf[i] & 0x0f) <= 9))
-                       char_buf[char_len - 2*i - 1] = '0' + (buf[i] & 0xf);
-               else
-                       char_buf[char_len - 2*i - 1] = 'a' + (buf[i] & 0xf) - 10;
-               
-               if (((buf[i] & 0xf0) >> 4 >= 0) && ((buf[i] & 0xf0) >> 4 <= 9))
-                       char_buf[char_len - 2*i - 2] = '0' + ((buf[i] & 0xf0) >> 4);
-               else
-                       char_buf[char_len - 2*i - 2] = 'a' + ((buf[i] & 0xf0) >> 4) - 10;
-               
+               factor = 2.0;   /* log(256) / log(16) = 2.0 */
        }
+       else if (radix == 10)
+       {
+               factor = 2.40824;   /* log(256) / log(10) = 2.40824 */
+    }
+       else if (radix == 8)
+       {
+               factor = 2.66667;       /* log(256) / log(8) = 2.66667 */
+       }
+       else
+               return NULL;
+       
+       str_len = ceil_f_to_u32(CEIL(buf_len, 8) * factor);
+       str = calloc(str_len + 1, 1);
+       
+       for (i = b256_len - 1; i >= 0; i--)
+    {
+        tmp = buf[i];
+       if ((i == (buf_len / 8)) && (buf_len % 8))
+               tmp &= (0xff >> (8 - (buf_len % 8)));
 
-       return char_buf;
+        for (j = str_len; j > 0; j--)
+        {
+            tmp += (u32)str[j-1] * 256;
+            str[j-1] = (u8)(tmp % radix);
+            tmp /= radix;
+        }
+    }
+    
+    for (j = 0; j < str_len; j++)
+               str[j] = DIGITS[(int)str[j]];
+       
+       return str;
 }
 
-int char_to_buf(char *buf, int len, u8 *bin_buf, int buf_size)
+int str_to_buf(char* str, int str_len, u8 *buf, int buf_len, int radix)
 {
-       int bin_len = CEIL(len, 2);
-       int i;
+       char *charbuf;
+       u32 tmp;
+       float factor;
+       u8 *b256_buf;
+       int b256_len; 
        
-       if (buf_size < CEIL(bin_len, 8))
-               return 0;
+       int j; /* base-256 digits */
+       int i; /* input digits (ASCII) */
+       
+       if (radix == 0) 
+       {
+               /* identify radix, and skip radix-prefix (0, 0x or 0X) */
+               if ((str[0] == '0') && (str[1] && ((str[1] == 'x') || (str[1] == 'X'))))
+               {
+                       radix = 16;
+                       str += 2;
+                       str_len -= 2;
+               }
+               else if ((str[0] == '0') && (str_len != 1))
+               {
+                       radix = 8;
+                       str += 1;
+                       str_len -= 1;
+               }
+               else
+               {
+                       radix = 10;
+               }
+       }
        
-       if (len % 2)
+       if (radix == 16)
+               factor = 0.5; /* log(16) / log(256) = 0.5 */
+       else if (radix == 10)
+               factor = 0.41524; /* log(10) / log(256) = 0.41524 */
+       else if (radix == 8)
+               factor = 0.375; /* log(8) / log(256) = 0.375 */
+       else
                return 0;
+
+       /* copy to zero-terminated buffer */
+       charbuf = malloc(str_len + 1);
+       memcpy(charbuf, str, str_len);
+       charbuf[str_len] = '\0';
        
-       for (i = 0; i < strlen(buf); i++)
-       {
-               u32 tmp;
-               sscanf(buf + 2*i, "%2x", &tmp);
-               bin_buf[i] = tmp & 0xff;
+       /* number of digits in base-256 notation */
+       b256_len = ceil_f_to_u32(str_len * factor);
+       b256_buf = calloc(b256_len, 1);
+               
+       /* go through zero terminated buffer */
+       for (i = 0; charbuf[i]; i++)
+       { 
+               tmp = charbuf[i];
+        if ((tmp >= '0') && (tmp <= '9'))
+               tmp = (tmp - '0');
+        else if ((tmp >= 'a') && (tmp <= 'f'))
+               tmp = (tmp - 'a' + 10);
+        else if ((tmp >= 'A') && (tmp <= 'F'))
+               tmp = (tmp - 'A' + 10);
+        else continue; /* skip characters other than [0-9,a-f,A-F] */
+               
+               if (tmp >= radix)
+                       continue;       /* skip digits invalid for the current radix */ 
+               
+               for (j = 0; j < b256_len; j++)
+        {
+            tmp += (u32)b256_buf[j] * radix;
+            b256_buf[j] = (u8)(tmp & 0xFF);
+            tmp >>= 8;
+        }
+               
        }
        
-       return bin_len * 8;
+       for (j = 0; j < CEIL(buf_len, 8); j++)
+               buf[j] = b256_buf[j];
+
+       /* mask out bits that don't belong to the buffer */
+       if (buf_len % 8)
+               buf[(buf_len / 8)] &= 0xff >> (8 - (buf_len % 8));
+               
+       free(b256_buf);
+       free(charbuf);
+       
+       return i;
 }
 
 int buf_to_u32_handler(u8 *in_buf, void *priv)
index 0a688945002a39f9509be5d186a38fa8454c7c94..6f39e7cf45d1efd3a39780e9d9d2d531be9aa5df 100644 (file)
@@ -38,8 +38,8 @@ extern u8* buf_cpy(u8 *from, u8 *to, int size);
 extern u8* buf_set_ones(u8 *buf, int count);
 extern u8* buf_set_buf(u8 *src, int src_start, u8 *dst, int dst_start, int len);
 
-extern char* buf_to_char(u8 *buf, int size);
-extern int char_to_buf(char *buf, int len, u8 *bin_buf, int buf_size);
+extern int str_to_buf(char* str, int len, u8 *bin_buf, int buf_size, int radix);
+extern char* buf_to_str(u8 *buf, int size, int radix);
 
 extern int buf_to_u32_handler(u8 *in_buf, void *priv);
 
index 17d24b1fe8cd89199f51ad8d77c5b68db65f9216..7b0432abc097a68191b142a8ab88ed734370eada 100644 (file)
@@ -126,7 +126,7 @@ int handle_var_command(struct command_context_s *cmd_ctx, char *cmd, char **args
                        last_var_p = &((*last_var_p)->next);
                }
 
-               if ((args[0][0] >= 0) && (args[0][0] <= 9))
+               if ((args[0][0] >= '0') && (args[0][0] <= '9'))
                {
                        command_print(cmd_ctx, "invalid name specified (first character may not be a number)");
                        return ERROR_OK;
index b05f19d990bf055761f3cb17cfc3307a1eb73f18..5ae7462163f4b5c2c8d2b7575b6439fcba032954 100644 (file)
@@ -958,12 +958,14 @@ int jtag_build_buffer(scan_command_t *cmd, u8 **buffer)
        {
                if (cmd->fields[i].out_value)
                {
-                       char* char_buf = buf_to_char(cmd->fields[i].out_value, cmd->fields[i].num_bits);
-                       buf_set_buf(cmd->fields[i].out_value, 0, *buffer, bit_count, cmd->fields[i].num_bits);
 #ifdef _DEBUG_JTAG_IO_
-                       DEBUG("fields[%i].out_value: %s", i, char_buf);
+                       char* char_buf = buf_to_str(cmd->fields[i].out_value, cmd->fields[i].num_bits, 16);
 #endif
+                       buf_set_buf(cmd->fields[i].out_value, 0, *buffer, bit_count, cmd->fields[i].num_bits);
+#ifdef _DEBUG_JTAG_IO_
+                       DEBUG("fields[%i].out_value: 0x%s", i, char_buf);
                        free(char_buf);
+#endif
                }
                
                bit_count += cmd->fields[i].num_bits;
@@ -991,8 +993,8 @@ int jtag_read_buffer(u8 *buffer, scan_command_t *cmd)
                        #ifdef _DEBUG_JTAG_IO_
                                char *char_buf;
 
-                               char_buf = buf_to_char(captured, num_bits);
-                               DEBUG("fields[%i].in_value: %s", i, char_buf);
+                               char_buf = buf_to_str(captured, num_bits, 16);
+                               DEBUG("fields[%i].in_value: 0x%s", i, char_buf);
                                free(char_buf);
                        #endif
 
@@ -1030,11 +1032,11 @@ int jtag_read_buffer(u8 *buffer, scan_command_t *cmd)
                                if ((cmd->fields[i].in_check_mask && buf_cmp_mask(captured, cmd->fields[i].in_check_value, cmd->fields[i].in_check_mask, num_bits))
                                        || (!cmd->fields[i].in_check_mask && buf_cmp(captured, cmd->fields[i].in_check_mask, num_bits)))
                                {
-                                       char *captured_char = buf_to_char(captured, num_bits);
-                                       char *in_check_value_char = buf_to_char(cmd->fields[i].in_check_value, num_bits);
-                                       char *in_check_mask_char = buf_to_char(cmd->fields[i].in_check_mask, num_bits);
+                                       char *captured_char = buf_to_str(captured, num_bits, 16);
+                                       char *in_check_value_char = buf_to_str(cmd->fields[i].in_check_value, num_bits, 16);
+                                       char *in_check_mask_char = buf_to_str(cmd->fields[i].in_check_mask, num_bits, 16);
                                        /* TODO: error reporting */
-                                       WARNING("value captured during scan didn't pass the requested check: captured: %s check_value: %s check_mask: %s", captured_char, in_check_value_char, in_check_mask_char);
+                                       WARNING("value captured during scan didn't pass the requested check: captured: 0x%s check_value: 0x%s check_mask: 0x%s", captured_char, in_check_value_char, in_check_mask_char);
                                        retval = ERROR_JTAG_QUEUE_FAILED;
                                        free(captured_char);
                                        free(in_check_value_char);
@@ -1144,8 +1146,8 @@ int jtag_validate_chain()
        {
                if (buf_get_u32(ir_test, chain_pos, 2) != 0x1)
                {
-                       char *cbuf = buf_to_char(ir_test, total_ir_length);
-                       ERROR("Error validating JTAG scan chain, IR mismatch, scan returned %s", cbuf);
+                       char *cbuf = buf_to_str(ir_test, total_ir_length, 16);
+                       ERROR("Error validating JTAG scan chain, IR mismatch, scan returned 0x%s", cbuf);
                        free(cbuf);
                        exit(-1);
                }
@@ -1155,8 +1157,8 @@ int jtag_validate_chain()
        
        if (buf_get_u32(ir_test, chain_pos, 2) != 0x3)
        {
-               char *cbuf = buf_to_char(ir_test, total_ir_length);
-               ERROR("Error validating JTAG scan chain, IR mismatch, scan returned %s", cbuf);
+               char *cbuf = buf_to_str(ir_test, total_ir_length, 16);
+               ERROR("Error validating JTAG scan chain, IR mismatch, scan returned 0x%s", cbuf);
                free(cbuf);
                exit(-1);
        }
index c0a2fe84b9d95d816e6b7fe3825a477147a4d35c..5bbb446beab00791f09f5519989348323134c94c 100644 (file)
@@ -464,6 +464,13 @@ int gdb_connection_closed(connection_t *connection)
        return ERROR_OK;
 }
 
+void gdb_send_error(connection_t *connection, u8 the_error)
+{
+    char err[4];
+    snprintf(err, 4, "E%2.2X", the_error );
+    gdb_put_packet(connection, err, 3);
+}
+
 int gdb_last_signal_packet(connection_t *connection, target_t *target, char* packet, int packet_size)
 {
        char sig_reply[4];
@@ -477,7 +484,63 @@ int gdb_last_signal_packet(connection_t *connection, target_t *target, char* pac
        return ERROR_OK;
 }
 
-void gdb_get_registers_packet(connection_t *connection, target_t *target, char* packet, int packet_size)
+void gdb_str_to_target(target_t *target, char *str, char *tstr)
+{
+       int str_len = strlen(str);
+       int i;
+       
+       if (str_len % 2)
+       {
+               ERROR("BUG: gdb value with uneven number of characters encountered");
+               exit(-1);
+       }
+       
+       if (target->endianness == TARGET_LITTLE_ENDIAN)
+       {
+               for (i = 0; i < str_len; i+=2)
+               {
+                       tstr[str_len - i - 1] = str[i + 1];
+                       tstr[str_len - i - 2] = str[i];
+               }
+       }
+       else
+       {
+               for (i = 0; i < str_len; i++)
+               {
+                       tstr[i] = str[i];
+               }
+       }       
+}
+
+void gdb_target_to_str(target_t *target, char *tstr, char *str)
+{
+       int str_len = strlen(tstr);
+       int i;
+
+       if (str_len % 2)
+       {
+               ERROR("BUG: gdb value with uneven number of characters encountered");
+               exit(-1);
+       }
+       
+       if (target->endianness == TARGET_LITTLE_ENDIAN)
+       {
+               for (i = 0; i < str_len; i+=2)
+               {
+                       str[str_len - i - 1] = tstr[i + 1];
+                       str[str_len - i - 2] = tstr[i];
+               }
+       }
+       else
+       {
+               for (i = 0; i < str_len; i++)
+               {
+                       str[i] = tstr[i];
+               }
+       }       
+}
+
+int gdb_get_registers_packet(connection_t *connection, target_t *target, char* packet, int packet_size)
 {
        reg_t **reg_list;
        int reg_list_size;
@@ -494,9 +557,10 @@ void gdb_get_registers_packet(connection_t *connection, target_t *target, char*
                switch (retval)
                {
                        case ERROR_TARGET_NOT_HALTED:
-                               ERROR("gdb requested registers, but we're not halted");
-                               exit(-1);
+                               ERROR("gdb requested registers but we're not halted, dropping connection");
+                               return ERROR_SERVER_REMOTE_CLOSED;
                        default:
+                               /* this is a bug condition - get_gdb_reg_list() may not return any other error */
                                ERROR("BUG: unexpected error returned by get_gdb_reg_list()");
                                exit(-1);
                }
@@ -512,14 +576,10 @@ void gdb_get_registers_packet(connection_t *connection, target_t *target, char*
        
        for (i = 0; i < reg_list_size; i++)
        {
-               int j;
-               char *hex_buf = buf_to_char(reg_list[i]->value, reg_list[i]->size);
+               char *hex_buf = buf_to_str(reg_list[i]->value, reg_list[i]->size, 16);
                DEBUG("hex_buf: %s", hex_buf);
-               for (j = CEIL(reg_list[i]->size, 8) * 2; j > 0; j -= 2)
-               {
-                       *reg_packet_p++ = hex_buf[j - 2];
-                       *reg_packet_p++ = hex_buf[j - 1];
-               }
+               gdb_str_to_target(target, hex_buf, reg_packet_p);
+               reg_packet_p += CEIL(reg_list[i]->size, 8) * 2;
                free(hex_buf);
        }
 
@@ -530,9 +590,12 @@ void gdb_get_registers_packet(connection_t *connection, target_t *target, char*
        gdb_put_packet(connection, reg_packet, CEIL(reg_packet_size, 8) * 2);
        free(reg_packet);
        
+       free(reg_list);
+       
+       return ERROR_OK;
 }
 
-void gdb_set_registers_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+int gdb_set_registers_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
 {
        int i;
        reg_t **reg_list;
@@ -548,8 +611,8 @@ void gdb_set_registers_packet(connection_t *connection, target_t *target, char *
 
        if (packet_size % 2)
        {
-               WARNING("GDB set_registers packet with uneven characters received");
-               return;
+               WARNING("GDB set_registers packet with uneven characters received, dropping connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
        }
 
        if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
@@ -557,9 +620,10 @@ void gdb_set_registers_packet(connection_t *connection, target_t *target, char *
                switch (retval)
                {
                        case ERROR_TARGET_NOT_HALTED:
-                               ERROR("gdb requested registers, but we're not halted");
-                               exit(-1);
+                               ERROR("gdb tried to registers but we're not halted, dropping connection");
+                               return ERROR_SERVER_REMOTE_CLOSED;
                        default:
+                               /* this is a bug condition - get_gdb_reg_list() may not return any other error */
                                ERROR("BUG: unexpected error returned by get_gdb_reg_list()");
                                exit(-1);
                }
@@ -568,23 +632,50 @@ void gdb_set_registers_packet(connection_t *connection, target_t *target, char *
        packet_p = packet;
        for (i = 0; i < reg_list_size; i++)
        {
-               char_to_buf(packet, CEIL(reg_list[i]->size, 8) * 2, reg_list[i]->value, reg_list[i]->size);
-               reg_list[i]->dirty = 1;
+               u8 *bin_buf;
+               char *hex_buf;
+               reg_arch_type_t *arch_type;
+               
+               /* convert from GDB-string (target-endian) to hex-string (big-endian) */
+               hex_buf = malloc(CEIL(reg_list[i]->size, 8) * 2);
+               gdb_target_to_str(target, packet_p, hex_buf);
+               
+               /* convert hex-string to binary buffer */
+               bin_buf = malloc(CEIL(reg_list[i]->size, 8));
+               str_to_buf(hex_buf, CEIL(reg_list[i]->size, 8) * 2, bin_buf, reg_list[i]->size, 16);
+
+               /* get register arch_type, and call set method */       
+               arch_type = register_get_arch_type(reg_list[i]->arch_type);
+               if (arch_type == NULL)
+               {
+                       ERROR("BUG: encountered unregistered arch type");
+                       exit(-1);
+               }
+               arch_type->set(reg_list[i], bin_buf);
+
+               /* advance packet pointer */            
+               packet_p += (CEIL(reg_list[i]->size, 8) * 2);
+               
+               free(bin_buf);
+               free(hex_buf);
        }
+       
+       /* free reg_t *reg_list[] array allocated by get_gdb_reg_list */ 
+       free(reg_list);
 
        gdb_put_packet(connection, "OK", 2);
+       
+       return ERROR_OK;
 }
 
-void gdb_get_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+int gdb_get_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
 {
-       char *hex_buf;
        char *reg_packet;
-       char *reg_packet_p;
        int reg_num = strtoul(packet + 1, NULL, 16);
        reg_t **reg_list;
        int reg_list_size;
        int retval;
-       int i;
+       char *hex_buf;
        
        DEBUG("");
        
@@ -593,9 +684,10 @@ void gdb_get_register_packet(connection_t *connection, target_t *target, char *p
                switch (retval)
                {
                        case ERROR_TARGET_NOT_HALTED:
-                               ERROR("gdb requested registers, but we're not halted");
-                               exit(-1);
+                               ERROR("gdb requested registers but we're not halted, dropping connection");
+                               return ERROR_SERVER_REMOTE_CLOSED;
                        default:
+                               /* this is a bug condition - get_gdb_reg_list() may not return any other error */
                                ERROR("BUG: unexpected error returned by get_gdb_reg_list()");
                                exit(-1);
                }
@@ -607,30 +699,32 @@ void gdb_get_register_packet(connection_t *connection, target_t *target, char *p
                exit(-1);
        }
 
-       hex_buf = buf_to_char(reg_list[reg_num]->value, reg_list[reg_num]->size);
-       reg_packet = reg_packet_p = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);
+       reg_packet = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);
+
+       hex_buf = buf_to_str(reg_list[reg_num]->value, reg_list[reg_num]->size, 16);
        
-       for (i = CEIL(reg_list[reg_num]->size, 8) * 2; i > 0; i -= 2)
-       {
-               *reg_packet_p++ = hex_buf[i - 2];
-               *reg_packet_p++ = hex_buf[i - 1];
-       }
+       gdb_str_to_target(target, reg_packet, hex_buf);
        
        gdb_put_packet(connection, reg_packet, CEIL(reg_list[reg_num]->size, 8) * 2);
        
+       free(reg_list);
        free(reg_packet);
        free(hex_buf);
        
+       return ERROR_OK;
 }
 
-void gdb_set_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+int gdb_set_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
 {
        char *separator;
+       char *hex_buf;
+       u8 *bin_buf;
        int reg_num = strtoul(packet + 1, &separator, 16);
        reg_t **reg_list;
        int reg_list_size;
        int retval;
-
+       reg_arch_type_t *arch_type;
+       
        DEBUG("");
        
        if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
@@ -638,9 +732,10 @@ void gdb_set_register_packet(connection_t *connection, target_t *target, char *p
                switch (retval)
                {
                        case ERROR_TARGET_NOT_HALTED:
-                               ERROR("gdb requested registers, but we're not halted");
-                               exit(-1);
+                               ERROR("gdb tried to set a register but we're not halted, dropping connection");
+                               return ERROR_SERVER_REMOTE_CLOSED;
                        default:
+                               /* this is a bug condition - get_gdb_reg_list() may not return any other error */
                                ERROR("BUG: unexpected error returned by get_gdb_reg_list()");
                                exit(-1);
                }
@@ -649,23 +744,67 @@ void gdb_set_register_packet(connection_t *connection, target_t *target, char *p
        if (reg_list_size < reg_num)
        {
                ERROR("gdb requested a non-existing register");
-               exit(-1);
+               return ERROR_SERVER_REMOTE_CLOSED;
        }
 
        if (*separator != '=')
        {
-               ERROR("GDB set register packet, but no '=' following the register number");
-               exit(-1);
+               ERROR("GDB 'set register packet', but no '=' following the register number");
+               return ERROR_SERVER_REMOTE_CLOSED;
        }
        
-       char_to_buf(separator + 1, CEIL(reg_list[reg_num]->size, 8) * 2, reg_list[reg_num]->value, reg_list[reg_num]->size);
-       reg_list[reg_num]->dirty = 1;
+       /* convert from GDB-string (target-endian) to hex-string (big-endian) */
+       hex_buf = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);
+       gdb_target_to_str(target, separator + 1, hex_buf);
+       
+       /* convert hex-string to binary buffer */
+       bin_buf = malloc(CEIL(reg_list[reg_num]->size, 8));
+       str_to_buf(hex_buf, CEIL(reg_list[reg_num]->size, 8) * 2, bin_buf, reg_list[reg_num]->size, 16);
+
+       /* get register arch_type, and call set method */       
+       arch_type = register_get_arch_type(reg_list[reg_num]->arch_type);
+       if (arch_type == NULL)
+       {
+               ERROR("BUG: encountered unregistered arch type");
+               exit(-1);
+       }
+       arch_type->set(reg_list[reg_num], bin_buf);
 
        gdb_put_packet(connection, "OK", 2);
 
+       free(bin_buf);
+       free(hex_buf);
+       free(reg_list);
+
+       return ERROR_OK;
 }
 
-void gdb_read_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+int gdb_memory_packet_error(connection_t *connection, int retval)
+{
+       switch (retval)
+       {
+               case ERROR_TARGET_NOT_HALTED:
+                       ERROR("gdb tried to read memory but we're not halted, dropping connection");
+                       return ERROR_SERVER_REMOTE_CLOSED;
+                       break;
+               case ERROR_TARGET_DATA_ABORT:
+                       gdb_send_error(connection, EIO);
+                       break;
+               case ERROR_TARGET_TRANSLATION_FAULT:
+                       gdb_send_error(connection, EFAULT);
+                       break;
+               case ERROR_TARGET_UNALIGNED_ACCESS:
+                       gdb_send_error(connection, EFAULT);
+                       break;
+               default:
+                       ERROR("BUG: unexpected error %i", retval);
+                       exit(-1);
+       }
+       
+       return ERROR_OK;
+}
+
+int gdb_read_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
 {
        char *separator;
        u32 addr = 0;
@@ -675,6 +814,7 @@ void gdb_read_memory_packet(connection_t *connection, target_t *target, char *pa
        char *hex_buffer;
 
        int i;
+       int retval;
 
        /* skip command character */
        packet++;
@@ -682,7 +822,10 @@ void gdb_read_memory_packet(connection_t *connection, target_t *target, char *pa
        addr = strtoul(packet, &separator, 16);
        
        if (*separator != ',')
-               return;
+       {
+               ERROR("incomplete read memory packet received, dropping connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
 
        len = strtoul(separator+1, NULL, 16);
 
@@ -694,35 +837,46 @@ void gdb_read_memory_packet(connection_t *connection, target_t *target, char *pa
        {
                case 4:
                        if ((addr % 4) == 0)
-                               target->type->read_memory(target, addr, 4, 1, buffer);
+                               retval = target->type->read_memory(target, addr, 4, 1, buffer);
                        else
-                               target->type->read_memory(target, addr, 1, len, buffer);
+                               retval = target->type->read_memory(target, addr, 1, len, buffer);
                        break;
                case 2:
                        if ((addr % 2) == 0)
-                               target->type->read_memory(target, addr, 2, 1, buffer);
+                               retval = target->type->read_memory(target, addr, 2, 1, buffer);
                        else
-                               target->type->read_memory(target, addr, 1, len, buffer);
+                               retval = target->type->read_memory(target, addr, 1, len, buffer);
                        break;
                default:
                        if (((addr % 4) == 0) && ((len % 4) == 0))
-                               target->type->read_memory(target, addr, 4, len / 4, buffer);
+                               retval = target->type->read_memory(target, addr, 4, len / 4, buffer);
                        else
-                               target->type->read_memory(target, addr, 1, len, buffer);
+                               retval = target->type->read_memory(target, addr, 1, len, buffer);
        }
 
-       hex_buffer = malloc(len * 2 + 1);
+       if (retval == ERROR_OK)
+       {
+               hex_buffer = malloc(len * 2 + 1);
+               
+               for (i=0; i<len; i++)
+                       snprintf(hex_buffer + 2*i, 3, "%2.2x", buffer[i]);
        
-       for (i=0; i<len; i++)
-               snprintf(hex_buffer + 2*i, 3, "%2.2x", buffer[i]);
-
-       gdb_put_packet(connection, hex_buffer, len * 2);
+               gdb_put_packet(connection, hex_buffer, len * 2);
        
-       free(hex_buffer);
+               free(hex_buffer);
+       }
+       else
+       {
+               if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)
+                       return retval; 
+       }
+
        free(buffer);
+       
+       return ERROR_OK;
 }
 
-void gdb_write_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+int gdb_write_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
 {
        char *separator;
        u32 addr = 0;
@@ -731,6 +885,7 @@ void gdb_write_memory_packet(connection_t *connection, target_t *target, char *p
        u8 *buffer;
 
        int i;
+       int retval;
 
        /* skip command character */
        packet++;
@@ -738,12 +893,18 @@ void gdb_write_memory_packet(connection_t *connection, target_t *target, char *p
        addr = strtoul(packet, &separator, 16);
        
        if (*separator != ',')
-               return;
+       {
+               ERROR("incomplete write memory packet received, dropping connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
 
        len = strtoul(separator+1, &separator, 16);
 
        if (*(separator++) != ':')
-               return;
+       {
+               ERROR("incomplete write memory packet received, dropping connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
 
        buffer = malloc(len);
 
@@ -761,38 +922,49 @@ void gdb_write_memory_packet(connection_t *connection, target_t *target, char *p
                /* handle sized writes */
                case 4:
                        if ((addr % 4) == 0)
-                               target->type->write_memory(target, addr, 4, 1, buffer);
+                               retval = target->type->write_memory(target, addr, 4, 1, buffer);
                        else
-                               target->type->write_memory(target, addr, 1, len, buffer);
+                               retval = target->type->write_memory(target, addr, 1, len, buffer);
                        break;
                case 2:
                        if ((addr % 2) == 0)
-                               target->type->write_memory(target, addr, 2, 1, buffer);
+                               retval = target->type->write_memory(target, addr, 2, 1, buffer);
                        else
-                               target->type->write_memory(target, addr, 1, len, buffer);
+                               retval = target->type->write_memory(target, addr, 1, len, buffer);
                        break;
                case 3:
                case 1:
-                       target->type->write_memory(target, addr, 1, len, buffer);
+                       retval = target->type->write_memory(target, addr, 1, len, buffer);
                        break;
                /* handle bulk writes */
                default:
-                       target_write_buffer(target, addr, len, buffer);
+                       retval = target_write_buffer(target, addr, len, buffer);
                        break;
        }
 
-       gdb_put_packet(connection, "OK", 2);
+       if (retval == ERROR_OK)
+       {
+               gdb_put_packet(connection, "OK", 2);
+       }
+       else
+       {
+               if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)
+                       return retval; 
+       }
        
        free(buffer);
+       
+       return ERROR_OK;
 }
 
-void gdb_write_memory_binary_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+int gdb_write_memory_binary_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
 {
        char *separator;
        u32 addr = 0;
        u32 len = 0;
 
        u8 *buffer;
+       int retval;
 
        /* skip command character */
        packet++;
@@ -800,12 +972,18 @@ void gdb_write_memory_binary_packet(connection_t *connection, target_t *target,
        addr = strtoul(packet, &separator, 16);
        
        if (*separator != ',')
-               return;
+       {
+               ERROR("incomplete write memory binary packet received, dropping connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
 
        len = strtoul(separator+1, &separator, 16);
 
        if (*(separator++) != ':')
-               return;
+       {
+               ERROR("incomplete write memory binary packet received, dropping connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
 
        if( len ) {
                
@@ -819,29 +997,39 @@ void gdb_write_memory_binary_packet(connection_t *connection, target_t *target,
                {
                        case 4:
                                if ((addr % 4) == 0)
-                                       target->type->write_memory(target, addr, 4, 1, buffer);
+                                       retval = target->type->write_memory(target, addr, 4, 1, buffer);
                                else
-                                       target->type->write_memory(target, addr, 1, len, buffer);
+                                       retval = target->type->write_memory(target, addr, 1, len, buffer);
                                break;
                        case 2:
                                if ((addr % 2) == 0)
-                                       target->type->write_memory(target, addr, 2, 1, buffer);
+                                       retval = target->type->write_memory(target, addr, 2, 1, buffer);
                                else
-                                       target->type->write_memory(target, addr, 1, len, buffer);
+                                       retval = target->type->write_memory(target, addr, 1, len, buffer);
                                break;
                        case 3:
                        case 1:
-                               target->type->write_memory(target, addr, 1, len, buffer);
+                               retval = target->type->write_memory(target, addr, 1, len, buffer);
                                break;
                        default:
-                               target_write_buffer(target, addr, len, buffer);
+                               retval = target_write_buffer(target, addr, len, buffer);
                                break;
                }
                
                free(buffer);
        }
 
-       gdb_put_packet(connection, "OK", 2);
+       if (retval == ERROR_OK)
+       {
+               gdb_put_packet(connection, "OK", 2);
+       }
+       else
+       {
+               if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)
+                       return retval; 
+       }
+       
+       return ERROR_OK;
 }
 
 void gdb_step_continue_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
@@ -853,7 +1041,6 @@ void gdb_step_continue_packet(connection_t *connection, target_t *target, char *
 
        if (packet_size > 1)
        {
-               u32 address = 0;
                packet[packet_size] = 0;
                address = strtoul(packet + 1, NULL, 16);
        }
@@ -874,7 +1061,26 @@ void gdb_step_continue_packet(connection_t *connection, target_t *target, char *
        }
 }
 
-void gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+int gdb_bp_wp_packet_error(connection_t *connection, int retval)
+{
+       switch (retval)
+       {
+               case ERROR_TARGET_NOT_HALTED:
+                       ERROR("gdb tried to set a breakpoint but we're not halted, dropping connection");
+                       return ERROR_SERVER_REMOTE_CLOSED;
+                       break;
+               case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
+                       gdb_send_error(connection, EBUSY);
+                       break;
+               default:
+                       ERROR("BUG: unexpected error %i", retval);
+                       exit(-1);
+       }
+       
+       return ERROR_OK;
+}
+
+int gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
 {
        int type;
        enum breakpoint_type bp_type;
@@ -900,12 +1106,18 @@ void gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target
                wp_type = WPT_ACCESS;
                
        if (*separator != ',')
-               return;
+       {
+               ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
 
        address = strtoul(separator+1, &separator, 16);
 
        if (*separator != ',')
-               return;
+       {
+               ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
 
        size = strtoul(separator+1, &separator, 16);
 
@@ -917,41 +1129,53 @@ void gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target
                        {
                                if ((retval = breakpoint_add(target, address, size, bp_type)) != ERROR_OK)
                                {
-                                       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
-                                       {
-                                               gdb_put_packet(connection, "E00", 3);
-                                               break;
-                                       }
+                                       if ((retval = gdb_bp_wp_packet_error(connection, retval)) != ERROR_OK)
+                                               return retval;
+                               }
+                               else
+                               {
+                                       gdb_put_packet(connection, "OK", 2);
                                }
                        }
                        else
                        {
                                breakpoint_remove(target, address);
+                               gdb_put_packet(connection, "OK", 2);
                        }
-                       gdb_put_packet(connection, "OK", 2);
                        break;
                case 2:
                case 3:
                case 4:
                {
                        if (packet[0] == 'Z')
-                               watchpoint_add(target, address, size, type-2, 0, 0xffffffffu);
+                       {
+                               if ((retval = watchpoint_add(target, address, size, type-2, 0, 0xffffffffu)) != ERROR_OK)
+                               {
+                                       if ((retval = gdb_bp_wp_packet_error(connection, retval)) != ERROR_OK)
+                                               return retval;
+                               }
+                               else
+                               {
+                                       gdb_put_packet(connection, "OK", 2);
+                               }
+                       }
                        else
+                       {
                                watchpoint_remove(target, address);
-                       gdb_put_packet(connection, "OK", 2);
+                               gdb_put_packet(connection, "OK", 2);
+                       }
                        break;
                }
                default:
                        break;
        }
 
+       return ERROR_OK;
 }
 
 void gdb_query_packet(connection_t *connection, char *packet, int packet_size)
 {
        command_context_t *cmd_ctx = connection->cmd_ctx;
-       gdb_service_t *gdb_service = connection->service->priv;
-       target_t *target = gdb_service->target;
 
        if (strstr(packet, "qRcmd,"))
        {
@@ -1000,7 +1224,7 @@ int gdb_input(connection_t *connection)
                                case ERROR_SERVER_REMOTE_CLOSED:
                                        return ERROR_SERVER_REMOTE_CLOSED;
                                default:
-                                       ERROR("unexpected error");
+                                       ERROR("BUG: unexpected error");
                                        exit(-1);
                        }
                }
@@ -1012,6 +1236,7 @@ int gdb_input(connection_t *connection)
                
                if (packet_size > 0)
                {
+                       retval = ERROR_OK;
                        switch (packet[0])
                        {
                                case 'H':
@@ -1023,26 +1248,26 @@ int gdb_input(connection_t *connection)
                                        gdb_query_packet(connection, packet, packet_size);
                                        break;
                                case 'g':
-                                       gdb_get_registers_packet(connection, target, packet, packet_size);
+                                       retval = gdb_get_registers_packet(connection, target, packet, packet_size);
                                        break;
                                case 'G':
-                                       gdb_set_registers_packet(connection, target, packet, packet_size);
+                                       retval = gdb_set_registers_packet(connection, target, packet, packet_size);
                                        break;
                                case 'p':
-                                       gdb_get_register_packet(connection, target, packet, packet_size);
+                                       retval = gdb_get_register_packet(connection, target, packet, packet_size);
                                        break;
                                case 'P':
-                                       gdb_set_register_packet(connection, target, packet, packet_size);
+                                       retval = gdb_set_register_packet(connection, target, packet, packet_size);
                                        break;
                                case 'm':
-                                       gdb_read_memory_packet(connection, target, packet, packet_size);
+                                       retval = gdb_read_memory_packet(connection, target, packet, packet_size);
                                        break;
                                case 'M':
-                                       gdb_write_memory_packet(connection, target, packet, packet_size);
+                                       retval = gdb_write_memory_packet(connection, target, packet, packet_size);
                                        break;
                                case 'z':
                                case 'Z':
-                                       gdb_breakpoint_watchpoint_packet(connection, target, packet, packet_size);
+                                       retval = gdb_breakpoint_watchpoint_packet(connection, target, packet, packet_size);
                                        break;
                                case '?':
                                        gdb_last_signal_packet(connection, target, packet, packet_size);
@@ -1056,7 +1281,8 @@ int gdb_input(connection_t *connection)
                                        gdb_put_packet(connection, "OK", 2);
                                        break;
                                case 'X':
-                                       gdb_write_memory_binary_packet(connection, target, packet, packet_size);
+                                       if ((retval = gdb_write_memory_binary_packet(connection, target, packet, packet_size)) != ERROR_OK)
+                                               return retval;
                                        break;
                                case 'k':
                                        gdb_put_packet(connection, "OK", 2);
@@ -1067,6 +1293,10 @@ int gdb_input(connection_t *connection)
                                        gdb_put_packet(connection, NULL, 0);
                                        break;
                        }
+                       
+                       /* if a packet handler returned an error, exit input loop */
+                       if (retval != ERROR_OK)
+                               return retval;
                }
                                
                if (gdb_con->ctrl_c)
index b7cfea8051be02c810e8f6a12922b6ce09f1dd99..f5f4a209f2b012fd36f8d628243acf3d44657bde 100644 (file)
@@ -70,6 +70,8 @@ target_type_t arm966e_target =
        .write_memory = arm7_9_write_memory,
        .bulk_write_memory = arm7_9_bulk_write_memory,
 
+       .run_algorithm = armv4_5_run_algorithm,
+       
        .add_breakpoint = arm7_9_add_breakpoint,
        .remove_breakpoint = arm7_9_remove_breakpoint,
        .add_watchpoint = arm7_9_add_watchpoint,
index 7584a8bbdb5893f56cffde1b592753650e19f023..ccd30312d253af77b7d817cf9620d8d64621f1a3 100644 (file)
@@ -68,6 +68,8 @@ target_type_t arm9tdmi_target =
        .write_memory = arm7_9_write_memory,
        .bulk_write_memory = arm7_9_bulk_write_memory,
 
+       .run_algorithm = armv4_5_run_algorithm,
+       
        .add_breakpoint = arm7_9_add_breakpoint,
        .remove_breakpoint = arm7_9_remove_breakpoint,
        .add_watchpoint = arm7_9_add_watchpoint,
index 86d5dc89d553e94a2659ea29835c570531e351c6..00fb2f07856fe0c3d300990a87ceecde212e09a3 100644 (file)
@@ -223,16 +223,42 @@ int armv4_5_get_core_reg(reg_t *reg)
        return retval;
 }
 
-int armv4_5_set_core_reg(reg_t *reg, u32 value)
+int armv4_5_set_core_reg(reg_t *reg, u8 *buf)
 {
        armv4_5_core_reg_t *armv4_5 = reg->arch_info;
        target_t *target = armv4_5->target;
+       armv4_5_common_t *armv4_5_target = target->arch_info;
+       u32 value = buf_get_u32(buf, 0, 32);
                
        if (target->state != TARGET_HALTED)
        {
                return ERROR_TARGET_NOT_HALTED;
        }
        
+       if (reg == &armv4_5_target->core_cache->reg_list[ARMV4_5_CPSR])
+       {
+               if (value & 0x20)
+               {
+                       /* T bit should be set */
+                       if (armv4_5_target->core_state == ARMV4_5_STATE_ARM)
+                       {
+                               /* change state to Thumb */
+                               DEBUG("changing to Thumb state");
+                               armv4_5_target->core_state = ARMV4_5_STATE_THUMB;       
+                       }
+               }
+               else
+               {
+                       /* T bit should be cleared */
+                       if (armv4_5_target->core_state == ARMV4_5_STATE_THUMB)
+                       {
+                               /* change state to ARM */
+                               DEBUG("changing to ARM state");
+                               armv4_5_target->core_state = ARMV4_5_STATE_ARM; 
+                       }
+               }
+       }
+       
        buf_set_u32(reg->value, 0, 32, value);
        reg->dirty = 1;
        reg->valid = 1;
@@ -518,7 +544,7 @@ int armv4_5_run_algorithm(struct target_s *target, int num_mem_params, mem_param
                        exit(-1);
                }
                
-               armv4_5_set_core_reg(reg, buf_get_u32(reg_params[i].value, 0, 32));
+               armv4_5_set_core_reg(reg, reg_params[i].value);
        }
        
        armv4_5->core_state = armv4_5_algorithm_info->core_state;
index 0cb4e01704b7af96674ca358fee1c727e105ef8a..b063bd2c35f15051e97d9c2da999e7788d009ab1 100644 (file)
@@ -78,6 +78,7 @@ int embeddedice_reg_arch_type = -1;
 
 int embeddedice_get_reg(reg_t *reg);
 int embeddedice_set_reg(reg_t *reg, u32 value);
+int embeddedice_set_reg_w_exec(reg_t *reg, u8 *buf);
 
 int embeddedice_write_reg(reg_t *reg, u32 value);
 int embeddedice_read_reg(reg_t *reg);
@@ -231,9 +232,9 @@ int embeddedice_set_reg(reg_t *reg, u32 value)
        return ERROR_OK;
 }
 
-int embeddedice_set_reg_w_exec(reg_t *reg, u32 value)
+int embeddedice_set_reg_w_exec(reg_t *reg, u8 *buf)
 {
-       embeddedice_set_reg(reg, value);
+       embeddedice_set_reg(reg, buf_get_u32(buf, 0, reg->size));
        
        if (jtag_execute_queue() != ERROR_OK)
        {
index 8631e7b93e29e9670f2ea6fc24e250c0e5213367..eedc21912fbea20941d3681dafb929874a520404 100644 (file)
@@ -95,6 +95,6 @@ extern int embeddedice_write_reg(reg_t *reg, u32 value);
 extern int embeddedice_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask);
 extern int embeddedice_store_reg(reg_t *reg);
 extern int embeddedice_set_reg(reg_t *reg, u32 value);
-extern int embeddedice_set_reg_w_exec(reg_t *reg, u32 value);
+extern int embeddedice_set_reg_w_exec(reg_t *reg, u8 *buf);
 
 #endif /* EMBEDDED_ICE_H */
index a6b63451d076797ecc2888bc3b01deb7f058602d..9c82acc926272ca183da3eb663aba036550ec386 100644 (file)
@@ -199,6 +199,7 @@ int etm_reg_arch_type = -1;
 
 int etm_get_reg(reg_t *reg);
 int etm_set_reg(reg_t *reg, u32 value);
+int etm_set_reg_w_exec(reg_t *reg, u8 *buf);
 
 int etm_write_reg(reg_t *reg, u32 value);
 int etm_read_reg(reg_t *reg);
@@ -338,9 +339,9 @@ int etm_set_reg(reg_t *reg, u32 value)
        return ERROR_OK;
 }
 
-int etm_set_reg_w_exec(reg_t *reg, u32 value)
+int etm_set_reg_w_exec(reg_t *reg, u8 *buf)
 {
-       etm_set_reg(reg, value);
+       etm_set_reg(reg, buf_get_u32(buf, 0, reg->size));
        
        if (jtag_execute_queue() != ERROR_OK)
        {
index dbe78f35ed342455af72b33da31ab277b01eb2e0..4b24e5c8800bc390d3b3cb70bb4f34ffee5ef884 100644 (file)
@@ -71,6 +71,6 @@ extern int etm_write_reg(reg_t *reg, u32 value);
 extern int etm_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask);\r
 extern int etm_store_reg(reg_t *reg);\r
 extern int etm_set_reg(reg_t *reg, u32 value);\r
-extern int etm_set_reg_w_exec(reg_t *reg, u32 value);\r
+extern int etm_set_reg_w_exec(reg_t *reg, u8 *buf);\r
 \r
 #endif /* ETM_H */\r
index 182ff9a22ef7fe315fc963ddac46cee39477ab83..2adf73e7590e601f0c6d47cbf62c94f3a05be20c 100644 (file)
@@ -66,7 +66,7 @@ reg_cache_t** register_get_last_cache_p(reg_cache_t **first)
        return cache_p;
 }
 
-int register_reg_arch_type(int (*get)(reg_t *reg), int (*set)(reg_t *reg, u32 value))
+int register_reg_arch_type(int (*get)(reg_t *reg), int (*set)(reg_t *reg, u8 *buf))
 {
        reg_arch_type_t** arch_type_p = &reg_arch_types;
        int id = 0;
index 8a903eddf24a380e8351371069eeef3acc59ede5..456ab5901c443ea227dc95dfec6dedccc673a9b3 100644 (file)
@@ -56,13 +56,13 @@ typedef struct reg_arch_type_s
 {
        int id;
        int (*get)(reg_t *reg);
-       int (*set)(reg_t *reg, u32 value);
+       int (*set)(reg_t *reg, u8 *buf);
        struct reg_arch_type_s *next;
 } reg_arch_type_t;
 
 extern reg_t* register_get_by_name(reg_cache_t *first, char *name, int search_all);
 extern reg_cache_t** register_get_last_cache_p(reg_cache_t **first);
-extern int register_reg_arch_type(int (*get)(reg_t *reg), int (*set)(reg_t *reg, u32 value));
+extern int register_reg_arch_type(int (*get)(reg_t *reg), int (*set)(reg_t *reg, u8 *buf));
 extern reg_arch_type_t* register_get_arch_type(int id);
 
 #endif /* REGISTER_H */
index f1229d86f48857714e4719fdda3592852e9064c7..531d632e698384ddec9dd321be8e12c84a0afe1d 100644 (file)
@@ -1085,7 +1085,7 @@ int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args
                        int i;
                        for (i = 0; i < cache->num_regs; i++)
                        {
-                               value = buf_to_char(cache->reg_list[i].value, cache->reg_list[i].size);
+                               value = buf_to_str(cache->reg_list[i].value, cache->reg_list[i].size, 16);
                                command_print(cmd_ctx, "(%i) %s (/%i): 0x%s (dirty: %i, valid: %i)", count++, cache->reg_list[i].name, cache->reg_list[i].size, value, cache->reg_list[i].dirty, cache->reg_list[i].valid);
                                free(value);
                        }
@@ -1150,7 +1150,7 @@ int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args
                        }
                        arch_type->get(reg);
                }
-               value = buf_to_char(reg->value, reg->size);
+               value = buf_to_str(reg->value, reg->size, 16);
                command_print(cmd_ctx, "%s (/%i): 0x%s", reg->name, reg->size, value);
                free(value);
                return ERROR_OK;
@@ -1159,7 +1159,9 @@ int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args
        /* set register value */
        if (argc == 2)
        {
-               u32 new_value = strtoul(args[1], NULL, 0);
+               u8 *buf = malloc(CEIL(reg->size, 8));
+               str_to_buf(args[1], strlen(args[1]), buf, reg->size, 0);
+
                reg_arch_type_t *arch_type = register_get_arch_type(reg->arch_type);
                if (arch_type == NULL)
                {
@@ -1167,11 +1169,14 @@ int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args
                        return ERROR_OK;
                }
                
-               arch_type->set(reg, new_value);
-               value = buf_to_char(reg->value, reg->size);
+               arch_type->set(reg, buf);
+               
+               value = buf_to_str(reg->value, reg->size, 16);
                command_print(cmd_ctx, "%s (/%i): 0x%s", reg->name, reg->size, value);
                free(value);
                
+               free(buf);
+               
                return ERROR_OK;
        }
        
@@ -1684,7 +1689,7 @@ int handle_bp_command(struct command_context_s *cmd_ctx, char *cmd, char **args,
                {
                        if (breakpoint->type == BKPT_SOFT)
                        {
-                               char* buf = buf_to_char(breakpoint->orig_instr, breakpoint->length);
+                               char* buf = buf_to_str(breakpoint->orig_instr, breakpoint->length, 16);
                                command_print(cmd_ctx, "0x%8.8x, 0x%x, %i, 0x%s", breakpoint->address, breakpoint->length, breakpoint->set, buf);
                                free(buf);
                        }

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)