diff options
42 files changed, 32837 insertions, 32837 deletions
diff --git a/src/flash/at91sam7.h b/src/flash/at91sam7.h index 4ef154c..eb0213c 100644 --- a/src/flash/at91sam7.h +++ b/src/flash/at91sam7.h @@ -1,100 +1,100 @@ -/***************************************************************************
- * Copyright (C) 2006 by Magnus Lundin *
- * lundin@mlu.mine.nu *
- * *
- * 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 AT91SAM7_H
-#define AT91SAM7_H
-
-#include "flash.h"
-#include "target.h"
-
-typedef struct at91sam7_flash_bank_s
-{
- u32 working_area;
- u32 working_area_size;
-
- /* chip id register */
- u32 cidr;
- u16 cidr_ext;
- u16 cidr_nvptyp;
- u16 cidr_arch;
- u16 cidr_sramsiz;
- u16 cidr_nvpsiz;
- u16 cidr_nvpsiz2;
- u16 cidr_eproc;
- u16 cidr_version;
- char * target_name;
-
- /* flash geometry */
- u16 num_pages;
- u16 pagesize;
- u16 pages_in_lockregion;
- u8 num_erase_regions;
- u8 num_planes;
- u32 *erase_region_info;
-
- /* nv memory bits */
- u16 num_lockbits;
- u16 lockbits[4];
- u16 num_nvmbits;
- u16 nvmbits;
- u8 securitybit;
- u8 flashmode[4]; /* 0: not init, 1: fmcn for nvbits (1uS), 2: fmcn for flash (1.5uS) */
-
- /* main clock status */
- u8 mck_valid;
- u32 mck_freq;
-
- int probed;
-
-} at91sam7_flash_bank_t;
-
-/* AT91SAM7 control registers */
-#define DBGU_CIDR 0xFFFFF240
-#define CKGR_MCFR 0xFFFFFC24
-#define CKGR_MCFR_MAINRDY 0x10000
-#define CKGR_PLLR 0xFFFFFC2c
-#define CKGR_PLLR_DIV 0xff
-#define CKGR_PLLR_MUL 0x07ff0000
-#define PMC_MCKR 0xFFFFFC30
-#define PMC_MCKR_CSS 0x03
-#define PMC_MCKR_PRES 0x1c
-
-/* Flash Controller Commands */
-#define WP 0x01
-#define SLB 0x02
-#define WPL 0x03
-#define CLB 0x04
-#define EA 0x08
-#define SGPB 0x0B
-#define CGPB 0x0D
-#define SSB 0x0F
-
-/* MC_FSR bit definitions */
-#define MC_FSR_FRDY 1
-#define MC_FSR_EOL 2
-
-/* AT91SAM7 constants */
-#define RC_FREQ 32000
-
-/* FLASH_TIMING_MODES */
-#define FMR_TIMING_NONE 0
-#define FMR_TIMING_NVBITS 1
-#define FMR_TIMING_FLASH 2
-
-#endif /* AT91SAM7_H */
+/*************************************************************************** + * Copyright (C) 2006 by Magnus Lundin * + * lundin@mlu.mine.nu * + * * + * 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 AT91SAM7_H +#define AT91SAM7_H + +#include "flash.h" +#include "target.h" + +typedef struct at91sam7_flash_bank_s +{ + u32 working_area; + u32 working_area_size; + + /* chip id register */ + u32 cidr; + u16 cidr_ext; + u16 cidr_nvptyp; + u16 cidr_arch; + u16 cidr_sramsiz; + u16 cidr_nvpsiz; + u16 cidr_nvpsiz2; + u16 cidr_eproc; + u16 cidr_version; + char * target_name; + + /* flash geometry */ + u16 num_pages; + u16 pagesize; + u16 pages_in_lockregion; + u8 num_erase_regions; + u8 num_planes; + u32 *erase_region_info; + + /* nv memory bits */ + u16 num_lockbits; + u16 lockbits[4]; + u16 num_nvmbits; + u16 nvmbits; + u8 securitybit; + u8 flashmode[4]; /* 0: not init, 1: fmcn for nvbits (1uS), 2: fmcn for flash (1.5uS) */ + + /* main clock status */ + u8 mck_valid; + u32 mck_freq; + + int probed; + +} at91sam7_flash_bank_t; + +/* AT91SAM7 control registers */ +#define DBGU_CIDR 0xFFFFF240 +#define CKGR_MCFR 0xFFFFFC24 +#define CKGR_MCFR_MAINRDY 0x10000 +#define CKGR_PLLR 0xFFFFFC2c +#define CKGR_PLLR_DIV 0xff +#define CKGR_PLLR_MUL 0x07ff0000 +#define PMC_MCKR 0xFFFFFC30 +#define PMC_MCKR_CSS 0x03 +#define PMC_MCKR_PRES 0x1c + +/* Flash Controller Commands */ +#define WP 0x01 +#define SLB 0x02 +#define WPL 0x03 +#define CLB 0x04 +#define EA 0x08 +#define SGPB 0x0B +#define CGPB 0x0D +#define SSB 0x0F + +/* MC_FSR bit definitions */ +#define MC_FSR_FRDY 1 +#define MC_FSR_EOL 2 + +/* AT91SAM7 constants */ +#define RC_FREQ 32000 + +/* FLASH_TIMING_MODES */ +#define FMR_TIMING_NONE 0 +#define FMR_TIMING_NVBITS 1 +#define FMR_TIMING_FLASH 2 + +#endif /* AT91SAM7_H */ diff --git a/src/flash/cfi.c b/src/flash/cfi.c index 82120d8..88e8e63 100644 --- a/src/flash/cfi.c +++ b/src/flash/cfi.c @@ -1,2355 +1,2355 @@ -/***************************************************************************
- * Copyright (C) 2005, 2007 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 "cfi.h"
-
-#include "flash.h"
-#include "target.h"
-#include "log.h"
-#include "armv4_5.h"
-#include "algorithm.h"
-#include "binarybuffer.h"
-#include "types.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-int cfi_register_commands(struct command_context_s *cmd_ctx);
-int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
-int cfi_erase(struct flash_bank_s *bank, int first, int last);
-int cfi_protect(struct flash_bank_s *bank, int set, int first, int last);
-int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
-int cfi_probe(struct flash_bank_s *bank);
-int cfi_auto_probe(struct flash_bank_s *bank);
-int cfi_erase_check(struct flash_bank_s *bank);
-int cfi_protect_check(struct flash_bank_s *bank);
-int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size);
-
-int cfi_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-#define CFI_MAX_BUS_WIDTH 4
-#define CFI_MAX_CHIP_WIDTH 4
-
-/* defines internal maximum size for code fragment in cfi_intel_write_block() */
-#define CFI_MAX_INTEL_CODESIZE 256
-
-flash_driver_t cfi_flash =
-{
- .name = "cfi",
- .register_commands = cfi_register_commands,
- .flash_bank_command = cfi_flash_bank_command,
- .erase = cfi_erase,
- .protect = cfi_protect,
- .write = cfi_write,
- .probe = cfi_probe,
- .auto_probe = cfi_auto_probe,
- .erase_check = cfi_erase_check,
- .protect_check = cfi_protect_check,
- .info = cfi_info
-};
-
-cfi_unlock_addresses_t cfi_unlock_addresses[] =
-{
- [CFI_UNLOCK_555_2AA] = { .unlock1 = 0x555, .unlock2 = 0x2aa },
- [CFI_UNLOCK_5555_2AAA] = { .unlock1 = 0x5555, .unlock2 = 0x2aaa },
-};
-
-/* CFI fixups foward declarations */
-void cfi_fixup_non_cfi(flash_bank_t *flash, void *param);
-void cfi_fixup_0002_erase_regions(flash_bank_t *flash, void *param);
-void cfi_fixup_0002_unlock_addresses(flash_bank_t *flash, void *param);
-void cfi_fixup_atmel_reversed_erase_regions(flash_bank_t *flash, void *param);
-
-/* fixup after identifying JEDEC manufactuer and ID */
-cfi_fixup_t cfi_jedec_fixups[] = {
- {CFI_MFR_SST, 0x00D4, cfi_fixup_non_cfi, NULL},
- {CFI_MFR_SST, 0x00D5, cfi_fixup_non_cfi, NULL},
- {CFI_MFR_SST, 0x00D6, cfi_fixup_non_cfi, NULL},
- {CFI_MFR_SST, 0x00D7, cfi_fixup_non_cfi, NULL},
- {CFI_MFR_SST, 0x2780, cfi_fixup_non_cfi, NULL},
- {CFI_MFR_ST, 0x00D5, cfi_fixup_non_cfi, NULL},
- {CFI_MFR_ST, 0x00D6, cfi_fixup_non_cfi, NULL},
- {CFI_MFR_AMD, 0x2223, cfi_fixup_non_cfi, NULL},
- {CFI_MFR_AMD, 0x22ab, cfi_fixup_non_cfi, NULL},
- {0, 0, NULL, NULL}
-};
-
-/* fixup after reading cmdset 0002 primary query table */
-cfi_fixup_t cfi_0002_fixups[] = {
- {CFI_MFR_SST, 0x00D4, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
- {CFI_MFR_SST, 0x00D5, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
- {CFI_MFR_SST, 0x00D6, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
- {CFI_MFR_SST, 0x00D7, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
- {CFI_MFR_SST, 0x2780, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
- {CFI_MFR_ATMEL, 0x00C8, cfi_fixup_atmel_reversed_erase_regions, NULL},
- {CFI_MFR_ANY, CFI_ID_ANY, cfi_fixup_0002_erase_regions, NULL},
- {0, 0, NULL, NULL}
-};
-
-/* fixup after reading cmdset 0001 primary query table */
-cfi_fixup_t cfi_0001_fixups[] = {
- {0, 0, NULL, NULL}
-};
-
-void cfi_fixup(flash_bank_t *bank, cfi_fixup_t *fixups)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- cfi_fixup_t *f;
-
- for (f = fixups; f->fixup; f++)
- {
- if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi_info->manufacturer)) &&
- ((f->id == CFI_ID_ANY) || (f->id == cfi_info->device_id)))
- {
- f->fixup(bank, f->param);
- }
- }
-}
-
-inline u32 flash_address(flash_bank_t *bank, int sector, u32 offset)
-{
- /* while the sector list isn't built, only accesses to sector 0 work */
- if (sector == 0)
- return bank->base + offset * bank->bus_width;
- else
- {
- if (!bank->sectors)
- {
- ERROR("BUG: sector list not yet built");
- exit(-1);
- }
- return bank->base + bank->sectors[sector].offset + offset * bank->bus_width;
- }
-
-}
-
-void cfi_command(flash_bank_t *bank, u8 cmd, u8 *cmd_buf)
-{
- int i;
-
- /* clear whole buffer, to ensure bits that exceed the bus_width
- * are set to zero
- */
- for (i = 0; i < CFI_MAX_BUS_WIDTH; i++)
- cmd_buf[i] = 0;
-
- if (bank->target->endianness == TARGET_LITTLE_ENDIAN)
- {
- for (i = bank->bus_width; i > 0; i--)
- {
- *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
- }
- }
- else
- {
- for (i = 1; i <= bank->bus_width; i++)
- {
- *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
- }
- }
-}
-
-/* read unsigned 8-bit value from the bank
- * flash banks are expected to be made of similar chips
- * the query result should be the same for all
- */
-u8 cfi_query_u8(flash_bank_t *bank, int sector, u32 offset)
-{
- target_t *target = bank->target;
- u8 data[CFI_MAX_BUS_WIDTH];
-
- target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data);
-
- if (bank->target->endianness == TARGET_LITTLE_ENDIAN)
- return data[0];
- else
- return data[bank->bus_width - 1];
-}
-
-/* read unsigned 8-bit value from the bank
- * in case of a bank made of multiple chips,
- * the individual values are ORed
- */
-u8 cfi_get_u8(flash_bank_t *bank, int sector, u32 offset)
-{
- target_t *target = bank->target;
- u8 data[CFI_MAX_BUS_WIDTH];
- int i;
-
- target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data);
-
- if (bank->target->endianness == TARGET_LITTLE_ENDIAN)
- {
- for (i = 0; i < bank->bus_width / bank->chip_width; i++)
- data[0] |= data[i];
-
- return data[0];
- }
- else
- {
- u8 value = 0;
- for (i = 0; i < bank->bus_width / bank->chip_width; i++)
- value |= data[bank->bus_width - 1 - i];
-
- return value;
- }
-}
-
-u16 cfi_query_u16(flash_bank_t *bank, int sector, u32 offset)
-{
- target_t *target = bank->target;
- u8 data[CFI_MAX_BUS_WIDTH * 2];
-
- target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 2, data);
-
- if (bank->target->endianness == TARGET_LITTLE_ENDIAN)
- return data[0] | data[bank->bus_width] << 8;
- else
- return data[bank->bus_width - 1] | data[(2 * bank->bus_width) - 1] << 8;
-}
-
-u32 cfi_query_u32(flash_bank_t *bank, int sector, u32 offset)
-{
- target_t *target = bank->target;
- u8 data[CFI_MAX_BUS_WIDTH * 4];
-
- target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 4, data);
-
- if (bank->target->endianness == TARGET_LITTLE_ENDIAN)
- return data[0] | data[bank->bus_width] << 8 | data[bank->bus_width * 2] << 16 | data[bank->bus_width * 3] << 24;
- else
- return data[bank->bus_width - 1] | data[(2* bank->bus_width) - 1] << 8 |
- data[(3 * bank->bus_width) - 1] << 16 | data[(4 * bank->bus_width) - 1] << 24;
-}
-
-void cfi_intel_clear_status_register(flash_bank_t *bank)
-{
- target_t *target = bank->target;
- u8 command[8];
-
- if (target->state != TARGET_HALTED)
- {
- ERROR("BUG: attempted to clear status register while target wasn't halted");
- exit(-1);
- }
-
- cfi_command(bank, 0x50, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-}
-
-u8 cfi_intel_wait_status_busy(flash_bank_t *bank, int timeout)
-{
- u8 status;
-
- while ((!((status = cfi_get_u8(bank, 0, 0x0)) & 0x80)) && (timeout-- > 0))
- {
- DEBUG("status: 0x%x", status);
- usleep(1000);
- }
-
- /* mask out bit 0 (reserved) */
- status = status & 0xfe;
-
- DEBUG("status: 0x%x", status);
-
- if ((status & 0x80) != 0x80)
- {
- ERROR("timeout while waiting for WSM to become ready");
- }
- else if (status != 0x80)
- {
- ERROR("status register: 0x%x", status);
- if (status & 0x2)
- ERROR("Block Lock-Bit Detected, Operation Abort");
- if (status & 0x4)
- ERROR("Program suspended");
- if (status & 0x8)
- ERROR("Low Programming Voltage Detected, Operation Aborted");
- if (status & 0x10)
- ERROR("Program Error / Error in Setting Lock-Bit");
- if (status & 0x20)
- ERROR("Error in Block Erasure or Clear Lock-Bits");
- if (status & 0x40)
- ERROR("Block Erase Suspended");
-
- cfi_intel_clear_status_register(bank);
- }
-
- return status;
-}
-
-int cfi_spansion_wait_status_busy(flash_bank_t *bank, int timeout)
-{
- u8 status, oldstatus;
-
- oldstatus = cfi_get_u8(bank, 0, 0x0);
-
- do {
- status = cfi_get_u8(bank, 0, 0x0);
- if ((status ^ oldstatus) & 0x40) {
- if (status & 0x20) {
- oldstatus = cfi_get_u8(bank, 0, 0x0);
- status = cfi_get_u8(bank, 0, 0x0);
- if ((status ^ oldstatus) & 0x40) {
- ERROR("dq5 timeout, status: 0x%x", status);
- return(ERROR_FLASH_OPERATION_FAILED);
- } else {
- DEBUG("status: 0x%x", status);
- return(ERROR_OK);
- }
- }
- } else {
- DEBUG("status: 0x%x", status);
- return(ERROR_OK);
- }
-
- oldstatus = status;
- usleep(1000);
- } while (timeout-- > 0);
-
- ERROR("timeout, status: 0x%x", status);
-
- return(ERROR_FLASH_BUSY);
-}
-
-int cfi_read_intel_pri_ext(flash_bank_t *bank)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- cfi_intel_pri_ext_t *pri_ext = malloc(sizeof(cfi_intel_pri_ext_t));
- target_t *target = bank->target;
- u8 command[8];
-
- cfi_info->pri_ext = pri_ext;
-
- pri_ext->pri[0] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0);
- pri_ext->pri[1] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1);
- pri_ext->pri[2] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2);
-
- if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I'))
- {
- cfi_command(bank, 0xf0, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
- cfi_command(bank, 0xff, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
- return ERROR_FLASH_BANK_INVALID;
- }
-
- pri_ext->major_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3);
- pri_ext->minor_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4);
-
- DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version);
-
- pri_ext->feature_support = cfi_query_u32(bank, 0, cfi_info->pri_addr + 5);
- pri_ext->suspend_cmd_support = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9);
- pri_ext->blk_status_reg_mask = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xa);
-
- DEBUG("feature_support: 0x%x, suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x", pri_ext->feature_support, pri_ext->suspend_cmd_support, pri_ext->blk_status_reg_mask);
-
- pri_ext->vcc_optimal = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xc);
- pri_ext->vpp_optimal = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xd);
-
- DEBUG("Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x",
- (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f,
- (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f);
-
- pri_ext->num_protection_fields = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xe);
- if (pri_ext->num_protection_fields != 1)
- {
- WARNING("expected one protection register field, but found %i", pri_ext->num_protection_fields);
- }
-
- pri_ext->prot_reg_addr = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xf);
- pri_ext->fact_prot_reg_size = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x11);
- pri_ext->user_prot_reg_size = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x12);
-
- DEBUG("protection_fields: %i, prot_reg_addr: 0x%x, factory pre-programmed: %i, user programmable: %i", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size);
-
- return ERROR_OK;
-}
-
-int cfi_read_spansion_pri_ext(flash_bank_t *bank)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- cfi_spansion_pri_ext_t *pri_ext = malloc(sizeof(cfi_spansion_pri_ext_t));
- target_t *target = bank->target;
- u8 command[8];
-
- cfi_info->pri_ext = pri_ext;
-
- pri_ext->pri[0] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0);
- pri_ext->pri[1] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1);
- pri_ext->pri[2] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2);
-
- if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I'))
- {
- cfi_command(bank, 0xf0, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
- return ERROR_FLASH_BANK_INVALID;
- }
-
- pri_ext->major_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3);
- pri_ext->minor_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4);
-
- DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version);
-
- pri_ext->SiliconRevision = cfi_query_u8(bank, 0, cfi_info->pri_addr + 5);
- pri_ext->EraseSuspend = cfi_query_u8(bank, 0, cfi_info->pri_addr + 6);
- pri_ext->BlkProt = cfi_query_u8(bank, 0, cfi_info->pri_addr + 7);
- pri_ext->TmpBlkUnprotect = cfi_query_u8(bank, 0, cfi_info->pri_addr + 8);
- pri_ext->BlkProtUnprot = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9);
- pri_ext->SimultaneousOps = cfi_query_u8(bank, 0, cfi_info->pri_addr + 10);
- pri_ext->BurstMode = cfi_query_u8(bank, 0, cfi_info->pri_addr + 11);
- pri_ext->PageMode = cfi_query_u8(bank, 0, cfi_info->pri_addr + 12);
- pri_ext->VppMin = cfi_query_u8(bank, 0, cfi_info->pri_addr + 13);
- pri_ext->VppMax = cfi_query_u8(bank, 0, cfi_info->pri_addr + 14);
- pri_ext->TopBottom = cfi_query_u8(bank, 0, cfi_info->pri_addr + 15);
-
- DEBUG("Silicon Revision: 0x%x, Erase Suspend: 0x%x, Block protect: 0x%x", pri_ext->SiliconRevision,
- pri_ext->EraseSuspend, pri_ext->BlkProt);
-
- DEBUG("Temporary Unprotect: 0x%x, Block Protect Scheme: 0x%x, Simultaneous Ops: 0x%x", pri_ext->TmpBlkUnprotect,
- pri_ext->BlkProtUnprot, pri_ext->SimultaneousOps);
-
- DEBUG("Burst Mode: 0x%x, Page Mode: 0x%x, ", pri_ext->BurstMode, pri_ext->PageMode);
-
-
- DEBUG("Vpp min: %2.2d.%1.1d, Vpp max: %2.2d.%1.1x",
- (pri_ext->VppMin & 0xf0) >> 4, pri_ext->VppMin & 0x0f,
- (pri_ext->VppMax & 0xf0) >> 4, pri_ext->VppMax & 0x0f);
-
- DEBUG("WP# protection 0x%x", pri_ext->TopBottom);
-
- /* default values for implementation specific workarounds */
- pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1;
- pri_ext->_unlock2 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock2;
- pri_ext->_reversed_geometry = 0;
-
- return ERROR_OK;
-}
-
-int cfi_read_atmel_pri_ext(flash_bank_t *bank)
-{
- cfi_atmel_pri_ext_t atmel_pri_ext;
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- cfi_spansion_pri_ext_t *pri_ext = malloc(sizeof(cfi_spansion_pri_ext_t));
- target_t *target = bank->target;
- u8 command[8];
-
- /* ATMEL devices use the same CFI primary command set (0x2) as AMD/Spansion,
- * but a different primary extended query table.
- * We read the atmel table, and prepare a valid AMD/Spansion query table.
- */
-
- memset(pri_ext, 0, sizeof(cfi_spansion_pri_ext_t));
-
- cfi_info->pri_ext = pri_ext;
-
- atmel_pri_ext.pri[0] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0);
- atmel_pri_ext.pri[1] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1);
- atmel_pri_ext.pri[2] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2);
-
- if ((atmel_pri_ext.pri[0] != 'P') || (atmel_pri_ext.pri[1] != 'R') || (atmel_pri_ext.pri[2] != 'I'))
- {
- cfi_command(bank, 0xf0, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
- return ERROR_FLASH_BANK_INVALID;
- }
-
- pri_ext->pri[0] = atmel_pri_ext.pri[0];
- pri_ext->pri[1] = atmel_pri_ext.pri[1];
- pri_ext->pri[2] = atmel_pri_ext.pri[2];
-
- atmel_pri_ext.major_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3);
- atmel_pri_ext.minor_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4);
-
- DEBUG("pri: '%c%c%c', version: %c.%c", atmel_pri_ext.pri[0], atmel_pri_ext.pri[1], atmel_pri_ext.pri[2], atmel_pri_ext.major_version, atmel_pri_ext.minor_version);
-
- pri_ext->major_version = atmel_pri_ext.major_version;
- pri_ext->minor_version = atmel_pri_ext.minor_version;
-
- atmel_pri_ext.features = cfi_query_u8(bank, 0, cfi_info->pri_addr + 5);
- atmel_pri_ext.bottom_boot = cfi_query_u8(bank, 0, cfi_info->pri_addr + 6);
- atmel_pri_ext.burst_mode = cfi_query_u8(bank, 0, cfi_info->pri_addr + 7);
- atmel_pri_ext.page_mode = cfi_query_u8(bank, 0, cfi_info->pri_addr + 8);
-
- DEBUG("features: 0x%2.2x, bottom_boot: 0x%2.2x, burst_mode: 0x%2.2x, page_mode: 0x%2.2x",
- atmel_pri_ext.features, atmel_pri_ext.bottom_boot, atmel_pri_ext.burst_mode, atmel_pri_ext.page_mode);
-
- if (atmel_pri_ext.features & 0x02)
- pri_ext->EraseSuspend = 2;
-
- if (atmel_pri_ext.bottom_boot)
- pri_ext->TopBottom = 2;
- else
- pri_ext->TopBottom = 3;
-
- pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1;
- pri_ext->_unlock2 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock2;
-
- return ERROR_OK;
-}
-
-int cfi_read_0002_pri_ext(flash_bank_t *bank)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
-
- if (cfi_info->manufacturer == CFI_MFR_ATMEL)
- {
- return cfi_read_atmel_pri_ext(bank);
- }
- else
- {
- return cfi_read_spansion_pri_ext(bank);
- }
-}
-
-int cfi_spansion_info(struct flash_bank_s *bank, char *buf, int buf_size)
-{
- int printed;
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
-
- printed = snprintf(buf, buf_size, "\nSpansion primary algorithm extend information:\n");
- buf += printed;
- buf_size -= printed;
-
- printed = snprintf(buf, buf_size, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0],
- pri_ext->pri[1], pri_ext->pri[2],
- pri_ext->major_version, pri_ext->minor_version);
- buf += printed;
- buf_size -= printed;
-
- printed = snprintf(buf, buf_size, "Silicon Rev.: 0x%x, Address Sensitive unlock: 0x%x\n",
- (pri_ext->SiliconRevision) >> 2,
- (pri_ext->SiliconRevision) & 0x03);
- buf += printed;
- buf_size -= printed;
-
- printed = snprintf(buf, buf_size, "Erase Suspend: 0x%x, Sector Protect: 0x%x\n",
- pri_ext->EraseSuspend,
- pri_ext->BlkProt);
- buf += printed;
- buf_size -= printed;
-
- printed = snprintf(buf, buf_size, "VppMin: %2.2d.%1.1x, VppMax: %2.2d.%1.1x\n",
- (pri_ext->VppMin & 0xf0) >> 4, pri_ext->VppMin & 0x0f,
- (pri_ext->VppMax & 0xf0) >> 4, pri_ext->VppMax & 0x0f);
-
- return ERROR_OK;
-}
-
-int cfi_intel_info(struct flash_bank_s *bank, char *buf, int buf_size)
-{
- int printed;
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
-
- printed = snprintf(buf, buf_size, "\nintel primary algorithm extend information:\n");
- buf += printed;
- buf_size -= printed;
-
- printed = snprintf(buf, buf_size, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version);
- buf += printed;
- buf_size -= printed;
-
- printed = snprintf(buf, buf_size, "feature_support: 0x%x, suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x\n", pri_ext->feature_support, pri_ext->suspend_cmd_support, pri_ext->blk_status_reg_mask);
- buf += printed;
- buf_size -= printed;
-
- printed = snprintf(buf, buf_size, "Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x\n",
- (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f,
- (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f);
- buf += printed;
- buf_size -= printed;
-
- printed = snprintf(buf, buf_size, "protection_fields: %i, prot_reg_addr: 0x%x, factory pre-programmed: %i, user programmable: %i\n", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size);
-
- return ERROR_OK;
-}
-
-int cfi_register_commands(struct command_context_s *cmd_ctx)
-{
- /*command_t *cfi_cmd = */
- register_command(cmd_ctx, NULL, "cfi", NULL, COMMAND_ANY, "flash bank cfi <base> <size> <chip_width> <bus_width> <targetNum> [jedec_probe/x16_as_x8]");
- /*
- register_command(cmd_ctx, cfi_cmd, "part_id", cfi_handle_part_id_command, COMMAND_EXEC,
- "print part id of cfi flash bank <num>");
- */
- return ERROR_OK;
-}
-
-/* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#> [options]
- */
-int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
-{
- cfi_flash_bank_t *cfi_info;
- int i;
-
- if (argc < 6)
- {
- WARNING("incomplete flash_bank cfi configuration");
- return ERROR_FLASH_BANK_INVALID;
- }
-
- if ((strtoul(args[4], NULL, 0) > CFI_MAX_CHIP_WIDTH)
- || (strtoul(args[3], NULL, 0) > CFI_MAX_BUS_WIDTH))
- {
- ERROR("chip and bus width have to specified in bytes");
- return ERROR_FLASH_BANK_INVALID;
- }
-
- cfi_info = malloc(sizeof(cfi_flash_bank_t));
- cfi_info->probed = 0;
- bank->driver_priv = cfi_info;
-
- cfi_info->write_algorithm = NULL;
- cfi_info->erase_check_algorithm = NULL;
-
- cfi_info->x16_as_x8 = 0;
- cfi_info->jedec_probe = 0;
- cfi_info->not_cfi = 0;
-
- for (i = 6; i < argc; i++)
- {
- if (strcmp(args[i], "x16_as_x8") == 0)
- {
- cfi_info->x16_as_x8 = 1;
- }
- else if (strcmp(args[i], "jedec_probe") == 0)
- {
- cfi_info->jedec_probe = 1;
- }
- }
-
- cfi_info->write_algorithm = NULL;
-
- /* bank wasn't probed yet */
- cfi_info->qry[0] = -1;
-
- return ERROR_OK;
-}
-
-int cfi_intel_erase(struct flash_bank_s *bank, int first, int last)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- target_t *target = bank->target;
- u8 command[8];
- int i;
-
- cfi_intel_clear_status_register(bank);
-
- for (i = first; i <= last; i++)
- {
- cfi_command(bank, 0x20, command);
- target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
-
- cfi_command(bank, 0xd0, command);
- target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
-
- if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->block_erase_timeout_typ)) == 0x80)
- bank->sectors[i].is_erased = 1;
- else
- {
- cfi_command(bank, 0xff, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-
- ERROR("couldn't erase block %i of flash bank at base 0x%x", i, bank->base);
- return ERROR_FLASH_OPERATION_FAILED;
- }
- }
-
- cfi_command(bank, 0xff, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-
- return ERROR_OK;
-}
-
-int cfi_spansion_erase(struct flash_bank_s *bank, int first, int last)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
- target_t *target = bank->target;
- u8 command[8];
- int i;
-
- for (i = first; i <= last; i++)
- {
- cfi_command(bank, 0xaa, command);
- target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command);
-
- cfi_command(bank, 0x55, command);
- target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command);
-
- cfi_command(bank, 0x80, command);
- target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command);
-
- cfi_command(bank, 0xaa, command);
- target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command);
-
- cfi_command(bank, 0x55, command);
- target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command);
-
- cfi_command(bank, 0x30, command);
- target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
-
- if (cfi_spansion_wait_status_busy(bank, 1000 * (1 << cfi_info->block_erase_timeout_typ)) == ERROR_OK)
- bank->sectors[i].is_erased = 1;
- else
- {
- cfi_command(bank, 0xf0, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-
- ERROR("couldn't erase block %i of flash bank at base 0x%x", i, bank->base);
- return ERROR_FLASH_OPERATION_FAILED;
- }
- }
-
- cfi_command(bank, 0xf0, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-
- return ERROR_OK;
-}
-
-int cfi_erase(struct flash_bank_s *bank, int first, int last)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
-
- if (bank->target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if ((first < 0) || (last < first) || (last >= bank->num_sectors))
- {
- return ERROR_FLASH_SECTOR_INVALID;
- }
-
- if (cfi_info->qry[0] != 'Q')
- return ERROR_FLASH_BANK_NOT_PROBED;
-
- switch(cfi_info->pri_id)
- {
- case 1:
- case 3:
- return cfi_intel_erase(bank, first, last);
- break;
- case 2:
- return cfi_spansion_erase(bank, first, last);
- break;
- default:
- ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
- break;
- }
-
- return ERROR_OK;
-}
-
-int cfi_intel_protect(struct flash_bank_s *bank, int set, int first, int last)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
- target_t *target = bank->target;
- u8 command[8];
- int retry = 0;
- int i;
-
- /* if the device supports neither legacy lock/unlock (bit 3) nor
- * instant individual block locking (bit 5).
- */
- if (!(pri_ext->feature_support & 0x28))
- return ERROR_FLASH_OPERATION_FAILED;
-
- cfi_intel_clear_status_register(bank);
-
- for (i = first; i <= last; i++)
- {
- cfi_command(bank, 0x60, command);
- DEBUG("address: 0x%4.4x, command: 0x%4.4x", flash_address(bank, i, 0x0), target_buffer_get_u32(target, command));
- target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
- if (set)
- {
- cfi_command(bank, 0x01, command);
- DEBUG("address: 0x%4.4x, command: 0x%4.4x", flash_address(bank, i, 0x0), target_buffer_get_u32(target, command));
- target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
- bank->sectors[i].is_protected = 1;
- }
- else
- {
- cfi_command(bank, 0xd0, command);
- DEBUG("address: 0x%4.4x, command: 0x%4.4x", flash_address(bank, i, 0x0), target_buffer_get_u32(target, command));
- target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
- bank->sectors[i].is_protected = 0;
- }
-
- /* instant individual block locking doesn't require reading of the status register */
- if (!(pri_ext->feature_support & 0x20))
- {
- /* Clear lock bits operation may take up to 1.4s */
- cfi_intel_wait_status_busy(bank, 1400);
- }
- else
- {
- u8 block_status;
- /* read block lock bit, to verify status */
- cfi_command(bank, 0x90, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command);
- block_status = cfi_get_u8(bank, i, 0x2);
-
- if ((block_status & 0x1) != set)
- {
- ERROR("couldn't change block lock status (set = %i, block_status = 0x%2.2x)", set, block_status);
- cfi_command(bank, 0x70, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command);
- cfi_intel_wait_status_busy(bank, 10);
-
- if (retry > 10)
- return ERROR_FLASH_OPERATION_FAILED;
- else
- {
- i--;
- retry++;
- }
- }
- }
- }
-
- /* if the device doesn't support individual block lock bits set/clear,
- * all blocks have been unlocked in parallel, so we set those that should be protected
- */
- if ((!set) && (!(pri_ext->feature_support & 0x20)))
- {
- for (i = 0; i < bank->num_sectors; i++)
- {
- if (bank->sectors[i].is_protected == 1)
- {
- cfi_intel_clear_status_register(bank);
-
- cfi_command(bank, 0x60, command);
- target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
-
- cfi_command(bank, 0x01, command);
- target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
-
- cfi_intel_wait_status_busy(bank, 100);
- }
- }
- }
-
- cfi_command(bank, 0xff, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-
- return ERROR_OK;
-}
-
-int cfi_protect(struct flash_bank_s *bank, int set, int first, int last)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
-
- if (bank->target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if ((first < 0) || (last < first) || (last >= bank->num_sectors))
- {
- return ERROR_FLASH_SECTOR_INVALID;
- }
-
- if (cfi_info->qry[0] != 'Q')
- return ERROR_FLASH_BANK_NOT_PROBED;
-
- switch(cfi_info->pri_id)
- {
- case 1:
- case 3:
- cfi_intel_protect(bank, set, first, last);
- break;
- default:
- ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
- break;
- }
-
- return ERROR_OK;
-}
-
-/* FIXME Replace this by a simple memcpy() - still unsure about sideeffects */
-static void cfi_add_byte(struct flash_bank_s *bank, u8 *word, u8 byte)
-{
- //target_t *target = bank->target;
-
- int i;
-
- // NOTE:
- // The data to flash must not be changed in endian! We write a bytestrem in
- // target byte order already. Only the control and status byte lane of the flash
- // WSM is interpreted by the CPU in different ways, when read a u16 or u32
- // word (data seems to be in the upper or lower byte lane for u16 accesses).
-
- //if (target->endianness == TARGET_LITTLE_ENDIAN)
- //{
- /* shift bytes */
- for (i = 0; i < bank->bus_width - 1; i++)
- word[i] = word[i + 1];
- word[bank->bus_width - 1] = byte;
- //}
- //else
- //{
- // /* shift bytes */
- // for (i = bank->bus_width - 1; i > 0; i--)
- // word[i] = word[i - 1];
- // word[0] = byte;
- //}
-}
-
-/* Convert code image to target endian */
-/* FIXME create general block conversion fcts in target.c?) */ static
-void cfi_fix_code_endian(target_t *target, u32 *dest, const u32 *src, u32 count)
-{
- u32 i;
- for (i=0; i< count; i++)
- {
- target_buffer_set_u32(target, (u8*)dest, *src);
- dest++;
- src++;
- }
-}
-
-int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u32 count)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- target_t *target = bank->target;
- reg_param_t reg_params[7];
- armv4_5_algorithm_t armv4_5_info;
- working_area_t *source;
- u32 buffer_size = 32768;
- u8 write_command_buf[CFI_MAX_BUS_WIDTH];
- u8 busy_pattern_buf[CFI_MAX_BUS_WIDTH];
- u8 error_pattern_buf[CFI_MAX_BUS_WIDTH];
- u32 write_command_val, busy_pattern_val, error_pattern_val;
-
- /* algorithm register usage:
- * r0: source address (in RAM)
- * r1: target address (in Flash)
- * r2: count
- * r3: flash write command
- * r4: status byte (returned to host)
- * r5: busy test pattern
- * r6: error test pattern
- */
-
- static const u32 word_32_code[] = {
- 0xe4904004, /* loop: ldr r4, [r0], #4 */
- 0xe5813000, /* str r3, [r1] */
- 0xe5814000, /* str r4, [r1] */
- 0xe5914000, /* busy: ldr r4, [r1] */
- 0xe0047005, /* and r7, r4, r5 */
- 0xe1570005, /* cmp r7, r5 */
- 0x1afffffb, /* bne busy */
- 0xe1140006, /* tst r4, r6 */
- 0x1a000003, /* bne done */
- 0xe2522001, /* subs r2, r2, #1 */
- 0x0a000001, /* beq done */
- 0xe2811004, /* add r1, r1 #4 */
- 0xeafffff2, /* b loop */
- 0xeafffffe /* done: b -2 */
- };
-
- static const u32 word_16_code[] = {
- 0xe0d040b2, /* loop: ldrh r4, [r0], #2 */
- 0xe1c130b0, /* strh r3, [r1] */
- 0xe1c140b0, /* strh r4, [r1] */
- 0xe1d140b0, /* busy ldrh r4, [r1] */
- 0xe0047005, /* and r7, r4, r5 */
- 0xe1570005, /* cmp r7, r5 */
- 0x1afffffb, /* bne busy */
- 0xe1140006, /* tst r4, r6 */
- 0x1a000003, /* bne done */
- 0xe2522001, /* subs r2, r2, #1 */
- 0x0a000001, /* beq done */
- 0xe2811002, /* add r1, r1 #2 */
- 0xeafffff2, /* b loop */
- 0xeafffffe /* done: b -2 */
- };
-
- static const u32 word_8_code[] = {
- 0xe4d04001, /* loop: ldrb r4, [r0], #1 */
- 0xe5c13000, /* strb r3, [r1] */
- 0xe5c14000, /* strb r4, [r1] */
- 0xe5d14000, /* busy ldrb r4, [r1] */
- 0xe0047005, /* and r7, r4, r5 */
- 0xe1570005, /* cmp r7, r5 */
- 0x1afffffb, /* bne busy */
- 0xe1140006, /* tst r4, r6 */
- 0x1a000003, /* bne done */
- 0xe2522001, /* subs r2, r2, #1 */
- 0x0a000001, /* beq done */
- 0xe2811001, /* add r1, r1 #1 */
- 0xeafffff2, /* b loop */
- 0xeafffffe /* done: b -2 */
- };
- u32 target_code[CFI_MAX_INTEL_CODESIZE];
- const u32 *target_code_src;
- int target_code_size;
- int retval = ERROR_OK;
-
-
- cfi_intel_clear_status_register(bank);
-
- 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;
-
- /* If we are setting up the write_algorith, we need target_code_src */
- /* if not we only need target_code_size. */
- /* */
- /* However, we don't want to create multiple code paths, so we */
- /* do the unecessary evaluation of target_code_src, which the */
- /* compiler will probably nicely optimize away if not needed */
-
- /* prepare algorithm code for target endian */
- switch (bank->bus_width)
- {
- case 1 :
- target_code_src = word_8_code;
- target_code_size = sizeof(word_8_code);
- break;
- case 2 :
- target_code_src = word_16_code;
- target_code_size = sizeof(word_16_code);
- break;
- case 4 :
- target_code_src = word_32_code;
- target_code_size = sizeof(word_32_code);
- break;
- default:
- ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width);
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
-
- /* flash write code */
- if (!cfi_info->write_algorithm)
- {
- if ( target_code_size > sizeof(target_code) )
- {
- WARNING("Internal error - target code buffer to small. Increase CFI_MAX_INTEL_CODESIZE and recompile.");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
- cfi_fix_code_endian(target, target_code, target_code_src, target_code_size);
-
- /* Get memory for block write handler */
- retval = target_alloc_working_area(target, target_code_size, &cfi_info->write_algorithm);
- if (retval != ERROR_OK)
- {
- WARNING("No working area available, can't do block memory writes");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- };
-
- /* write algorithm code to working area */
- retval = target_write_buffer(target, cfi_info->write_algorithm->address, target_code_size, (u8*)target_code);
- if (retval != ERROR_OK)
- {
- ERROR("Unable to write block write code to target");
- goto cleanup;
- }
- }
-
- /* Get a workspace buffer for the data to flash starting with 32k size.
- Half size until buffer would be smaller 256 Bytem then fail back */
- /* FIXME Why 256 bytes, why not 32 bytes (smallest flash write page */
- while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
- {
- buffer_size /= 2;
- if (buffer_size <= 256)
- {
- WARNING("no large enough working area available, can't do block memory writes");
- retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- goto cleanup;
- }
- };
-
- /* setup algo registers */
- init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
- init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
- init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
- init_reg_param(®_params[3], "r3", 32, PARAM_OUT);
- init_reg_param(®_params[4], "r4", 32, PARAM_IN);
- init_reg_param(®_params[5], "r5", 32, PARAM_OUT);
- init_reg_param(®_params[6], "r6", 32, PARAM_OUT);
-
- /* prepare command and status register patterns */
- cfi_command(bank, 0x40, write_command_buf);
- cfi_command(bank, 0x80, busy_pattern_buf);
- cfi_command(bank, 0x7e, error_pattern_buf);
-
- switch (bank->bus_width)
- {
- case 1 :
- write_command_val = write_command_buf[0];
- busy_pattern_val = busy_pattern_buf[0];
- error_pattern_val = error_pattern_buf[0];
- break;
- case 2 :
- write_command_val = target_buffer_get_u16(target, write_command_buf);
- busy_pattern_val = target_buffer_get_u16(target, busy_pattern_buf);
- error_pattern_val = target_buffer_get_u16(target, error_pattern_buf);
- break;
- case 4 :
- write_command_val = target_buffer_get_u32(target, write_command_buf);
- busy_pattern_val = target_buffer_get_u32(target, busy_pattern_buf);
- error_pattern_val = target_buffer_get_u32(target, error_pattern_buf);
- break;
- default :
- ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width);
- retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- goto cleanup;
- }
-
- INFO("Using target buffer at 0x%08x and of size 0x%04x", source->address, buffer_size );
-
- /* Programming main loop */
- while (count > 0)
- {
- u32 thisrun_count = (count > buffer_size) ? buffer_size : count;
- u32 wsm_error;
-
- target_write_buffer(target, source->address, thisrun_count, 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 / bank->bus_width);
-
- buf_set_u32(reg_params[3].value, 0, 32, write_command_val);
- buf_set_u32(reg_params[5].value, 0, 32, busy_pattern_val);
- buf_set_u32(reg_params[6].value, 0, 32, error_pattern_val);
-
- INFO("Write 0x%04x bytes to flash at 0x%08x", thisrun_count, address );
-
- /* Execute algorithm, assume breakpoint for last instruction */
- retval = target->type->run_algorithm(target, 0, NULL, 7, reg_params,
- cfi_info->write_algorithm->address,
- cfi_info->write_algorithm->address + target_code_size - sizeof(u32),
- 10000, /* 10s should be enough for max. 32k of data */
- &armv4_5_info);
-
- /* On failure try a fall back to direct word writes */
- if (retval != ERROR_OK)
- {
- cfi_intel_clear_status_register(bank);
- ERROR("Execution of flash algorythm failed. Can't fall back. Please report.");
- retval = ERROR_FLASH_OPERATION_FAILED;
- //retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- // FIXME To allow fall back or recovery, we must save the actual status
- // somewhere, so that a higher level code can start recovery.
- goto cleanup;
- }
-
- /* Check return value from algo code */
- wsm_error = buf_get_u32(reg_params[4].value, 0, 32) & error_pattern_val;
- if (wsm_error)
- {
- /* read status register (outputs debug inforation) */
- cfi_intel_wait_status_busy(bank, 100);
- cfi_intel_clear_status_register(bank);
- retval = ERROR_FLASH_OPERATION_FAILED;
- goto cleanup;
- }
-
- buffer += thisrun_count;
- address += thisrun_count;
- count -= thisrun_count;
- }
-
- /* free up resources */
-cleanup:
- if (source)
- target_free_working_area(target, source);
-
- if (cfi_info->write_algorithm)
- {
- target_free_working_area(target, cfi_info->write_algorithm);
- cfi_info->write_algorithm = NULL;
- }
-
- destroy_reg_param(®_params[0]);
- destroy_reg_param(®_params[1]);
- destroy_reg_param(®_params[2]);
- destroy_reg_param(®_params[3]);
- destroy_reg_param(®_params[4]);
- destroy_reg_param(®_params[5]);
- destroy_reg_param(®_params[6]);
-
- return retval;
-}
-
-int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u32 count)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
- target_t *target = bank->target;
- reg_param_t reg_params[10];
- armv4_5_algorithm_t armv4_5_info;
- working_area_t *source;
- u32 buffer_size = 32768;
- u8 write_command[CFI_MAX_BUS_WIDTH];
- u32 status;
- int i;
- int retval;
- int exit_code = ERROR_OK;
-
- /* input parameters - */
- /* R0 = source address */
- /* R1 = destination address */
- /* R2 = number of writes */
- /* R3 = flash write command */
- /* R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */
- /* output parameters - */
- /* R5 = 0x80 ok 0x00 bad */
- /* temp registers - */
- /* R6 = value read from flash to test status */
- /* R7 = holding register */
- /* unlock registers - */
- /* R8 = unlock1_addr */
- /* R9 = unlock1_cmd */
- /* R10 = unlock2_addr */
- /* R11 = unlock2_cmd */
-
- u32 word_32_code[] = {
- /* 00008100 <sp_32_code>: */
- 0xe4905004, /* ldr r5, [r0], #4 */
- 0xe5889000, /* str r9, [r8] */
- 0xe58ab000, /* str r11, [r10] */
- 0xe5883000, /* str r3, [r8] */
- 0xe5815000, /* str r5, [r1] */
- 0xe1a00000, /* nop */
- /* */
- /* 00008110 <sp_32_busy>: */
- 0xe5916000, /* ldr r6, [r1] */
- 0xe0257006, /* eor r7, r5, r6 */
- 0xe0147007, /* ands r7, r4, r7 */
- 0x0a000007, /* beq 8140 <sp_32_cont> ; b if DQ7 == Data7 */
- 0xe0166124, /* ands r6, r6, r4, lsr #2 */
- 0x0afffff9, /* beq 8110 <sp_32_busy> ; b if DQ5 low */
- 0xe5916000, /* ldr r6, [r1] */
- 0xe0257006, /* eor r7, r5, r6 */
- 0xe0147007, /* ands r7, r4, r7 */
- 0x0a000001, /* beq 8140 <sp_32_cont> ; b if DQ7 == Data7 */
- 0xe3a05000, /* mov r5, #0 ; 0x0 - return 0x00, error */
- 0x1a000004, /* bne 8154 <sp_32_done> */
- /* */
- /* 00008140 <sp_32_cont>: */
- 0xe2522001, /* subs r2, r2, #1 ; 0x1 */
- 0x03a05080, /* moveq r5, #128 ; 0x80 */
- 0x0a000001, /* beq 8154 <sp_32_done> */
- 0xe2811004, /* add r1, r1, #4 ; 0x4 */
- 0xeaffffe8, /* b 8100 <sp_32_code> */
- /* */
- /* 00008154 <sp_32_done>: */
- 0xeafffffe /* b 8154 <sp_32_done> */
- };
-
- u32 word_16_code[] = {
- /* 00008158 <sp_16_code>: */
- 0xe0d050b2, /* ldrh r5, [r0], #2 */
- 0xe1c890b0, /* strh r9, [r8] */
- 0xe1cab0b0, /* strh r11, [r10] */
- 0xe1c830b0, /* strh r3, [r8] */
- 0xe1c150b0, /* strh r5, [r1] */
- 0xe1a00000, /* nop (mov r0,r0) */
- /* */
- /* 00008168 <sp_16_busy>: */
- 0xe1d160b0, /* ldrh r6, [r1] */
- 0xe0257006, /* eor r7, r5, r6 */
- 0xe0147007, /* ands r7, r4, r7 */
- 0x0a000007, /* beq 8198 <sp_16_cont> */
- 0xe0166124, /* ands r6, r6, r4, lsr #2 */
- 0x0afffff9, /* beq 8168 <sp_16_busy> */
- 0xe1d160b0, /* ldrh r6, [r1] */
- 0xe0257006, /* eor r7, r5, r6 */
- 0xe0147007, /* ands r7, r4, r7 */
- 0x0a000001, /* beq 8198 <sp_16_cont> */
- 0xe3a05000, /* mov r5, #0 ; 0x0 */
- 0x1a000004, /* bne 81ac <sp_16_done> */
- /* */
- /* 00008198 <sp_16_cont>: */
- 0xe2522001, /* subs r2, r2, #1 ; 0x1 */
- 0x03a05080, /* moveq r5, #128 ; 0x80 */
- 0x0a000001, /* beq 81ac <sp_16_done> */
- 0xe2811002, /* add r1, r1, #2 ; 0x2 */
- 0xeaffffe8, /* b 8158 <sp_16_code> */
- /* */
- /* 000081ac <sp_16_done>: */
- 0xeafffffe /* b 81ac <sp_16_done> */
- };
-
- u32 word_8_code[] = {
- /* 000081b0 <sp_16_code_end>: */
- 0xe4d05001, /* ldrb r5, [r0], #1 */
- 0xe5c89000, /* strb r9, [r8] */
- 0xe5cab000, /* strb r11, [r10] */
- 0xe5c83000, /* strb r3, [r8] */
- 0xe5c15000, /* strb r5, [r1] */
- 0xe1a00000, /* nop (mov r0,r0) */
- /* */
- /* 000081c0 <sp_8_busy>: */
- 0xe5d16000, /* ldrb r6, [r1] */
- 0xe0257006, /* eor r7, r5, r6 */
- 0xe0147007, /* ands r7, r4, r7 */
- 0x0a000007, /* beq 81f0 <sp_8_cont> */
- 0xe0166124, /* ands r6, r6, r4, lsr #2 */
- 0x0afffff9, /* beq 81c0 <sp_8_busy> */
- 0xe5d16000, /* ldrb r6, [r1] */
- 0xe0257006, /* eor r7, r5, r6 */
- 0xe0147007, /* ands r7, r4, r7 */
- 0x0a000001, /* beq 81f0 <sp_8_cont> */
- 0xe3a05000, /* mov r5, #0 ; 0x0 */
- 0x1a000004, /* bne 8204 <sp_8_done> */
- /* */
- /* 000081f0 <sp_8_cont>: */
- 0xe2522001, /* subs r2, r2, #1 ; 0x1 */
- 0x03a05080, /* moveq r5, #128 ; 0x80 */
- 0x0a000001, /* beq 8204 <sp_8_done> */
- 0xe2811001, /* add r1, r1, #1 ; 0x1 */
- 0xeaffffe8, /* b 81b0 <sp_16_code_end> */
- /* */
- /* 00008204 <sp_8_done>: */
- 0xeafffffe /* b 8204 <sp_8_done> */
- };
-
- 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;
-
- /* flash write code */
- if (!cfi_info->write_algorithm)
- {
- u8 *code_p;
-
- /* convert bus-width dependent algorithm code to correct endiannes */
- if (bank->bus_width == 1)
- {
- code_p = malloc(24 * 4);
-
- for (i = 0; i < 24; i++)
- target_buffer_set_u32(target, code_p + (i*4), word_8_code[i]);
- }
- else if (bank->bus_width == 2)
- {
- code_p = malloc(24 * 4);
-
- for (i = 0; i < 24; i++)
- target_buffer_set_u32(target, code_p + (i*4), word_16_code[i]);
- }
- else if (bank->bus_width == 4)
- {
- code_p = malloc(24 * 4);
-
- for (i = 0; i < 24; i++)
- target_buffer_set_u32(target, code_p + (i*4), word_32_code[i]);
- }
- else
- {
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- /* allocate working area */
- retval=target_alloc_working_area(target, 24 * 4,
- &cfi_info->write_algorithm);
- if (retval != ERROR_OK)
- {
- return retval;
- }
-
- /* write algorithm code to working area */
- target_write_buffer(target, cfi_info->write_algorithm->address, 24 * 4, code_p);
-
- free(code_p);
- }
-
- 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 (cfi_info->write_algorithm)
- target_free_working_area(target, cfi_info->write_algorithm);
-
- WARNING("not enough working area available, can't do block memory writes");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
- };
-
- init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
- init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
- init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
- init_reg_param(®_params[3], "r3", 32, PARAM_OUT);
- init_reg_param(®_params[4], "r4", 32, PARAM_OUT);
- init_reg_param(®_params[5], "r5", 32, PARAM_IN);
- init_reg_param(®_params[6], "r8", 32, PARAM_OUT);
- init_reg_param(®_params[7], "r9", 32, PARAM_OUT);
- init_reg_param(®_params[8], "r10", 32, PARAM_OUT);
- init_reg_param(®_params[9], "r11", 32, PARAM_OUT);
-
- while (count > 0)
- {
- u32 thisrun_count = (count > buffer_size) ? buffer_size : count;
-
- target_write_buffer(target, source->address, thisrun_count, 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 / bank->bus_width);
- cfi_command(bank, 0xA0, write_command);
- buf_set_u32(reg_params[3].value, 0, 32, buf_get_u32(write_command, 0, 32));
- cfi_command(bank, 0x80, write_command);
- buf_set_u32(reg_params[4].value, 0, 32, buf_get_u32(write_command, 0, 32));
- buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock1));
- buf_set_u32(reg_params[7].value, 0, 32, 0xaa);
- buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock2));
- buf_set_u32(reg_params[9].value, 0, 32, 0x55);
-
- retval = target->type->run_algorithm(target, 0, NULL, 10, reg_params,
- cfi_info->write_algorithm->address,
- cfi_info->write_algorithm->address + ((24 * 4) - 4),
- 10000, &armv4_5_info);
-
- status = buf_get_u32(reg_params[5].value, 0, 32);
-
- if ((retval != ERROR_OK) || status != 0x80)
- {
- DEBUG("status: 0x%x", status);
- exit_code = ERROR_FLASH_OPERATION_FAILED;
- break;
- }
-
- buffer += thisrun_count;
- address += thisrun_count;
- count -= thisrun_count;
- }
-
- target_free_working_area(target, source);
-
- destroy_reg_param(®_params[0]);
- destroy_reg_param(®_params[1]);
- destroy_reg_param(®_params[2]);
- destroy_reg_param(®_params[3]);
- destroy_reg_param(®_params[4]);
- destroy_reg_param(®_params[5]);
- destroy_reg_param(®_params[6]);
- destroy_reg_param(®_params[7]);
- destroy_reg_param(®_params[8]);
- destroy_reg_param(®_params[9]);
-
- return exit_code;
-}
-
-int cfi_intel_write_word(struct flash_bank_s *bank, u8 *word, u32 address)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- target_t *target = bank->target;
- u8 command[8];
-
- cfi_intel_clear_status_register(bank);
- cfi_command(bank, 0x40, command);
- target->type->write_memory(target, address, bank->bus_width, 1, command);
-
- target->type->write_memory(target, address, bank->bus_width, 1, word);
-
- if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->word_write_timeout_max)) != 0x80)
- {
- cfi_command(bank, 0xff, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-
- ERROR("couldn't write word at base 0x%x, address %x", bank->base, address);
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- return ERROR_OK;
-}
-
-int cfi_intel_write_words(struct flash_bank_s *bank, u8 *word, u32 wordcount, u32 address)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- target_t *target = bank->target;
- u8 command[8];
-
- /* Calculate buffer size and boundary mask */
- u32 buffersize = 1UL << cfi_info->max_buf_write_size;
- u32 buffermask = buffersize-1;
- u32 bufferwsize;
-
- /* Check for valid range */
- if (address & buffermask)
- {
- ERROR("Write address at base 0x%x, address %x not aligned to 2^%d boundary", bank->base, address, cfi_info->max_buf_write_size);
- return ERROR_FLASH_OPERATION_FAILED;
- }
- switch(bank->chip_width)
- {
- case 4 : bufferwsize = buffersize / 4; break;
- case 2 : bufferwsize = buffersize / 2; break;
- case 1 : bufferwsize = buffersize; break;
- default:
- ERROR("Unsupported chip width %d", bank->chip_width);
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- /* Check for valid size */
- if (wordcount > bufferwsize)
- {
- ERROR("Number of data words %d exceeds available buffersize %d", wordcount, buffersize);
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- /* Write to flash buffer */
- cfi_intel_clear_status_register(bank);
-
- /* Initiate buffer operation _*/
- cfi_command(bank, 0xE8, command);
- target->type->write_memory(target, address, bank->bus_width, 1, command);
- if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->buf_write_timeout_max)) != 0x80)
- {
- cfi_command(bank, 0xff, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-
- ERROR("couldn't start buffer write operation at base 0x%x, address %x", bank->base, address);
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- /* Write buffer wordcount-1 and data words */
- cfi_command(bank, bufferwsize-1, command);
- target->type->write_memory(target, address, bank->bus_width, 1, command);
-
- target->type->write_memory(target, address, bank->bus_width, bufferwsize, word);
-
- /* Commit write operation */
- cfi_command(bank, 0xd0, command);
- target->type->write_memory(target, address, bank->bus_width, 1, command);
- if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->buf_write_timeout_max)) != 0x80)
- {
- cfi_command(bank, 0xff, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-
- ERROR("Buffer write at base 0x%x, address %x failed.", bank->base, address);
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- return ERROR_OK;
-}
-
-int cfi_spansion_write_word(struct flash_bank_s *bank, u8 *word, u32 address)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
- target_t *target = bank->target;
- u8 command[8];
-
- cfi_command(bank, 0xaa, command);
- target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command);
-
- cfi_command(bank, 0x55, command);
- target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command);
-
- cfi_command(bank, 0xa0, command);
- target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command);
-
- target->type->write_memory(target, address, bank->bus_width, 1, word);
-
- if (cfi_spansion_wait_status_busy(bank, 1000 * (1 << cfi_info->word_write_timeout_max)) != ERROR_OK)
- {
- cfi_command(bank, 0xf0, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-
- ERROR("couldn't write word at base 0x%x, address %x", bank->base, address);
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- return ERROR_OK;
-}
-
-int cfi_write_word(struct flash_bank_s *bank, u8 *word, u32 address)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
-
- switch(cfi_info->pri_id)
- {
- case 1:
- case 3:
- return cfi_intel_write_word(bank, word, address);
- break;
- case 2:
- return cfi_spansion_write_word(bank, word, address);
- break;
- default:
- ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
- break;
- }
-
- return ERROR_FLASH_OPERATION_FAILED;
-}
-
-int cfi_write_words(struct flash_bank_s *bank, u8 *word, u32 wordcount, u32 address)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
-
- switch(cfi_info->pri_id)
- {
- case 1:
- case 3:
- return cfi_intel_write_words(bank, word, wordcount, address);
- break;
- case 2:
- //return cfi_spansion_write_words(bank, word, address);
- ERROR("cfi primary command set %i unimplemented - FIXME", cfi_info->pri_id);
- break;
- default:
- ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
- break;
- }
-
- return ERROR_FLASH_OPERATION_FAILED;
-}
-
-int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- target_t *target = bank->target;
- u32 address = bank->base + offset; /* address of first byte to be programmed */
- u32 write_p, copy_p;
- int align; /* number of unaligned bytes */
- int blk_count; /* number of bus_width bytes for block copy */
- u8 current_word[CFI_MAX_BUS_WIDTH * 4]; /* word (bus_width size) currently being programmed */
- int i;
- int retval;
-
- if (offset + count > bank->size)
- return ERROR_FLASH_DST_OUT_OF_BANK;
-
- if (cfi_info->qry[0] != 'Q')
- return ERROR_FLASH_BANK_NOT_PROBED;
-
- /* start at the first byte of the first word (bus_width size) */
- write_p = address & ~(bank->bus_width - 1);
- if ((align = address - write_p) != 0)
- {
- INFO("Fixup %d unaligned head bytes", align );
-
- for (i = 0; i < bank->bus_width; i++)
- current_word[i] = 0;
- copy_p = write_p;
-
- /* copy bytes before the first write address */
- for (i = 0; i < align; ++i, ++copy_p)
- {
- u8 byte;
- target->type->read_memory(target, copy_p, 1, 1, &byte);
- cfi_add_byte(bank, current_word, byte);
- }
-
- /* add bytes from the buffer */
- for (; (i < bank->bus_width) && (count > 0); i++)
- {
- cfi_add_byte(bank, current_word, *buffer++);
- count--;
- copy_p++;
- }
-
- /* if the buffer is already finished, copy bytes after the last write address */
- for (; (count == 0) && (i < bank->bus_width); ++i, ++copy_p)
- {
- u8 byte;
- target->type->read_memory(target, copy_p, 1, 1, &byte);
- cfi_add_byte(bank, current_word, byte);
- }
-
- retval = cfi_write_word(bank, current_word, write_p);
- if (retval != ERROR_OK)
- return retval;
- write_p = copy_p;
- }
-
- /* handle blocks of bus_size aligned bytes */
- blk_count = count & ~(bank->bus_width - 1); /* round down, leave tail bytes */
- switch(cfi_info->pri_id)
- {
- /* try block writes (fails without working area) */
- case 1:
- case 3:
- retval = cfi_intel_write_block(bank, buffer, write_p, blk_count);
- break;
- case 2:
- retval = cfi_spansion_write_block(bank, buffer, write_p, blk_count);
- break;
- default:
- ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
- retval = ERROR_FLASH_OPERATION_FAILED;
- break;
- }
- if (retval == ERROR_OK)
- {
- /* Increment pointers and decrease count on succesful block write */
- buffer += blk_count;
- write_p += blk_count;
- count -= blk_count;
- }
- else
- {
- if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
- {
- u32 buffersize = 1UL << cfi_info->max_buf_write_size;
- u32 buffermask = buffersize-1;
- u32 bufferwsize;
-
- switch(bank->chip_width)
- {
- case 4 : bufferwsize = buffersize / 4; break;
- case 2 : bufferwsize = buffersize / 2; break;
- case 1 : bufferwsize = buffersize; break;
- default:
- ERROR("Unsupported chip width %d", bank->chip_width);
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- /* fall back to memory writes */
- while (count > bank->bus_width)
- {
- if ((write_p & 0xff) == 0)
- {
- INFO("Programming at %08x, count %08x bytes remaining", write_p, count);
- }
-#if 0
- /* NB! this is broken for spansion! */
- if ((count > bufferwsize) && !(write_p & buffermask))
- {
- retval = cfi_write_words(bank, buffer, bufferwsize, write_p);
- if (retval != ERROR_OK)
- return retval;
-
- buffer += buffersize;
- write_p += buffersize;
- count -= buffersize;
- }
- else
-#endif
- {
- for (i = 0; i < bank->bus_width; i++)
- current_word[i] = 0;
-
- for (i = 0; i < bank->bus_width; i++)
- {
- cfi_add_byte(bank, current_word, *buffer++);
- }
-
- retval = cfi_write_word(bank, current_word, write_p);
- if (retval != ERROR_OK)
- return retval;
-
- write_p += bank->bus_width;
- count -= bank->bus_width;
- }
- }
- }
- else
- return retval;
- }
-
- /* return to read array mode, so we can read from flash again for padding */
- cfi_command(bank, 0xf0, current_word);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word);
- cfi_command(bank, 0xff, current_word);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word);
-
- /* handle unaligned tail bytes */
- if (count > 0)
- {
- INFO("Fixup %d unaligned tail bytes", count );
-
- copy_p = write_p;
- for (i = 0; i < bank->bus_width; i++)
- current_word[i] = 0;
-
- for (i = 0; (i < bank->bus_width) && (count > 0); ++i, ++copy_p)
- {
- cfi_add_byte(bank, current_word, *buffer++);
- count--;
- }
- for (; i < bank->bus_width; ++i, ++copy_p)
- {
- u8 byte;
- target->type->read_memory(target, copy_p, 1, 1, &byte);
- cfi_add_byte(bank, current_word, byte);
- }
- retval = cfi_write_word(bank, current_word, write_p);
- if (retval != ERROR_OK)
- return retval;
- }
-
- /* return to read array mode */
- cfi_command(bank, 0xf0, current_word);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word);
- cfi_command(bank, 0xff, current_word);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word);
-
- return ERROR_OK;
-}
-
-void cfi_fixup_atmel_reversed_erase_regions(flash_bank_t *bank, void *param)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
-
- pri_ext->_reversed_geometry = 1;
-}
-
-void cfi_fixup_0002_erase_regions(flash_bank_t *bank, void *param)
-{
- int i;
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
-
- if ((pri_ext->_reversed_geometry) || (pri_ext->TopBottom == 3))
- {
- DEBUG("swapping reversed erase region information on cmdset 0002 device");
-
- for (i = 0; i < cfi_info->num_erase_regions / 2; i++)
- {
- int j = (cfi_info->num_erase_regions - 1) - i;
- u32 swap;
-
- swap = cfi_info->erase_region_info[i];
- cfi_info->erase_region_info[i] = cfi_info->erase_region_info[j];
- cfi_info->erase_region_info[j] = swap;
- }
- }
-}
-
-void cfi_fixup_0002_unlock_addresses(flash_bank_t *bank, void *param)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
- cfi_unlock_addresses_t *unlock_addresses = param;
-
- pri_ext->_unlock1 = unlock_addresses->unlock1;
- pri_ext->_unlock2 = unlock_addresses->unlock2;
-}
-
-int cfi_probe(struct flash_bank_s *bank)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- target_t *target = bank->target;
- u8 command[8];
- int num_sectors = 0;
- int i;
- int sector = 0;
- u32 offset = 0;
- u32 unlock1 = 0x555;
- u32 unlock2 = 0x2aa;
-
- cfi_info->probed = 0;
-
- /* JEDEC standard JESD21C uses 0x5555 and 0x2aaa as unlock addresses,
- * while CFI compatible AMD/Spansion flashes use 0x555 and 0x2aa
- */
- if (cfi_info->jedec_probe)
- {
- unlock1 = 0x5555;
- unlock2 = 0x2aaa;
- }
-
- /* switch to read identifier codes mode ("AUTOSELECT") */
- cfi_command(bank, 0xaa, command);
- target->type->write_memory(target, flash_address(bank, 0, unlock1), bank->bus_width, 1, command);
- cfi_command(bank, 0x55, command);
- target->type->write_memory(target, flash_address(bank, 0, unlock2), bank->bus_width, 1, command);
- cfi_command(bank, 0x90, command);
- target->type->write_memory(target, flash_address(bank, 0, unlock1), bank->bus_width, 1, command);
-
- if (bank->chip_width == 1)
- {
- u8 manufacturer, device_id;
- target_read_u8(target, bank->base + 0x0, &manufacturer);
- target_read_u8(target, bank->base + 0x1, &device_id);
- cfi_info->manufacturer = manufacturer;
- cfi_info->device_id = device_id;
- }
- else if (bank->chip_width == 2)
- {
- target_read_u16(target, bank->base + 0x0, &cfi_info->manufacturer);
- target_read_u16(target, bank->base + 0x2, &cfi_info->device_id);
- }
-
- /* switch back to read array mode */
- cfi_command(bank, 0xf0, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x00), bank->bus_width, 1, command);
- cfi_command(bank, 0xff, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x00), bank->bus_width, 1, command);
-
- cfi_fixup(bank, cfi_jedec_fixups);
-
- /* query only if this is a CFI compatible flash,
- * otherwise the relevant info has already been filled in
- */
- if (cfi_info->not_cfi == 0)
- {
- /* enter CFI query mode
- * according to JEDEC Standard No. 68.01,
- * a single bus sequence with address = 0x55, data = 0x98 should put
- * the device into CFI query mode.
- *
- * SST flashes clearly violate this, and we will consider them incompatbile for now
- */
- cfi_command(bank, 0x98, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command);
-
- cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10);
- 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);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
- cfi_command(bank, 0xff, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
- return ERROR_FLASH_BANK_INVALID;
- }
-
- cfi_info->pri_id = cfi_query_u16(bank, 0, 0x13);
- cfi_info->pri_addr = cfi_query_u16(bank, 0, 0x15);
- cfi_info->alt_id = cfi_query_u16(bank, 0, 0x17);
- cfi_info->alt_addr = cfi_query_u16(bank, 0, 0x19);
-
- DEBUG("qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr);
-
- cfi_info->vcc_min = cfi_query_u8(bank, 0, 0x1b);
- cfi_info->vcc_max = cfi_query_u8(bank, 0, 0x1c);
- cfi_info->vpp_min = cfi_query_u8(bank, 0, 0x1d);
- cfi_info->vpp_max = cfi_query_u8(bank, 0, 0x1e);
- cfi_info->word_write_timeout_typ = cfi_query_u8(bank, 0, 0x1f);
- cfi_info->buf_write_timeout_typ = cfi_query_u8(bank, 0, 0x20);
- cfi_info->block_erase_timeout_typ = cfi_query_u8(bank, 0, 0x21);
- cfi_info->chip_erase_timeout_typ = cfi_query_u8(bank, 0, 0x22);
- cfi_info->word_write_timeout_max = cfi_query_u8(bank, 0, 0x23);
- cfi_info->buf_write_timeout_max = cfi_query_u8(bank, 0, 0x24);
- cfi_info->block_erase_timeout_max = cfi_query_u8(bank, 0, 0x25);
- cfi_info->chip_erase_timeout_max = cfi_query_u8(bank, 0, 0x26);
-
- DEBUG("Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x",
- (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
- (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
- (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
- (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
- DEBUG("typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ,
- 1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ);
- DEBUG("max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
- (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
- (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
- (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
-
- cfi_info->dev_size = cfi_query_u8(bank, 0, 0x27);
- cfi_info->interface_desc = cfi_query_u16(bank, 0, 0x28);
- cfi_info->max_buf_write_size = cfi_query_u16(bank, 0, 0x2a);
- cfi_info->num_erase_regions = cfi_query_u8(bank, 0, 0x2c);
-
- DEBUG("size: 0x%x, interface desc: %i, max buffer write size: %x", 1 << cfi_info->dev_size, cfi_info->interface_desc, (1 << cfi_info->max_buf_write_size));
-
- if (((1 << cfi_info->dev_size) * bank->bus_width / bank->chip_width) != bank->size)
- {
- WARNING("configuration specifies 0x%x size, but a 0x%x size flash was found", bank->size, 1 << cfi_info->dev_size);
- }
-
- if (cfi_info->num_erase_regions)
- {
- cfi_info->erase_region_info = malloc(4 * cfi_info->num_erase_regions);
- for (i = 0; i < cfi_info->num_erase_regions; i++)
- {
- cfi_info->erase_region_info[i] = cfi_query_u32(bank, 0, 0x2d + (4 * i));
- DEBUG("erase region[%i]: %i blocks of size 0x%x", i, (cfi_info->erase_region_info[i] & 0xffff) + 1, (cfi_info->erase_region_info[i] >> 16) * 256);
- }
- }
- else
- {
- cfi_info->erase_region_info = NULL;
- }
-
- /* We need to read the primary algorithm extended query table before calculating
- * the sector layout to be able to apply fixups
- */
- switch(cfi_info->pri_id)
- {
- /* Intel command set (standard and extended) */
- case 0x0001:
- case 0x0003:
- cfi_read_intel_pri_ext(bank);
- break;
- /* AMD/Spansion, Atmel, ... command set */
- case 0x0002:
- cfi_read_0002_pri_ext(bank);
- break;
- default:
- ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
- break;
- }
-
- /* return to read array mode
- * we use both reset commands, as some Intel flashes fail to recognize the 0xF0 command
- */
- cfi_command(bank, 0xf0, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
- cfi_command(bank, 0xff, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
- }
-
- /* apply fixups depending on the primary command set */
- switch(cfi_info->pri_id)
- {
- /* Intel command set (standard and extended) */
- case 0x0001:
- case 0x0003:
- cfi_fixup(bank, cfi_0001_fixups);
- break;
- /* AMD/Spansion, Atmel, ... command set */
- case 0x0002:
- cfi_fixup(bank, cfi_0002_fixups);
- break;
- default:
- ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
- break;
- }
-
- if (cfi_info->num_erase_regions == 0)
- {
- /* a device might have only one erase block, spanning the whole device */
- bank->num_sectors = 1;
- bank->sectors = malloc(sizeof(flash_sector_t));
-
- bank->sectors[sector].offset = 0x0;
- bank->sectors[sector].size = bank->size;
- bank->sectors[sector].is_erased = -1;
- bank->sectors[sector].is_protected = -1;
- }
- else
- {
- for (i = 0; i < cfi_info->num_erase_regions; i++)
- {
- num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1;
- }
-
- bank->num_sectors = num_sectors;
- bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
-
- for (i = 0; i < cfi_info->num_erase_regions; i++)
- {
- int j;
- for (j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++)
- {
- bank->sectors[sector].offset = offset;
- bank->sectors[sector].size = ((cfi_info->erase_region_info[i] >> 16) * 256) * bank->bus_width / bank->chip_width;
- offset += bank->sectors[sector].size;
- bank->sectors[sector].is_erased = -1;
- bank->sectors[sector].is_protected = -1;
- sector++;
- }
- }
- }
-
- cfi_info->probed = 1;
-
- return ERROR_OK;
-}
-
-int cfi_auto_probe(struct flash_bank_s *bank)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- if (cfi_info->probed)
- return ERROR_OK;
- return cfi_probe(bank);
-}
-
-int cfi_erase_check(struct flash_bank_s *bank)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- target_t *target = bank->target;
- int i;
- int retval;
-
- if (!cfi_info->erase_check_algorithm)
- {
- u32 erase_check_code[] =
- {
- 0xe4d03001, /* ldrb r3, [r0], #1 */
- 0xe0022003, /* and r2, r2, r3 */
- 0xe2511001, /* subs r1, r1, #1 */
- 0x1afffffb, /* b -4 */
- 0xeafffffe /* b 0 */
- };
-
- /* make sure we have a working area */
- if (target_alloc_working_area(target, 20, &cfi_info->erase_check_algorithm) != ERROR_OK)
- {
- WARNING("no working area available, falling back to slow memory reads");
- }
- else
- {
- u8 erase_check_code_buf[5 * 4];
-
- for (i = 0; i < 5; i++)
- target_buffer_set_u32(target, erase_check_code_buf + (i*4), erase_check_code[i]);
-
- /* write algorithm code to working area */
- target->type->write_memory(target, cfi_info->erase_check_algorithm->address, 4, 5, erase_check_code_buf);
- }
- }
-
- if (!cfi_info->erase_check_algorithm)
- {
- u32 *buffer = malloc(4096);
-
- for (i = 0; i < bank->num_sectors; i++)
- {
- u32 address = bank->base + bank->sectors[i].offset;
- u32 size = bank->sectors[i].size;
- u32 check = 0xffffffffU;
- int erased = 1;
-
- while (size > 0)
- {
- u32 thisrun_size = (size > 4096) ? 4096 : size;
- int j;
-
- target->type->read_memory(target, address, 4, thisrun_size / 4, (u8*)buffer);
-
- for (j = 0; j < thisrun_size / 4; j++)
- check &= buffer[j];
-
- if (check != 0xffffffff)
- {
- erased = 0;
- break;
- }
-
- size -= thisrun_size;
- address += thisrun_size;
- }
-
- bank->sectors[i].is_erased = erased;
- }
-
- free(buffer);
- }
- else
- {
- for (i = 0; i < bank->num_sectors; i++)
- {
- u32 address = bank->base + bank->sectors[i].offset;
- u32 size = bank->sectors[i].size;
-
- reg_param_t reg_params[3];
- armv4_5_algorithm_t armv4_5_info;
-
- armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
- armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
- armv4_5_info.core_state = ARMV4_5_STATE_ARM;
-
- init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
- buf_set_u32(reg_params[0].value, 0, 32, address);
-
- init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
- buf_set_u32(reg_params[1].value, 0, 32, size);
-
- init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT);
- buf_set_u32(reg_params[2].value, 0, 32, 0xff);
-
- if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params, cfi_info->erase_check_algorithm->address, cfi_info->erase_check_algorithm->address + 0x10, 10000, &armv4_5_info)) != ERROR_OK)
- return ERROR_FLASH_OPERATION_FAILED;
-
- if (buf_get_u32(reg_params[2].value, 0, 32) == 0xff)
- bank->sectors[i].is_erased = 1;
- else
- bank->sectors[i].is_erased = 0;
-
- destroy_reg_param(®_params[0]);
- destroy_reg_param(®_params[1]);
- destroy_reg_param(®_params[2]);
- }
- }
-
- return ERROR_OK;
-}
-
-int cfi_intel_protect_check(struct flash_bank_s *bank)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
- target_t *target = bank->target;
- u8 command[CFI_MAX_BUS_WIDTH];
- int i;
-
- /* check if block lock bits are supported on this device */
- if (!(pri_ext->blk_status_reg_mask & 0x1))
- return ERROR_FLASH_OPERATION_FAILED;
-
- cfi_command(bank, 0x90, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command);
-
- for (i = 0; i < bank->num_sectors; i++)
- {
- u8 block_status = cfi_get_u8(bank, i, 0x2);
-
- if (block_status & 1)
- bank->sectors[i].is_protected = 1;
- else
- bank->sectors[i].is_protected = 0;
- }
-
- cfi_command(bank, 0xff, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-
- return ERROR_OK;
-}
-
-int cfi_spansion_protect_check(struct flash_bank_s *bank)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
- cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
- target_t *target = bank->target;
- u8 command[8];
- int i;
-
- cfi_command(bank, 0xaa, command);
- target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command);
-
- cfi_command(bank, 0x55, command);
- target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command);
-
- cfi_command(bank, 0x90, command);
- target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command);
-
- for (i = 0; i < bank->num_sectors; i++)
- {
- u8 block_status = cfi_get_u8(bank, i, 0x2);
-
- if (block_status & 1)
- bank->sectors[i].is_protected = 1;
- else
- bank->sectors[i].is_protected = 0;
- }
-
- cfi_command(bank, 0xf0, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-
- return ERROR_OK;
-}
-
-int cfi_protect_check(struct flash_bank_s *bank)
-{
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
-
- if (cfi_info->qry[0] != 'Q')
- return ERROR_FLASH_BANK_NOT_PROBED;
-
- switch(cfi_info->pri_id)
- {
- case 1:
- case 3:
- return cfi_intel_protect_check(bank);
- break;
- case 2:
- return cfi_spansion_protect_check(bank);
- break;
- default:
- ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
- break;
- }
-
- return ERROR_OK;
-}
-
-int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size)
-{
- int printed;
- cfi_flash_bank_t *cfi_info = bank->driver_priv;
-
- if (cfi_info->qry[0] == (char)-1)
- {
- printed = snprintf(buf, buf_size, "\ncfi flash bank not probed yet\n");
- return ERROR_OK;
- }
-
- printed = snprintf(buf, buf_size, "\ncfi information:\n");
- buf += printed;
- buf_size -= printed;
-
- printed = snprintf(buf, buf_size, "\nmfr: 0x%4.4x, id:0x%4.4x\n",
- cfi_info->manufacturer, cfi_info->device_id);
- buf += printed;
- buf_size -= printed;
-
- printed = snprintf(buf, buf_size, "qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x\n", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr);
- buf += printed;
- buf_size -= printed;
-
- printed = snprintf(buf, buf_size, "Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x\n", (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
- (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
- (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
- (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
- buf += printed;
- buf_size -= printed;
-
- printed = snprintf(buf, buf_size, "typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u\n", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ,
- 1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ);
- buf += printed;
- buf_size -= printed;
-
- printed = snprintf(buf, buf_size, "max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u\n", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
- (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
- (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
- (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
- buf += printed;
- buf_size -= printed;
-
- printed = snprintf(buf, buf_size, "size: 0x%x, interface desc: %i, max buffer write size: %x\n", 1 << cfi_info->dev_size, cfi_info->interface_desc, cfi_info->max_buf_write_size);
- buf += printed;
- buf_size -= printed;
-
- switch(cfi_info->pri_id)
- {
- case 1:
- case 3:
- cfi_intel_info(bank, buf, buf_size);
- break;
- case 2:
- cfi_spansion_info(bank, buf, buf_size);
- break;
- default:
- ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
- break;
- }
-
- return ERROR_OK;
-}
+/*************************************************************************** + * Copyright (C) 2005, 2007 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 "cfi.h" + +#include "flash.h" +#include "target.h" +#include "log.h" +#include "armv4_5.h" +#include "algorithm.h" +#include "binarybuffer.h" +#include "types.h" + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +int cfi_register_commands(struct command_context_s *cmd_ctx); +int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank); +int cfi_erase(struct flash_bank_s *bank, int first, int last); +int cfi_protect(struct flash_bank_s *bank, int set, int first, int last); +int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count); +int cfi_probe(struct flash_bank_s *bank); +int cfi_auto_probe(struct flash_bank_s *bank); +int cfi_erase_check(struct flash_bank_s *bank); +int cfi_protect_check(struct flash_bank_s *bank); +int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size); + +int cfi_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +#define CFI_MAX_BUS_WIDTH 4 +#define CFI_MAX_CHIP_WIDTH 4 + +/* defines internal maximum size for code fragment in cfi_intel_write_block() */ +#define CFI_MAX_INTEL_CODESIZE 256 + +flash_driver_t cfi_flash = +{ + .name = "cfi", + .register_commands = cfi_register_commands, + .flash_bank_command = cfi_flash_bank_command, + .erase = cfi_erase, + .protect = cfi_protect, + .write = cfi_write, + .probe = cfi_probe, + .auto_probe = cfi_auto_probe, + .erase_check = cfi_erase_check, + .protect_check = cfi_protect_check, + .info = cfi_info +}; + +cfi_unlock_addresses_t cfi_unlock_addresses[] = +{ + [CFI_UNLOCK_555_2AA] = { .unlock1 = 0x555, .unlock2 = 0x2aa }, + [CFI_UNLOCK_5555_2AAA] = { .unlock1 = 0x5555, .unlock2 = 0x2aaa }, +}; + +/* CFI fixups foward declarations */ +void cfi_fixup_non_cfi(flash_bank_t *flash, void *param); +void cfi_fixup_0002_erase_regions(flash_bank_t *flash, void *param); +void cfi_fixup_0002_unlock_addresses(flash_bank_t *flash, void *param); +void cfi_fixup_atmel_reversed_erase_regions(flash_bank_t *flash, void *param); + +/* fixup after identifying JEDEC manufactuer and ID */ +cfi_fixup_t cfi_jedec_fixups[] = { + {CFI_MFR_SST, 0x00D4, cfi_fixup_non_cfi, NULL}, + {CFI_MFR_SST, 0x00D5, cfi_fixup_non_cfi, NULL}, + {CFI_MFR_SST, 0x00D6, cfi_fixup_non_cfi, NULL}, + {CFI_MFR_SST, 0x00D7, cfi_fixup_non_cfi, NULL}, + {CFI_MFR_SST, 0x2780, cfi_fixup_non_cfi, NULL}, + {CFI_MFR_ST, 0x00D5, cfi_fixup_non_cfi, NULL}, + {CFI_MFR_ST, 0x00D6, cfi_fixup_non_cfi, NULL}, + {CFI_MFR_AMD, 0x2223, cfi_fixup_non_cfi, NULL}, + {CFI_MFR_AMD, 0x22ab, cfi_fixup_non_cfi, NULL}, + {0, 0, NULL, NULL} +}; + +/* fixup after reading cmdset 0002 primary query table */ +cfi_fixup_t cfi_0002_fixups[] = { + {CFI_MFR_SST, 0x00D4, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, + {CFI_MFR_SST, 0x00D5, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, + {CFI_MFR_SST, 0x00D6, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, + {CFI_MFR_SST, 0x00D7, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, + {CFI_MFR_SST, 0x2780, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, + {CFI_MFR_ATMEL, 0x00C8, cfi_fixup_atmel_reversed_erase_regions, NULL}, + {CFI_MFR_ANY, CFI_ID_ANY, cfi_fixup_0002_erase_regions, NULL}, + {0, 0, NULL, NULL} +}; + +/* fixup after reading cmdset 0001 primary query table */ +cfi_fixup_t cfi_0001_fixups[] = { + {0, 0, NULL, NULL} +}; + +void cfi_fixup(flash_bank_t *bank, cfi_fixup_t *fixups) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + cfi_fixup_t *f; + + for (f = fixups; f->fixup; f++) + { + if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi_info->manufacturer)) && + ((f->id == CFI_ID_ANY) || (f->id == cfi_info->device_id))) + { + f->fixup(bank, f->param); + } + } +} + +inline u32 flash_address(flash_bank_t *bank, int sector, u32 offset) +{ + /* while the sector list isn't built, only accesses to sector 0 work */ + if (sector == 0) + return bank->base + offset * bank->bus_width; + else + { + if (!bank->sectors) + { + ERROR("BUG: sector list not yet built"); + exit(-1); + } + return bank->base + bank->sectors[sector].offset + offset * bank->bus_width; + } + +} + +void cfi_command(flash_bank_t *bank, u8 cmd, u8 *cmd_buf) +{ + int i; + + /* clear whole buffer, to ensure bits that exceed the bus_width + * are set to zero + */ + for (i = 0; i < CFI_MAX_BUS_WIDTH; i++) + cmd_buf[i] = 0; + + if (bank->target->endianness == TARGET_LITTLE_ENDIAN) + { + for (i = bank->bus_width; i > 0; i--) + { + *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd; + } + } + else + { + for (i = 1; i <= bank->bus_width; i++) + { + *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd; + } + } +} + +/* read unsigned 8-bit value from the bank + * flash banks are expected to be made of similar chips + * the query result should be the same for all + */ +u8 cfi_query_u8(flash_bank_t *bank, int sector, u32 offset) +{ + target_t *target = bank->target; + u8 data[CFI_MAX_BUS_WIDTH]; + + target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data); + + if (bank->target->endianness == TARGET_LITTLE_ENDIAN) + return data[0]; + else + return data[bank->bus_width - 1]; +} + +/* read unsigned 8-bit value from the bank + * in case of a bank made of multiple chips, + * the individual values are ORed + */ +u8 cfi_get_u8(flash_bank_t *bank, int sector, u32 offset) +{ + target_t *target = bank->target; + u8 data[CFI_MAX_BUS_WIDTH]; + int i; + + target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data); + + if (bank->target->endianness == TARGET_LITTLE_ENDIAN) + { + for (i = 0; i < bank->bus_width / bank->chip_width; i++) + data[0] |= data[i]; + + return data[0]; + } + else + { + u8 value = 0; + for (i = 0; i < bank->bus_width / bank->chip_width; i++) + value |= data[bank->bus_width - 1 - i]; + + return value; + } +} + +u16 cfi_query_u16(flash_bank_t *bank, int sector, u32 offset) +{ + target_t *target = bank->target; + u8 data[CFI_MAX_BUS_WIDTH * 2]; + + target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 2, data); + + if (bank->target->endianness == TARGET_LITTLE_ENDIAN) + return data[0] | data[bank->bus_width] << 8; + else + return data[bank->bus_width - 1] | data[(2 * bank->bus_width) - 1] << 8; +} + +u32 cfi_query_u32(flash_bank_t *bank, int sector, u32 offset) +{ + target_t *target = bank->target; + u8 data[CFI_MAX_BUS_WIDTH * 4]; + + target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 4, data); + + if (bank->target->endianness == TARGET_LITTLE_ENDIAN) + return data[0] | data[bank->bus_width] << 8 | data[bank->bus_width * 2] << 16 | data[bank->bus_width * 3] << 24; + else + return data[bank->bus_width - 1] | data[(2* bank->bus_width) - 1] << 8 | + data[(3 * bank->bus_width) - 1] << 16 | data[(4 * bank->bus_width) - 1] << 24; +} + +void cfi_intel_clear_status_register(flash_bank_t *bank) +{ + target_t *target = bank->target; + u8 command[8]; + + if (target->state != TARGET_HALTED) + { + ERROR("BUG: attempted to clear status register while target wasn't halted"); + exit(-1); + } + + cfi_command(bank, 0x50, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); +} + +u8 cfi_intel_wait_status_busy(flash_bank_t *bank, int timeout) +{ + u8 status; + + while ((!((status = cfi_get_u8(bank, 0, 0x0)) & 0x80)) && (timeout-- > 0)) + { + DEBUG("status: 0x%x", status); + usleep(1000); + } + + /* mask out bit 0 (reserved) */ + status = status & 0xfe; + + DEBUG("status: 0x%x", status); + + if ((status & 0x80) != 0x80) + { + ERROR("timeout while waiting for WSM to become ready"); + } + else if (status != 0x80) + { + ERROR("status register: 0x%x", status); + if (status & 0x2) + ERROR("Block Lock-Bit Detected, Operation Abort"); + if (status & 0x4) + ERROR("Program suspended"); + if (status & 0x8) + ERROR("Low Programming Voltage Detected, Operation Aborted"); + if (status & 0x10) + ERROR("Program Error / Error in Setting Lock-Bit"); + if (status & 0x20) + ERROR("Error in Block Erasure or Clear Lock-Bits"); + if (status & 0x40) + ERROR("Block Erase Suspended"); + + cfi_intel_clear_status_register(bank); + } + + return status; +} + +int cfi_spansion_wait_status_busy(flash_bank_t *bank, int timeout) +{ + u8 status, oldstatus; + + oldstatus = cfi_get_u8(bank, 0, 0x0); + + do { + status = cfi_get_u8(bank, 0, 0x0); + if ((status ^ oldstatus) & 0x40) { + if (status & 0x20) { + oldstatus = cfi_get_u8(bank, 0, 0x0); + status = cfi_get_u8(bank, 0, 0x0); + if ((status ^ oldstatus) & 0x40) { + ERROR("dq5 timeout, status: 0x%x", status); + return(ERROR_FLASH_OPERATION_FAILED); + } else { + DEBUG("status: 0x%x", status); + return(ERROR_OK); + } + } + } else { + DEBUG("status: 0x%x", status); + return(ERROR_OK); + } + + oldstatus = status; + usleep(1000); + } while (timeout-- > 0); + + ERROR("timeout, status: 0x%x", status); + + return(ERROR_FLASH_BUSY); +} + +int cfi_read_intel_pri_ext(flash_bank_t *bank) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + cfi_intel_pri_ext_t *pri_ext = malloc(sizeof(cfi_intel_pri_ext_t)); + target_t *target = bank->target; + u8 command[8]; + + cfi_info->pri_ext = pri_ext; + + pri_ext->pri[0] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0); + pri_ext->pri[1] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1); + pri_ext->pri[2] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2); + + if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I')) + { + cfi_command(bank, 0xf0, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + cfi_command(bank, 0xff, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + return ERROR_FLASH_BANK_INVALID; + } + + pri_ext->major_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3); + pri_ext->minor_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4); + + DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); + + pri_ext->feature_support = cfi_query_u32(bank, 0, cfi_info->pri_addr + 5); + pri_ext->suspend_cmd_support = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9); + pri_ext->blk_status_reg_mask = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xa); + + DEBUG("feature_support: 0x%x, suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x", pri_ext->feature_support, pri_ext->suspend_cmd_support, pri_ext->blk_status_reg_mask); + + pri_ext->vcc_optimal = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xc); + pri_ext->vpp_optimal = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xd); + + DEBUG("Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x", + (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f, + (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f); + + pri_ext->num_protection_fields = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xe); + if (pri_ext->num_protection_fields != 1) + { + WARNING("expected one protection register field, but found %i", pri_ext->num_protection_fields); + } + + pri_ext->prot_reg_addr = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xf); + pri_ext->fact_prot_reg_size = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x11); + pri_ext->user_prot_reg_size = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x12); + + DEBUG("protection_fields: %i, prot_reg_addr: 0x%x, factory pre-programmed: %i, user programmable: %i", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size); + + return ERROR_OK; +} + +int cfi_read_spansion_pri_ext(flash_bank_t *bank) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + cfi_spansion_pri_ext_t *pri_ext = malloc(sizeof(cfi_spansion_pri_ext_t)); + target_t *target = bank->target; + u8 command[8]; + + cfi_info->pri_ext = pri_ext; + + pri_ext->pri[0] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0); + pri_ext->pri[1] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1); + pri_ext->pri[2] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2); + + if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I')) + { + cfi_command(bank, 0xf0, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + return ERROR_FLASH_BANK_INVALID; + } + + pri_ext->major_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3); + pri_ext->minor_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4); + + DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); + + pri_ext->SiliconRevision = cfi_query_u8(bank, 0, cfi_info->pri_addr + 5); + pri_ext->EraseSuspend = cfi_query_u8(bank, 0, cfi_info->pri_addr + 6); + pri_ext->BlkProt = cfi_query_u8(bank, 0, cfi_info->pri_addr + 7); + pri_ext->TmpBlkUnprotect = cfi_query_u8(bank, 0, cfi_info->pri_addr + 8); + pri_ext->BlkProtUnprot = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9); + pri_ext->SimultaneousOps = cfi_query_u8(bank, 0, cfi_info->pri_addr + 10); + pri_ext->BurstMode = cfi_query_u8(bank, 0, cfi_info->pri_addr + 11); + pri_ext->PageMode = cfi_query_u8(bank, 0, cfi_info->pri_addr + 12); + pri_ext->VppMin = cfi_query_u8(bank, 0, cfi_info->pri_addr + 13); + pri_ext->VppMax = cfi_query_u8(bank, 0, cfi_info->pri_addr + 14); + pri_ext->TopBottom = cfi_query_u8(bank, 0, cfi_info->pri_addr + 15); + + DEBUG("Silicon Revision: 0x%x, Erase Suspend: 0x%x, Block protect: 0x%x", pri_ext->SiliconRevision, + pri_ext->EraseSuspend, pri_ext->BlkProt); + + DEBUG("Temporary Unprotect: 0x%x, Block Protect Scheme: 0x%x, Simultaneous Ops: 0x%x", pri_ext->TmpBlkUnprotect, + pri_ext->BlkProtUnprot, pri_ext->SimultaneousOps); + + DEBUG("Burst Mode: 0x%x, Page Mode: 0x%x, ", pri_ext->BurstMode, pri_ext->PageMode); + + + DEBUG("Vpp min: %2.2d.%1.1d, Vpp max: %2.2d.%1.1x", + (pri_ext->VppMin & 0xf0) >> 4, pri_ext->VppMin & 0x0f, + (pri_ext->VppMax & 0xf0) >> 4, pri_ext->VppMax & 0x0f); + + DEBUG("WP# protection 0x%x", pri_ext->TopBottom); + + /* default values for implementation specific workarounds */ + pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1; + pri_ext->_unlock2 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock2; + pri_ext->_reversed_geometry = 0; + + return ERROR_OK; +} + +int cfi_read_atmel_pri_ext(flash_bank_t *bank) +{ + cfi_atmel_pri_ext_t atmel_pri_ext; + cfi_flash_bank_t *cfi_info = bank->driver_priv; + cfi_spansion_pri_ext_t *pri_ext = malloc(sizeof(cfi_spansion_pri_ext_t)); + target_t *target = bank->target; + u8 command[8]; + + /* ATMEL devices use the same CFI primary command set (0x2) as AMD/Spansion, + * but a different primary extended query table. + * We read the atmel table, and prepare a valid AMD/Spansion query table. + */ + + memset(pri_ext, 0, sizeof(cfi_spansion_pri_ext_t)); + + cfi_info->pri_ext = pri_ext; + + atmel_pri_ext.pri[0] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0); + atmel_pri_ext.pri[1] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1); + atmel_pri_ext.pri[2] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2); + + if ((atmel_pri_ext.pri[0] != 'P') || (atmel_pri_ext.pri[1] != 'R') || (atmel_pri_ext.pri[2] != 'I')) + { + cfi_command(bank, 0xf0, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + return ERROR_FLASH_BANK_INVALID; + } + + pri_ext->pri[0] = atmel_pri_ext.pri[0]; + pri_ext->pri[1] = atmel_pri_ext.pri[1]; + pri_ext->pri[2] = atmel_pri_ext.pri[2]; + + atmel_pri_ext.major_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3); + atmel_pri_ext.minor_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4); + + DEBUG("pri: '%c%c%c', version: %c.%c", atmel_pri_ext.pri[0], atmel_pri_ext.pri[1], atmel_pri_ext.pri[2], atmel_pri_ext.major_version, atmel_pri_ext.minor_version); + + pri_ext->major_version = atmel_pri_ext.major_version; + pri_ext->minor_version = atmel_pri_ext.minor_version; + + atmel_pri_ext.features = cfi_query_u8(bank, 0, cfi_info->pri_addr + 5); + atmel_pri_ext.bottom_boot = cfi_query_u8(bank, 0, cfi_info->pri_addr + 6); + atmel_pri_ext.burst_mode = cfi_query_u8(bank, 0, cfi_info->pri_addr + 7); + atmel_pri_ext.page_mode = cfi_query_u8(bank, 0, cfi_info->pri_addr + 8); + + DEBUG("features: 0x%2.2x, bottom_boot: 0x%2.2x, burst_mode: 0x%2.2x, page_mode: 0x%2.2x", + atmel_pri_ext.features, atmel_pri_ext.bottom_boot, atmel_pri_ext.burst_mode, atmel_pri_ext.page_mode); + + if (atmel_pri_ext.features & 0x02) + pri_ext->EraseSuspend = 2; + + if (atmel_pri_ext.bottom_boot) + pri_ext->TopBottom = 2; + else + pri_ext->TopBottom = 3; + + pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1; + pri_ext->_unlock2 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock2; + + return ERROR_OK; +} + +int cfi_read_0002_pri_ext(flash_bank_t *bank) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + + if (cfi_info->manufacturer == CFI_MFR_ATMEL) + { + return cfi_read_atmel_pri_ext(bank); + } + else + { + return cfi_read_spansion_pri_ext(bank); + } +} + +int cfi_spansion_info(struct flash_bank_s *bank, char *buf, int buf_size) +{ + int printed; + cfi_flash_bank_t *cfi_info = bank->driver_priv; + cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext; + + printed = snprintf(buf, buf_size, "\nSpansion primary algorithm extend information:\n"); + buf += printed; + buf_size -= printed; + + printed = snprintf(buf, buf_size, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0], + pri_ext->pri[1], pri_ext->pri[2], + pri_ext->major_version, pri_ext->minor_version); + buf += printed; + buf_size -= printed; + + printed = snprintf(buf, buf_size, "Silicon Rev.: 0x%x, Address Sensitive unlock: 0x%x\n", + (pri_ext->SiliconRevision) >> 2, + (pri_ext->SiliconRevision) & 0x03); + buf += printed; + buf_size -= printed; + + printed = snprintf(buf, buf_size, "Erase Suspend: 0x%x, Sector Protect: 0x%x\n", + pri_ext->EraseSuspend, + pri_ext->BlkProt); + buf += printed; + buf_size -= printed; + + printed = snprintf(buf, buf_size, "VppMin: %2.2d.%1.1x, VppMax: %2.2d.%1.1x\n", + (pri_ext->VppMin & 0xf0) >> 4, pri_ext->VppMin & 0x0f, + (pri_ext->VppMax & 0xf0) >> 4, pri_ext->VppMax & 0x0f); + + return ERROR_OK; +} + +int cfi_intel_info(struct flash_bank_s *bank, char *buf, int buf_size) +{ + int printed; + cfi_flash_bank_t *cfi_info = bank->driver_priv; + cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext; + + printed = snprintf(buf, buf_size, "\nintel primary algorithm extend information:\n"); + buf += printed; + buf_size -= printed; + + printed = snprintf(buf, buf_size, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); + buf += printed; + buf_size -= printed; + + printed = snprintf(buf, buf_size, "feature_support: 0x%x, suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x\n", pri_ext->feature_support, pri_ext->suspend_cmd_support, pri_ext->blk_status_reg_mask); + buf += printed; + buf_size -= printed; + + printed = snprintf(buf, buf_size, "Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x\n", + (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f, + (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f); + buf += printed; + buf_size -= printed; + + printed = snprintf(buf, buf_size, "protection_fields: %i, prot_reg_addr: 0x%x, factory pre-programmed: %i, user programmable: %i\n", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size); + + return ERROR_OK; +} + +int cfi_register_commands(struct command_context_s *cmd_ctx) +{ + /*command_t *cfi_cmd = */ + register_command(cmd_ctx, NULL, "cfi", NULL, COMMAND_ANY, "flash bank cfi <base> <size> <chip_width> <bus_width> <targetNum> [jedec_probe/x16_as_x8]"); + /* + register_command(cmd_ctx, cfi_cmd, "part_id", cfi_handle_part_id_command, COMMAND_EXEC, + "print part id of cfi flash bank <num>"); + */ + return ERROR_OK; +} + +/* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#> [options] + */ +int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank) +{ + cfi_flash_bank_t *cfi_info; + int i; + + if (argc < 6) + { + WARNING("incomplete flash_bank cfi configuration"); + return ERROR_FLASH_BANK_INVALID; + } + + if ((strtoul(args[4], NULL, 0) > CFI_MAX_CHIP_WIDTH) + || (strtoul(args[3], NULL, 0) > CFI_MAX_BUS_WIDTH)) + { + ERROR("chip and bus width have to specified in bytes"); + return ERROR_FLASH_BANK_INVALID; + } + + cfi_info = malloc(sizeof(cfi_flash_bank_t)); + cfi_info->probed = 0; + bank->driver_priv = cfi_info; + + cfi_info->write_algorithm = NULL; + cfi_info->erase_check_algorithm = NULL; + + cfi_info->x16_as_x8 = 0; + cfi_info->jedec_probe = 0; + cfi_info->not_cfi = 0; + + for (i = 6; i < argc; i++) + { + if (strcmp(args[i], "x16_as_x8") == 0) + { + cfi_info->x16_as_x8 = 1; + } + else if (strcmp(args[i], "jedec_probe") == 0) + { + cfi_info->jedec_probe = 1; + } + } + + cfi_info->write_algorithm = NULL; + + /* bank wasn't probed yet */ + cfi_info->qry[0] = -1; + + return ERROR_OK; +} + +int cfi_intel_erase(struct flash_bank_s *bank, int first, int last) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + target_t *target = bank->target; + u8 command[8]; + int i; + + cfi_intel_clear_status_register(bank); + + for (i = first; i <= last; i++) + { + cfi_command(bank, 0x20, command); + target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command); + + cfi_command(bank, 0xd0, command); + target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command); + + if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->block_erase_timeout_typ)) == 0x80) + bank->sectors[i].is_erased = 1; + else + { + cfi_command(bank, 0xff, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + + ERROR("couldn't erase block %i of flash bank at base 0x%x", i, bank->base); + return ERROR_FLASH_OPERATION_FAILED; + } + } + + cfi_command(bank, 0xff, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + + return ERROR_OK; +} + +int cfi_spansion_erase(struct flash_bank_s *bank, int first, int last) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext; + target_t *target = bank->target; + u8 command[8]; + int i; + + for (i = first; i <= last; i++) + { + cfi_command(bank, 0xaa, command); + target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); + + cfi_command(bank, 0x55, command); + target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command); + + cfi_command(bank, 0x80, command); + target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); + + cfi_command(bank, 0xaa, command); + target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); + + cfi_command(bank, 0x55, command); + target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command); + + cfi_command(bank, 0x30, command); + target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command); + + if (cfi_spansion_wait_status_busy(bank, 1000 * (1 << cfi_info->block_erase_timeout_typ)) == ERROR_OK) + bank->sectors[i].is_erased = 1; + else + { + cfi_command(bank, 0xf0, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + + ERROR("couldn't erase block %i of flash bank at base 0x%x", i, bank->base); + return ERROR_FLASH_OPERATION_FAILED; + } + } + + cfi_command(bank, 0xf0, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + + return ERROR_OK; +} + +int cfi_erase(struct flash_bank_s *bank, int first, int last) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + + if (bank->target->state != TARGET_HALTED) + { + return ERROR_TARGET_NOT_HALTED; + } + + if ((first < 0) || (last < first) || (last >= bank->num_sectors)) + { + return ERROR_FLASH_SECTOR_INVALID; + } + + if (cfi_info->qry[0] != 'Q') + return ERROR_FLASH_BANK_NOT_PROBED; + + switch(cfi_info->pri_id) + { + case 1: + case 3: + return cfi_intel_erase(bank, first, last); + break; + case 2: + return cfi_spansion_erase(bank, first, last); + break; + default: + ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; + } + + return ERROR_OK; +} + +int cfi_intel_protect(struct flash_bank_s *bank, int set, int first, int last) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext; + target_t *target = bank->target; + u8 command[8]; + int retry = 0; + int i; + + /* if the device supports neither legacy lock/unlock (bit 3) nor + * instant individual block locking (bit 5). + */ + if (!(pri_ext->feature_support & 0x28)) + return ERROR_FLASH_OPERATION_FAILED; + + cfi_intel_clear_status_register(bank); + + for (i = first; i <= last; i++) + { + cfi_command(bank, 0x60, command); + DEBUG("address: 0x%4.4x, command: 0x%4.4x", flash_address(bank, i, 0x0), target_buffer_get_u32(target, command)); + target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command); + if (set) + { + cfi_command(bank, 0x01, command); + DEBUG("address: 0x%4.4x, command: 0x%4.4x", flash_address(bank, i, 0x0), target_buffer_get_u32(target, command)); + target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command); + bank->sectors[i].is_protected = 1; + } + else + { + cfi_command(bank, 0xd0, command); + DEBUG("address: 0x%4.4x, command: 0x%4.4x", flash_address(bank, i, 0x0), target_buffer_get_u32(target, command)); + target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command); + bank->sectors[i].is_protected = 0; + } + + /* instant individual block locking doesn't require reading of the status register */ + if (!(pri_ext->feature_support & 0x20)) + { + /* Clear lock bits operation may take up to 1.4s */ + cfi_intel_wait_status_busy(bank, 1400); + } + else + { + u8 block_status; + /* read block lock bit, to verify status */ + cfi_command(bank, 0x90, command); + target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command); + block_status = cfi_get_u8(bank, i, 0x2); + + if ((block_status & 0x1) != set) + { + ERROR("couldn't change block lock status (set = %i, block_status = 0x%2.2x)", set, block_status); + cfi_command(bank, 0x70, command); + target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command); + cfi_intel_wait_status_busy(bank, 10); + + if (retry > 10) + return ERROR_FLASH_OPERATION_FAILED; + else + { + i--; + retry++; + } + } + } + } + + /* if the device doesn't support individual block lock bits set/clear, + * all blocks have been unlocked in parallel, so we set those that should be protected + */ + if ((!set) && (!(pri_ext->feature_support & 0x20))) + { + for (i = 0; i < bank->num_sectors; i++) + { + if (bank->sectors[i].is_protected == 1) + { + cfi_intel_clear_status_register(bank); + + cfi_command(bank, 0x60, command); + target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command); + + cfi_command(bank, 0x01, command); + target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command); + + cfi_intel_wait_status_busy(bank, 100); + } + } + } + + cfi_command(bank, 0xff, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + + return ERROR_OK; +} + +int cfi_protect(struct flash_bank_s *bank, int set, int first, int last) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + + if (bank->target->state != TARGET_HALTED) + { + return ERROR_TARGET_NOT_HALTED; + } + + if ((first < 0) || (last < first) || (last >= bank->num_sectors)) + { + return ERROR_FLASH_SECTOR_INVALID; + } + + if (cfi_info->qry[0] != 'Q') + return ERROR_FLASH_BANK_NOT_PROBED; + + switch(cfi_info->pri_id) + { + case 1: + case 3: + cfi_intel_protect(bank, set, first, last); + break; + default: + ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; + } + + return ERROR_OK; +} + +/* FIXME Replace this by a simple memcpy() - still unsure about sideeffects */ +static void cfi_add_byte(struct flash_bank_s *bank, u8 *word, u8 byte) +{ + //target_t *target = bank->target; + + int i; + + // NOTE: + // The data to flash must not be changed in endian! We write a bytestrem in + // target byte order already. Only the control and status byte lane of the flash + // WSM is interpreted by the CPU in different ways, when read a u16 or u32 + // word (data seems to be in the upper or lower byte lane for u16 accesses). + + //if (target->endianness == TARGET_LITTLE_ENDIAN) + //{ + /* shift bytes */ + for (i = 0; i < bank->bus_width - 1; i++) + word[i] = word[i + 1]; + word[bank->bus_width - 1] = byte; + //} + //else + //{ + // /* shift bytes */ + // for (i = bank->bus_width - 1; i > 0; i--) + // word[i] = word[i - 1]; + // word[0] = byte; + //} +} + +/* Convert code image to target endian */ +/* FIXME create general block conversion fcts in target.c?) */ static +void cfi_fix_code_endian(target_t *target, u32 *dest, const u32 *src, u32 count) +{ + u32 i; + for (i=0; i< count; i++) + { + target_buffer_set_u32(target, (u8*)dest, *src); + dest++; + src++; + } +} + +int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u32 count) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + target_t *target = bank->target; + reg_param_t reg_params[7]; + armv4_5_algorithm_t armv4_5_info; + working_area_t *source; + u32 buffer_size = 32768; + u8 write_command_buf[CFI_MAX_BUS_WIDTH]; + u8 busy_pattern_buf[CFI_MAX_BUS_WIDTH]; + u8 error_pattern_buf[CFI_MAX_BUS_WIDTH]; + u32 write_command_val, busy_pattern_val, error_pattern_val; + + /* algorithm register usage: + * r0: source address (in RAM) + * r1: target address (in Flash) + * r2: count + * r3: flash write command + * r4: status byte (returned to host) + * r5: busy test pattern + * r6: error test pattern + */ + + static const u32 word_32_code[] = { + 0xe4904004, /* loop: ldr r4, [r0], #4 */ + 0xe5813000, /* str r3, [r1] */ + 0xe5814000, /* str r4, [r1] */ + 0xe5914000, /* busy: ldr r4, [r1] */ + 0xe0047005, /* and r7, r4, r5 */ + 0xe1570005, /* cmp r7, r5 */ + 0x1afffffb, /* bne busy */ + 0xe1140006, /* tst r4, r6 */ + 0x1a000003, /* bne done */ + 0xe2522001, /* subs r2, r2, #1 */ + 0x0a000001, /* beq done */ + 0xe2811004, /* add r1, r1 #4 */ + 0xeafffff2, /* b loop */ + 0xeafffffe /* done: b -2 */ + }; + + static const u32 word_16_code[] = { + 0xe0d040b2, /* loop: ldrh r4, [r0], #2 */ + 0xe1c130b0, /* strh r3, [r1] */ + 0xe1c140b0, /* strh r4, [r1] */ + 0xe1d140b0, /* busy ldrh r4, [r1] */ + 0xe0047005, /* and r7, r4, r5 */ + 0xe1570005, /* cmp r7, r5 */ + 0x1afffffb, /* bne busy */ + 0xe1140006, /* tst r4, r6 */ + 0x1a000003, /* bne done */ + 0xe2522001, /* subs r2, r2, #1 */ + 0x0a000001, /* beq done */ + 0xe2811002, /* add r1, r1 #2 */ + 0xeafffff2, /* b loop */ + 0xeafffffe /* done: b -2 */ + }; + + static const u32 word_8_code[] = { + 0xe4d04001, /* loop: ldrb r4, [r0], #1 */ + 0xe5c13000, /* strb r3, [r1] */ + 0xe5c14000, /* strb r4, [r1] */ + 0xe5d14000, /* busy ldrb r4, [r1] */ + 0xe0047005, /* and r7, r4, r5 */ + 0xe1570005, /* cmp r7, r5 */ + 0x1afffffb, /* bne busy */ + 0xe1140006, /* tst r4, r6 */ + 0x1a000003, /* bne done */ + 0xe2522001, /* subs r2, r2, #1 */ + 0x0a000001, /* beq done */ + 0xe2811001, /* add r1, r1 #1 */ + 0xeafffff2, /* b loop */ + 0xeafffffe /* done: b -2 */ + }; + u32 target_code[CFI_MAX_INTEL_CODESIZE]; + const u32 *target_code_src; + int target_code_size; + int retval = ERROR_OK; + + + cfi_intel_clear_status_register(bank); + + 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; + + /* If we are setting up the write_algorith, we need target_code_src */ + /* if not we only need target_code_size. */ + /* */ + /* However, we don't want to create multiple code paths, so we */ + /* do the unecessary evaluation of target_code_src, which the */ + /* compiler will probably nicely optimize away if not needed */ + + /* prepare algorithm code for target endian */ + switch (bank->bus_width) + { + case 1 : + target_code_src = word_8_code; + target_code_size = sizeof(word_8_code); + break; + case 2 : + target_code_src = word_16_code; + target_code_size = sizeof(word_16_code); + break; + case 4 : + target_code_src = word_32_code; + target_code_size = sizeof(word_32_code); + break; + default: + ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* flash write code */ + if (!cfi_info->write_algorithm) + { + if ( target_code_size > sizeof(target_code) ) + { + WARNING("Internal error - target code buffer to small. Increase CFI_MAX_INTEL_CODESIZE and recompile."); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + cfi_fix_code_endian(target, target_code, target_code_src, target_code_size); + + /* Get memory for block write handler */ + retval = target_alloc_working_area(target, target_code_size, &cfi_info->write_algorithm); + if (retval != ERROR_OK) + { + WARNING("No working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + }; + + /* write algorithm code to working area */ + retval = target_write_buffer(target, cfi_info->write_algorithm->address, target_code_size, (u8*)target_code); + if (retval != ERROR_OK) + { + ERROR("Unable to write block write code to target"); + goto cleanup; + } + } + + /* Get a workspace buffer for the data to flash starting with 32k size. + Half size until buffer would be smaller 256 Bytem then fail back */ + /* FIXME Why 256 bytes, why not 32 bytes (smallest flash write page */ + while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) + { + buffer_size /= 2; + if (buffer_size <= 256) + { + WARNING("no large enough working area available, can't do block memory writes"); + retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + goto cleanup; + } + }; + + /* setup algo registers */ + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); + init_reg_param(®_params[4], "r4", 32, PARAM_IN); + init_reg_param(®_params[5], "r5", 32, PARAM_OUT); + init_reg_param(®_params[6], "r6", 32, PARAM_OUT); + + /* prepare command and status register patterns */ + cfi_command(bank, 0x40, write_command_buf); + cfi_command(bank, 0x80, busy_pattern_buf); + cfi_command(bank, 0x7e, error_pattern_buf); + + switch (bank->bus_width) + { + case 1 : + write_command_val = write_command_buf[0]; + busy_pattern_val = busy_pattern_buf[0]; + error_pattern_val = error_pattern_buf[0]; + break; + case 2 : + write_command_val = target_buffer_get_u16(target, write_command_buf); + busy_pattern_val = target_buffer_get_u16(target, busy_pattern_buf); + error_pattern_val = target_buffer_get_u16(target, error_pattern_buf); + break; + case 4 : + write_command_val = target_buffer_get_u32(target, write_command_buf); + busy_pattern_val = target_buffer_get_u32(target, busy_pattern_buf); + error_pattern_val = target_buffer_get_u32(target, error_pattern_buf); + break; + default : + ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width); + retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + goto cleanup; + } + + INFO("Using target buffer at 0x%08x and of size 0x%04x", source->address, buffer_size ); + + /* Programming main loop */ + while (count > 0) + { + u32 thisrun_count = (count > buffer_size) ? buffer_size : count; + u32 wsm_error; + + target_write_buffer(target, source->address, thisrun_count, 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 / bank->bus_width); + + buf_set_u32(reg_params[3].value, 0, 32, write_command_val); + buf_set_u32(reg_params[5].value, 0, 32, busy_pattern_val); + buf_set_u32(reg_params[6].value, 0, 32, error_pattern_val); + + INFO("Write 0x%04x bytes to flash at 0x%08x", thisrun_count, address ); + + /* Execute algorithm, assume breakpoint for last instruction */ + retval = target->type->run_algorithm(target, 0, NULL, 7, reg_params, + cfi_info->write_algorithm->address, + cfi_info->write_algorithm->address + target_code_size - sizeof(u32), + 10000, /* 10s should be enough for max. 32k of data */ + &armv4_5_info); + + /* On failure try a fall back to direct word writes */ + if (retval != ERROR_OK) + { + cfi_intel_clear_status_register(bank); + ERROR("Execution of flash algorythm failed. Can't fall back. Please report."); + retval = ERROR_FLASH_OPERATION_FAILED; + //retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + // FIXME To allow fall back or recovery, we must save the actual status + // somewhere, so that a higher level code can start recovery. + goto cleanup; + } + + /* Check return value from algo code */ + wsm_error = buf_get_u32(reg_params[4].value, 0, 32) & error_pattern_val; + if (wsm_error) + { + /* read status register (outputs debug inforation) */ + cfi_intel_wait_status_busy(bank, 100); + cfi_intel_clear_status_register(bank); + retval = ERROR_FLASH_OPERATION_FAILED; + goto cleanup; + } + + buffer += thisrun_count; + address += thisrun_count; + count -= thisrun_count; + } + + /* free up resources */ +cleanup: + if (source) + target_free_working_area(target, source); + + if (cfi_info->write_algorithm) + { + target_free_working_area(target, cfi_info->write_algorithm); + cfi_info->write_algorithm = NULL; + } + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + destroy_reg_param(®_params[5]); + destroy_reg_param(®_params[6]); + + return retval; +} + +int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u32 count) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext; + target_t *target = bank->target; + reg_param_t reg_params[10]; + armv4_5_algorithm_t armv4_5_info; + working_area_t *source; + u32 buffer_size = 32768; + u8 write_command[CFI_MAX_BUS_WIDTH]; + u32 status; + int i; + int retval; + int exit_code = ERROR_OK; + + /* input parameters - */ + /* R0 = source address */ + /* R1 = destination address */ + /* R2 = number of writes */ + /* R3 = flash write command */ + /* R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */ + /* output parameters - */ + /* R5 = 0x80 ok 0x00 bad */ + /* temp registers - */ + /* R6 = value read from flash to test status */ + /* R7 = holding register */ + /* unlock registers - */ + /* R8 = unlock1_addr */ + /* R9 = unlock1_cmd */ + /* R10 = unlock2_addr */ + /* R11 = unlock2_cmd */ + + u32 word_32_code[] = { + /* 00008100 <sp_32_code>: */ + 0xe4905004, /* ldr r5, [r0], #4 */ + 0xe5889000, /* str r9, [r8] */ + 0xe58ab000, /* str r11, [r10] */ + 0xe5883000, /* str r3, [r8] */ + 0xe5815000, /* str r5, [r1] */ + 0xe1a00000, /* nop */ + /* */ + /* 00008110 <sp_32_busy>: */ + 0xe5916000, /* ldr r6, [r1] */ + 0xe0257006, /* eor r7, r5, r6 */ + 0xe0147007, /* ands r7, r4, r7 */ + 0x0a000007, /* beq 8140 <sp_32_cont> ; b if DQ7 == Data7 */ + 0xe0166124, /* ands r6, r6, r4, lsr #2 */ + 0x0afffff9, /* beq 8110 <sp_32_busy> ; b if DQ5 low */ + 0xe5916000, /* ldr r6, [r1] */ + 0xe0257006, /* eor r7, r5, r6 */ + 0xe0147007, /* ands r7, r4, r7 */ + 0x0a000001, /* beq 8140 <sp_32_cont> ; b if DQ7 == Data7 */ + 0xe3a05000, /* mov r5, #0 ; 0x0 - return 0x00, error */ + 0x1a000004, /* bne 8154 <sp_32_done> */ + /* */ + /* 00008140 <sp_32_cont>: */ + 0xe2522001, /* subs r2, r2, #1 ; 0x1 */ + 0x03a05080, /* moveq r5, #128 ; 0x80 */ + 0x0a000001, /* beq 8154 <sp_32_done> */ + 0xe2811004, /* add r1, r1, #4 ; 0x4 */ + 0xeaffffe8, /* b 8100 <sp_32_code> */ + /* */ + /* 00008154 <sp_32_done>: */ + 0xeafffffe /* b 8154 <sp_32_done> */ + }; + + u32 word_16_code[] = { + /* 00008158 <sp_16_code>: */ + 0xe0d050b2, /* ldrh r5, [r0], #2 */ + 0xe1c890b0, /* strh r9, [r8] */ + 0xe1cab0b0, /* strh r11, [r10] */ + 0xe1c830b0, /* strh r3, [r8] */ + 0xe1c150b0, /* strh r5, [r1] */ + 0xe1a00000, /* nop (mov r0,r0) */ + /* */ + /* 00008168 <sp_16_busy>: */ + 0xe1d160b0, /* ldrh r6, [r1] */ + 0xe0257006, /* eor r7, r5, r6 */ + 0xe0147007, /* ands r7, r4, r7 */ + 0x0a000007, /* beq 8198 <sp_16_cont> */ + 0xe0166124, /* ands r6, r6, r4, lsr #2 */ + 0x0afffff9, /* beq 8168 <sp_16_busy> */ + 0xe1d160b0, /* ldrh r6, [r1] */ + 0xe0257006, /* eor r7, r5, r6 */ + 0xe0147007, /* ands r7, r4, r7 */ + 0x0a000001, /* beq 8198 <sp_16_cont> */ + 0xe3a05000, /* mov r5, #0 ; 0x0 */ + 0x1a000004, /* bne 81ac <sp_16_done> */ + /* */ + /* 00008198 <sp_16_cont>: */ + 0xe2522001, /* subs r2, r2, #1 ; 0x1 */ + 0x03a05080, /* moveq r5, #128 ; 0x80 */ + 0x0a000001, /* beq 81ac <sp_16_done> */ + 0xe2811002, /* add r1, r1, #2 ; 0x2 */ + 0xeaffffe8, /* b 8158 <sp_16_code> */ + /* */ + /* 000081ac <sp_16_done>: */ + 0xeafffffe /* b 81ac <sp_16_done> */ + }; + + u32 word_8_code[] = { + /* 000081b0 <sp_16_code_end>: */ + 0xe4d05001, /* ldrb r5, [r0], #1 */ + 0xe5c89000, /* strb r9, [r8] */ + 0xe5cab000, /* strb r11, [r10] */ + 0xe5c83000, /* strb r3, [r8] */ + 0xe5c15000, /* strb r5, [r1] */ + 0xe1a00000, /* nop (mov r0,r0) */ + /* */ + /* 000081c0 <sp_8_busy>: */ + 0xe5d16000, /* ldrb r6, [r1] */ + 0xe0257006, /* eor r7, r5, r6 */ + 0xe0147007, /* ands r7, r4, r7 */ + 0x0a000007, /* beq 81f0 <sp_8_cont> */ + 0xe0166124, /* ands r6, r6, r4, lsr #2 */ + 0x0afffff9, /* beq 81c0 <sp_8_busy> */ + 0xe5d16000, /* ldrb r6, [r1] */ + 0xe0257006, /* eor r7, r5, r6 */ + 0xe0147007, /* ands r7, r4, r7 */ + 0x0a000001, /* beq 81f0 <sp_8_cont> */ + 0xe3a05000, /* mov r5, #0 ; 0x0 */ + 0x1a000004, /* bne 8204 <sp_8_done> */ + /* */ + /* 000081f0 <sp_8_cont>: */ + 0xe2522001, /* subs r2, r2, #1 ; 0x1 */ + 0x03a05080, /* moveq r5, #128 ; 0x80 */ + 0x0a000001, /* beq 8204 <sp_8_done> */ + 0xe2811001, /* add r1, r1, #1 ; 0x1 */ + 0xeaffffe8, /* b 81b0 <sp_16_code_end> */ + /* */ + /* 00008204 <sp_8_done>: */ + 0xeafffffe /* b 8204 <sp_8_done> */ + }; + + 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; + + /* flash write code */ + if (!cfi_info->write_algorithm) + { + u8 *code_p; + + /* convert bus-width dependent algorithm code to correct endiannes */ + if (bank->bus_width == 1) + { + code_p = malloc(24 * 4); + + for (i = 0; i < 24; i++) + target_buffer_set_u32(target, code_p + (i*4), word_8_code[i]); + } + else if (bank->bus_width == 2) + { + code_p = malloc(24 * 4); + + for (i = 0; i < 24; i++) + target_buffer_set_u32(target, code_p + (i*4), word_16_code[i]); + } + else if (bank->bus_width == 4) + { + code_p = malloc(24 * 4); + + for (i = 0; i < 24; i++) + target_buffer_set_u32(target, code_p + (i*4), word_32_code[i]); + } + else + { + return ERROR_FLASH_OPERATION_FAILED; + } + + /* allocate working area */ + retval=target_alloc_working_area(target, 24 * 4, + &cfi_info->write_algorithm); + if (retval != ERROR_OK) + { + return retval; + } + + /* write algorithm code to working area */ + target_write_buffer(target, cfi_info->write_algorithm->address, 24 * 4, code_p); + + free(code_p); + } + + 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 (cfi_info->write_algorithm) + target_free_working_area(target, cfi_info->write_algorithm); + + WARNING("not enough working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + }; + + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); + init_reg_param(®_params[5], "r5", 32, PARAM_IN); + init_reg_param(®_params[6], "r8", 32, PARAM_OUT); + init_reg_param(®_params[7], "r9", 32, PARAM_OUT); + init_reg_param(®_params[8], "r10", 32, PARAM_OUT); + init_reg_param(®_params[9], "r11", 32, PARAM_OUT); + + while (count > 0) + { + u32 thisrun_count = (count > buffer_size) ? buffer_size : count; + + target_write_buffer(target, source->address, thisrun_count, 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 / bank->bus_width); + cfi_command(bank, 0xA0, write_command); + buf_set_u32(reg_params[3].value, 0, 32, buf_get_u32(write_command, 0, 32)); + cfi_command(bank, 0x80, write_command); + buf_set_u32(reg_params[4].value, 0, 32, buf_get_u32(write_command, 0, 32)); + buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock1)); + buf_set_u32(reg_params[7].value, 0, 32, 0xaa); + buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock2)); + buf_set_u32(reg_params[9].value, 0, 32, 0x55); + + retval = target->type->run_algorithm(target, 0, NULL, 10, reg_params, + cfi_info->write_algorithm->address, + cfi_info->write_algorithm->address + ((24 * 4) - 4), + 10000, &armv4_5_info); + + status = buf_get_u32(reg_params[5].value, 0, 32); + + if ((retval != ERROR_OK) || status != 0x80) + { + DEBUG("status: 0x%x", status); + exit_code = ERROR_FLASH_OPERATION_FAILED; + break; + } + + buffer += thisrun_count; + address += thisrun_count; + count -= thisrun_count; + } + + target_free_working_area(target, source); + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + destroy_reg_param(®_params[5]); + destroy_reg_param(®_params[6]); + destroy_reg_param(®_params[7]); + destroy_reg_param(®_params[8]); + destroy_reg_param(®_params[9]); + + return exit_code; +} + +int cfi_intel_write_word(struct flash_bank_s *bank, u8 *word, u32 address) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + target_t *target = bank->target; + u8 command[8]; + + cfi_intel_clear_status_register(bank); + cfi_command(bank, 0x40, command); + target->type->write_memory(target, address, bank->bus_width, 1, command); + + target->type->write_memory(target, address, bank->bus_width, 1, word); + + if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->word_write_timeout_max)) != 0x80) + { + cfi_command(bank, 0xff, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + + ERROR("couldn't write word at base 0x%x, address %x", bank->base, address); + return ERROR_FLASH_OPERATION_FAILED; + } + + return ERROR_OK; +} + +int cfi_intel_write_words(struct flash_bank_s *bank, u8 *word, u32 wordcount, u32 address) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + target_t *target = bank->target; + u8 command[8]; + + /* Calculate buffer size and boundary mask */ + u32 buffersize = 1UL << cfi_info->max_buf_write_size; + u32 buffermask = buffersize-1; + u32 bufferwsize; + + /* Check for valid range */ + if (address & buffermask) + { + ERROR("Write address at base 0x%x, address %x not aligned to 2^%d boundary", bank->base, address, cfi_info->max_buf_write_size); + return ERROR_FLASH_OPERATION_FAILED; + } + switch(bank->chip_width) + { + case 4 : bufferwsize = buffersize / 4; break; + case 2 : bufferwsize = buffersize / 2; break; + case 1 : bufferwsize = buffersize; break; + default: + ERROR("Unsupported chip width %d", bank->chip_width); + return ERROR_FLASH_OPERATION_FAILED; + } + + /* Check for valid size */ + if (wordcount > bufferwsize) + { + ERROR("Number of data words %d exceeds available buffersize %d", wordcount, buffersize); + return ERROR_FLASH_OPERATION_FAILED; + } + + /* Write to flash buffer */ + cfi_intel_clear_status_register(bank); + + /* Initiate buffer operation _*/ + cfi_command(bank, 0xE8, command); + target->type->write_memory(target, address, bank->bus_width, 1, command); + if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->buf_write_timeout_max)) != 0x80) + { + cfi_command(bank, 0xff, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + + ERROR("couldn't start buffer write operation at base 0x%x, address %x", bank->base, address); + return ERROR_FLASH_OPERATION_FAILED; + } + + /* Write buffer wordcount-1 and data words */ + cfi_command(bank, bufferwsize-1, command); + target->type->write_memory(target, address, bank->bus_width, 1, command); + + target->type->write_memory(target, address, bank->bus_width, bufferwsize, word); + + /* Commit write operation */ + cfi_command(bank, 0xd0, command); + target->type->write_memory(target, address, bank->bus_width, 1, command); + if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->buf_write_timeout_max)) != 0x80) + { + cfi_command(bank, 0xff, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + + ERROR("Buffer write at base 0x%x, address %x failed.", bank->base, address); + return ERROR_FLASH_OPERATION_FAILED; + } + + return ERROR_OK; +} + +int cfi_spansion_write_word(struct flash_bank_s *bank, u8 *word, u32 address) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext; + target_t *target = bank->target; + u8 command[8]; + + cfi_command(bank, 0xaa, command); + target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); + + cfi_command(bank, 0x55, command); + target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command); + + cfi_command(bank, 0xa0, command); + target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); + + target->type->write_memory(target, address, bank->bus_width, 1, word); + + if (cfi_spansion_wait_status_busy(bank, 1000 * (1 << cfi_info->word_write_timeout_max)) != ERROR_OK) + { + cfi_command(bank, 0xf0, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + + ERROR("couldn't write word at base 0x%x, address %x", bank->base, address); + return ERROR_FLASH_OPERATION_FAILED; + } + + return ERROR_OK; +} + +int cfi_write_word(struct flash_bank_s *bank, u8 *word, u32 address) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + + switch(cfi_info->pri_id) + { + case 1: + case 3: + return cfi_intel_write_word(bank, word, address); + break; + case 2: + return cfi_spansion_write_word(bank, word, address); + break; + default: + ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; + } + + return ERROR_FLASH_OPERATION_FAILED; +} + +int cfi_write_words(struct flash_bank_s *bank, u8 *word, u32 wordcount, u32 address) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + + switch(cfi_info->pri_id) + { + case 1: + case 3: + return cfi_intel_write_words(bank, word, wordcount, address); + break; + case 2: + //return cfi_spansion_write_words(bank, word, address); + ERROR("cfi primary command set %i unimplemented - FIXME", cfi_info->pri_id); + break; + default: + ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; + } + + return ERROR_FLASH_OPERATION_FAILED; +} + +int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + target_t *target = bank->target; + u32 address = bank->base + offset; /* address of first byte to be programmed */ + u32 write_p, copy_p; + int align; /* number of unaligned bytes */ + int blk_count; /* number of bus_width bytes for block copy */ + u8 current_word[CFI_MAX_BUS_WIDTH * 4]; /* word (bus_width size) currently being programmed */ + int i; + int retval; + + if (offset + count > bank->size) + return ERROR_FLASH_DST_OUT_OF_BANK; + + if (cfi_info->qry[0] != 'Q') + return ERROR_FLASH_BANK_NOT_PROBED; + + /* start at the first byte of the first word (bus_width size) */ + write_p = address & ~(bank->bus_width - 1); + if ((align = address - write_p) != 0) + { + INFO("Fixup %d unaligned head bytes", align ); + + for (i = 0; i < bank->bus_width; i++) + current_word[i] = 0; + copy_p = write_p; + + /* copy bytes before the first write address */ + for (i = 0; i < align; ++i, ++copy_p) + { + u8 byte; + target->type->read_memory(target, copy_p, 1, 1, &byte); + cfi_add_byte(bank, current_word, byte); + } + + /* add bytes from the buffer */ + for (; (i < bank->bus_width) && (count > 0); i++) + { + cfi_add_byte(bank, current_word, *buffer++); + count--; + copy_p++; + } + + /* if the buffer is already finished, copy bytes after the last write address */ + for (; (count == 0) && (i < bank->bus_width); ++i, ++copy_p) + { + u8 byte; + target->type->read_memory(target, copy_p, 1, 1, &byte); + cfi_add_byte(bank, current_word, byte); + } + + retval = cfi_write_word(bank, current_word, write_p); + if (retval != ERROR_OK) + return retval; + write_p = copy_p; + } + + /* handle blocks of bus_size aligned bytes */ + blk_count = count & ~(bank->bus_width - 1); /* round down, leave tail bytes */ + switch(cfi_info->pri_id) + { + /* try block writes (fails without working area) */ + case 1: + case 3: + retval = cfi_intel_write_block(bank, buffer, write_p, blk_count); + break; + case 2: + retval = cfi_spansion_write_block(bank, buffer, write_p, blk_count); + break; + default: + ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + retval = ERROR_FLASH_OPERATION_FAILED; + break; + } + if (retval == ERROR_OK) + { + /* Increment pointers and decrease count on succesful block write */ + buffer += blk_count; + write_p += blk_count; + count -= blk_count; + } + else + { + if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + { + u32 buffersize = 1UL << cfi_info->max_buf_write_size; + u32 buffermask = buffersize-1; + u32 bufferwsize; + + switch(bank->chip_width) + { + case 4 : bufferwsize = buffersize / 4; break; + case 2 : bufferwsize = buffersize / 2; break; + case 1 : bufferwsize = buffersize; break; + default: + ERROR("Unsupported chip width %d", bank->chip_width); + return ERROR_FLASH_OPERATION_FAILED; + } + + /* fall back to memory writes */ + while (count > bank->bus_width) + { + if ((write_p & 0xff) == 0) + { + INFO("Programming at %08x, count %08x bytes remaining", write_p, count); + } +#if 0 + /* NB! this is broken for spansion! */ + if ((count > bufferwsize) && !(write_p & buffermask)) + { + retval = cfi_write_words(bank, buffer, bufferwsize, write_p); + if (retval != ERROR_OK) + return retval; + + buffer += buffersize; + write_p += buffersize; + count -= buffersize; + } + else +#endif + { + for (i = 0; i < bank->bus_width; i++) + current_word[i] = 0; + + for (i = 0; i < bank->bus_width; i++) + { + cfi_add_byte(bank, current_word, *buffer++); + } + + retval = cfi_write_word(bank, current_word, write_p); + if (retval != ERROR_OK) + return retval; + + write_p += bank->bus_width; + count -= bank->bus_width; + } + } + } + else + return retval; + } + + /* return to read array mode, so we can read from flash again for padding */ + cfi_command(bank, 0xf0, current_word); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word); + cfi_command(bank, 0xff, current_word); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word); + + /* handle unaligned tail bytes */ + if (count > 0) + { + INFO("Fixup %d unaligned tail bytes", count ); + + copy_p = write_p; + for (i = 0; i < bank->bus_width; i++) + current_word[i] = 0; + + for (i = 0; (i < bank->bus_width) && (count > 0); ++i, ++copy_p) + { + cfi_add_byte(bank, current_word, *buffer++); + count--; + } + for (; i < bank->bus_width; ++i, ++copy_p) + { + u8 byte; + target->type->read_memory(target, copy_p, 1, 1, &byte); + cfi_add_byte(bank, current_word, byte); + } + retval = cfi_write_word(bank, current_word, write_p); + if (retval != ERROR_OK) + return retval; + } + + /* return to read array mode */ + cfi_command(bank, 0xf0, current_word); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word); + cfi_command(bank, 0xff, current_word); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word); + + return ERROR_OK; +} + +void cfi_fixup_atmel_reversed_erase_regions(flash_bank_t *bank, void *param) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext; + + pri_ext->_reversed_geometry = 1; +} + +void cfi_fixup_0002_erase_regions(flash_bank_t *bank, void *param) +{ + int i; + cfi_flash_bank_t *cfi_info = bank->driver_priv; + cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext; + + if ((pri_ext->_reversed_geometry) || (pri_ext->TopBottom == 3)) + { + DEBUG("swapping reversed erase region information on cmdset 0002 device"); + + for (i = 0; i < cfi_info->num_erase_regions / 2; i++) + { + int j = (cfi_info->num_erase_regions - 1) - i; + u32 swap; + + swap = cfi_info->erase_region_info[i]; + cfi_info->erase_region_info[i] = cfi_info->erase_region_info[j]; + cfi_info->erase_region_info[j] = swap; + } + } +} + +void cfi_fixup_0002_unlock_addresses(flash_bank_t *bank, void *param) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext; + cfi_unlock_addresses_t *unlock_addresses = param; + + pri_ext->_unlock1 = unlock_addresses->unlock1; + pri_ext->_unlock2 = unlock_addresses->unlock2; +} + +int cfi_probe(struct flash_bank_s *bank) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + target_t *target = bank->target; + u8 command[8]; + int num_sectors = 0; + int i; + int sector = 0; + u32 offset = 0; + u32 unlock1 = 0x555; + u32 unlock2 = 0x2aa; + + cfi_info->probed = 0; + + /* JEDEC standard JESD21C uses 0x5555 and 0x2aaa as unlock addresses, + * while CFI compatible AMD/Spansion flashes use 0x555 and 0x2aa + */ + if (cfi_info->jedec_probe) + { + unlock1 = 0x5555; + unlock2 = 0x2aaa; + } + + /* switch to read identifier codes mode ("AUTOSELECT") */ + cfi_command(bank, 0xaa, command); + target->type->write_memory(target, flash_address(bank, 0, unlock1), bank->bus_width, 1, command); + cfi_command(bank, 0x55, command); + target->type->write_memory(target, flash_address(bank, 0, unlock2), bank->bus_width, 1, command); + cfi_command(bank, 0x90, command); + target->type->write_memory(target, flash_address(bank, 0, unlock1), bank->bus_width, 1, command); + + if (bank->chip_width == 1) + { + u8 manufacturer, device_id; + target_read_u8(target, bank->base + 0x0, &manufacturer); + target_read_u8(target, bank->base + 0x1, &device_id); + cfi_info->manufacturer = manufacturer; + cfi_info->device_id = device_id; + } + else if (bank->chip_width == 2) + { + target_read_u16(target, bank->base + 0x0, &cfi_info->manufacturer); + target_read_u16(target, bank->base + 0x2, &cfi_info->device_id); + } + + /* switch back to read array mode */ + cfi_command(bank, 0xf0, command); + target->type->write_memory(target, flash_address(bank, 0, 0x00), bank->bus_width, 1, command); + cfi_command(bank, 0xff, command); + target->type->write_memory(target, flash_address(bank, 0, 0x00), bank->bus_width, 1, command); + + cfi_fixup(bank, cfi_jedec_fixups); + + /* query only if this is a CFI compatible flash, + * otherwise the relevant info has already been filled in + */ + if (cfi_info->not_cfi == 0) + { + /* enter CFI query mode + * according to JEDEC Standard No. 68.01, + * a single bus sequence with address = 0x55, data = 0x98 should put + * the device into CFI query mode. + * + * SST flashes clearly violate this, and we will consider them incompatbile for now + */ + cfi_command(bank, 0x98, command); + target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command); + + cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10); + 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); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + cfi_command(bank, 0xff, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + return ERROR_FLASH_BANK_INVALID; + } + + cfi_info->pri_id = cfi_query_u16(bank, 0, 0x13); + cfi_info->pri_addr = cfi_query_u16(bank, 0, 0x15); + cfi_info->alt_id = cfi_query_u16(bank, 0, 0x17); + cfi_info->alt_addr = cfi_query_u16(bank, 0, 0x19); + + DEBUG("qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr); + + cfi_info->vcc_min = cfi_query_u8(bank, 0, 0x1b); + cfi_info->vcc_max = cfi_query_u8(bank, 0, 0x1c); + cfi_info->vpp_min = cfi_query_u8(bank, 0, 0x1d); + cfi_info->vpp_max = cfi_query_u8(bank, 0, 0x1e); + cfi_info->word_write_timeout_typ = cfi_query_u8(bank, 0, 0x1f); + cfi_info->buf_write_timeout_typ = cfi_query_u8(bank, 0, 0x20); + cfi_info->block_erase_timeout_typ = cfi_query_u8(bank, 0, 0x21); + cfi_info->chip_erase_timeout_typ = cfi_query_u8(bank, 0, 0x22); + cfi_info->word_write_timeout_max = cfi_query_u8(bank, 0, 0x23); + cfi_info->buf_write_timeout_max = cfi_query_u8(bank, 0, 0x24); + cfi_info->block_erase_timeout_max = cfi_query_u8(bank, 0, 0x25); + cfi_info->chip_erase_timeout_max = cfi_query_u8(bank, 0, 0x26); + + DEBUG("Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x", + (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f, + (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f, + (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f, + (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f); + DEBUG("typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ, + 1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ); + DEBUG("max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ), + (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ), + (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ), + (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ)); + + cfi_info->dev_size = cfi_query_u8(bank, 0, 0x27); + cfi_info->interface_desc = cfi_query_u16(bank, 0, 0x28); + cfi_info->max_buf_write_size = cfi_query_u16(bank, 0, 0x2a); + cfi_info->num_erase_regions = cfi_query_u8(bank, 0, 0x2c); + + DEBUG("size: 0x%x, interface desc: %i, max buffer write size: %x", 1 << cfi_info->dev_size, cfi_info->interface_desc, (1 << cfi_info->max_buf_write_size)); + + if (((1 << cfi_info->dev_size) * bank->bus_width / bank->chip_width) != bank->size) + { + WARNING("configuration specifies 0x%x size, but a 0x%x size flash was found", bank->size, 1 << cfi_info->dev_size); + } + + if (cfi_info->num_erase_regions) + { + cfi_info->erase_region_info = malloc(4 * cfi_info->num_erase_regions); + for (i = 0; i < cfi_info->num_erase_regions; i++) + { + cfi_info->erase_region_info[i] = cfi_query_u32(bank, 0, 0x2d + (4 * i)); + DEBUG("erase region[%i]: %i blocks of size 0x%x", i, (cfi_info->erase_region_info[i] & 0xffff) + 1, (cfi_info->erase_region_info[i] >> 16) * 256); + } + } + else + { + cfi_info->erase_region_info = NULL; + } + + /* We need to read the primary algorithm extended query table before calculating + * the sector layout to be able to apply fixups + */ + switch(cfi_info->pri_id) + { + /* Intel command set (standard and extended) */ + case 0x0001: + case 0x0003: + cfi_read_intel_pri_ext(bank); + break; + /* AMD/Spansion, Atmel, ... command set */ + case 0x0002: + cfi_read_0002_pri_ext(bank); + break; + default: + ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; + } + + /* return to read array mode + * we use both reset commands, as some Intel flashes fail to recognize the 0xF0 command + */ + cfi_command(bank, 0xf0, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + cfi_command(bank, 0xff, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + } + + /* apply fixups depending on the primary command set */ + switch(cfi_info->pri_id) + { + /* Intel command set (standard and extended) */ + case 0x0001: + case 0x0003: + cfi_fixup(bank, cfi_0001_fixups); + break; + /* AMD/Spansion, Atmel, ... command set */ + case 0x0002: + cfi_fixup(bank, cfi_0002_fixups); + break; + default: + ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; + } + + if (cfi_info->num_erase_regions == 0) + { + /* a device might have only one erase block, spanning the whole device */ + bank->num_sectors = 1; + bank->sectors = malloc(sizeof(flash_sector_t)); + + bank->sectors[sector].offset = 0x0; + bank->sectors[sector].size = bank->size; + bank->sectors[sector].is_erased = -1; + bank->sectors[sector].is_protected = -1; + } + else + { + for (i = 0; i < cfi_info->num_erase_regions; i++) + { + num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1; + } + + bank->num_sectors = num_sectors; + bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors); + + for (i = 0; i < cfi_info->num_erase_regions; i++) + { + int j; + for (j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++) + { + bank->sectors[sector].offset = offset; + bank->sectors[sector].size = ((cfi_info->erase_region_info[i] >> 16) * 256) * bank->bus_width / bank->chip_width; + offset += bank->sectors[sector].size; + bank->sectors[sector].is_erased = -1; + bank->sectors[sector].is_protected = -1; + sector++; + } + } + } + + cfi_info->probed = 1; + + return ERROR_OK; +} + +int cfi_auto_probe(struct flash_bank_s *bank) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + if (cfi_info->probed) + return ERROR_OK; + return cfi_probe(bank); +} + +int cfi_erase_check(struct flash_bank_s *bank) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + target_t *target = bank->target; + int i; + int retval; + + if (!cfi_info->erase_check_algorithm) + { + u32 erase_check_code[] = + { + 0xe4d03001, /* ldrb r3, [r0], #1 */ + 0xe0022003, /* and r2, r2, r3 */ + 0xe2511001, /* subs r1, r1, #1 */ + 0x1afffffb, /* b -4 */ + 0xeafffffe /* b 0 */ + }; + + /* make sure we have a working area */ + if (target_alloc_working_area(target, 20, &cfi_info->erase_check_algorithm) != ERROR_OK) + { + WARNING("no working area available, falling back to slow memory reads"); + } + else + { + u8 erase_check_code_buf[5 * 4]; + + for (i = 0; i < 5; i++) + target_buffer_set_u32(target, erase_check_code_buf + (i*4), erase_check_code[i]); + + /* write algorithm code to working area */ + target->type->write_memory(target, cfi_info->erase_check_algorithm->address, 4, 5, erase_check_code_buf); + } + } + + if (!cfi_info->erase_check_algorithm) + { + u32 *buffer = malloc(4096); + + for (i = 0; i < bank->num_sectors; i++) + { + u32 address = bank->base + bank->sectors[i].offset; + u32 size = bank->sectors[i].size; + u32 check = 0xffffffffU; + int erased = 1; + + while (size > 0) + { + u32 thisrun_size = (size > 4096) ? 4096 : size; + int j; + + target->type->read_memory(target, address, 4, thisrun_size / 4, (u8*)buffer); + + for (j = 0; j < thisrun_size / 4; j++) + check &= buffer[j]; + + if (check != 0xffffffff) + { + erased = 0; + break; + } + + size -= thisrun_size; + address += thisrun_size; + } + + bank->sectors[i].is_erased = erased; + } + + free(buffer); + } + else + { + for (i = 0; i < bank->num_sectors; i++) + { + u32 address = bank->base + bank->sectors[i].offset; + u32 size = bank->sectors[i].size; + + reg_param_t reg_params[3]; + armv4_5_algorithm_t armv4_5_info; + + armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC; + armv4_5_info.core_mode = ARMV4_5_MODE_SVC; + armv4_5_info.core_state = ARMV4_5_STATE_ARM; + + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); + buf_set_u32(reg_params[0].value, 0, 32, address); + + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); + buf_set_u32(reg_params[1].value, 0, 32, size); + + init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); + buf_set_u32(reg_params[2].value, 0, 32, 0xff); + + if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params, cfi_info->erase_check_algorithm->address, cfi_info->erase_check_algorithm->address + 0x10, 10000, &armv4_5_info)) != ERROR_OK) + return ERROR_FLASH_OPERATION_FAILED; + + if (buf_get_u32(reg_params[2].value, 0, 32) == 0xff) + bank->sectors[i].is_erased = 1; + else + bank->sectors[i].is_erased = 0; + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + } + } + + return ERROR_OK; +} + +int cfi_intel_protect_check(struct flash_bank_s *bank) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext; + target_t *target = bank->target; + u8 command[CFI_MAX_BUS_WIDTH]; + int i; + + /* check if block lock bits are supported on this device */ + if (!(pri_ext->blk_status_reg_mask & 0x1)) + return ERROR_FLASH_OPERATION_FAILED; + + cfi_command(bank, 0x90, command); + target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command); + + for (i = 0; i < bank->num_sectors; i++) + { + u8 block_status = cfi_get_u8(bank, i, 0x2); + + if (block_status & 1) + bank->sectors[i].is_protected = 1; + else + bank->sectors[i].is_protected = 0; + } + + cfi_command(bank, 0xff, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + + return ERROR_OK; +} + +int cfi_spansion_protect_check(struct flash_bank_s *bank) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext; + target_t *target = bank->target; + u8 command[8]; + int i; + + cfi_command(bank, 0xaa, command); + target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); + + cfi_command(bank, 0x55, command); + target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command); + + cfi_command(bank, 0x90, command); + target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); + + for (i = 0; i < bank->num_sectors; i++) + { + u8 block_status = cfi_get_u8(bank, i, 0x2); + + if (block_status & 1) + bank->sectors[i].is_protected = 1; + else + bank->sectors[i].is_protected = 0; + } + + cfi_command(bank, 0xf0, command); + target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); + + return ERROR_OK; +} + +int cfi_protect_check(struct flash_bank_s *bank) +{ + cfi_flash_bank_t *cfi_info = bank->driver_priv; + + if (cfi_info->qry[0] != 'Q') + return ERROR_FLASH_BANK_NOT_PROBED; + + switch(cfi_info->pri_id) + { + case 1: + case 3: + return cfi_intel_protect_check(bank); + break; + case 2: + return cfi_spansion_protect_check(bank); + break; + default: + ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; + } + + return ERROR_OK; +} + +int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size) +{ + int printed; + cfi_flash_bank_t *cfi_info = bank->driver_priv; + + if (cfi_info->qry[0] == (char)-1) + { + printed = snprintf(buf, buf_size, "\ncfi flash bank not probed yet\n"); + return ERROR_OK; + } + + printed = snprintf(buf, buf_size, "\ncfi information:\n"); + buf += printed; + buf_size -= printed; + + printed = snprintf(buf, buf_size, "\nmfr: 0x%4.4x, id:0x%4.4x\n", + cfi_info->manufacturer, cfi_info->device_id); + buf += printed; + buf_size -= printed; + + printed = snprintf(buf, buf_size, "qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x\n", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr); + buf += printed; + buf_size -= printed; + + printed = snprintf(buf, buf_size, "Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x\n", (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f, + (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f, + (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f, + (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f); + buf += printed; + buf_size -= printed; + + printed = snprintf(buf, buf_size, "typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u\n", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ, + 1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ); + buf += printed; + buf_size -= printed; + + printed = snprintf(buf, buf_size, "max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u\n", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ), + (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ), + (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ), + (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ)); + buf += printed; + buf_size -= printed; + + printed = snprintf(buf, buf_size, "size: 0x%x, interface desc: %i, max buffer write size: %x\n", 1 << cfi_info->dev_size, cfi_info->interface_desc, cfi_info->max_buf_write_size); + buf += printed; + buf_size -= printed; + + switch(cfi_info->pri_id) + { + case 1: + case 3: + cfi_intel_info(bank, buf, buf_size); + break; + case 2: + cfi_spansion_info(bank, buf, buf_size); + break; + default: + ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; + } + + return ERROR_OK; +} diff --git a/src/flash/s3c2440_nand.c b/src/flash/s3c2440_nand.c index 1390a3f..4e3234f 100644 --- a/src/flash/s3c2440_nand.c +++ b/src/flash/s3c2440_nand.c @@ -1,179 +1,179 @@ -/* src/flash/s3c2440_nand.c
- *
- * S3C2440 OpenOCD NAND Flash controller support.
- *
- * Copyright 2007,2008 Ben Dooks <ben@fluff.org>
- *
- * 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.
- *
- * Many thanks to Simtec Electronics for sponsoring this work.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "replacements.h"
-#include "log.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "nand.h"
-#include "s3c24xx_nand.h"
-#include "target.h"
-
-int s3c2440_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
-int s3c2440_init(struct nand_device_s *device);
-int s3c2440_nand_ready(struct nand_device_s *device, int timeout);
-
-nand_flash_controller_t s3c2440_nand_controller =
-{
- .name = "s3c2440",
- .nand_device_command = s3c2440_nand_device_command,
- .register_commands = s3c24xx_register_commands,
- .init = s3c2440_init,
- .reset = s3c24xx_reset,
- .command = s3c24xx_command,
- .address = s3c24xx_address,
- .write_data = s3c24xx_write_data,
- .read_data = s3c24xx_read_data,
- .write_page = s3c24xx_write_page,
- .read_page = s3c24xx_read_page,
- .write_block_data = s3c2440_write_block_data,
- .read_block_data = s3c2440_read_block_data,
- .controller_ready = s3c24xx_controller_ready,
- .nand_ready = s3c2440_nand_ready,
-};
-
-int s3c2440_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
- char **args, int argc,
- struct nand_device_s *device)
-{
- s3c24xx_nand_controller_t *info;
-
- info = s3c24xx_nand_device_command(cmd_ctx, cmd, args, argc, device);
- if (info == NULL) {
- return ERROR_NAND_DEVICE_INVALID;
- }
-
- /* fill in the address fields for the core device */
- info->cmd = S3C2440_NFCMD;
- info->addr = S3C2440_NFADDR;
- info->data = S3C2440_NFDATA;
- info->nfstat = S3C2440_NFSTAT;
-
- return ERROR_OK;
-}
-
-int s3c2440_init(struct nand_device_s *device)
-{
- s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
- target_t *target = s3c24xx_info->target;
- u32 version;
-
- target_write_u32(target, S3C2410_NFCONF,
- S3C2440_NFCONF_TACLS(3) |
- S3C2440_NFCONF_TWRPH0(7) |
- S3C2440_NFCONF_TWRPH1(7));
-
- target_write_u32(target, S3C2440_NFCONT,
- S3C2440_NFCONT_INITECC | S3C2440_NFCONT_ENABLE);
-
- return ERROR_OK;
-}
-
-int s3c2440_nand_ready(struct nand_device_s *device, int timeout)
-{
- s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
- target_t *target = s3c24xx_info->target;
- u8 status;
-
- if (target->state != TARGET_HALTED) {
- ERROR("target must be halted to use S3C24XX NAND flash controller");
- return ERROR_NAND_OPERATION_FAILED;
- }
-
- do {
- target_read_u8(target, s3c24xx_info->nfstat, &status);
-
- if (status & S3C2440_NFSTAT_READY)
- return 1;
-
- usleep(1000);
- } while (timeout-- > 0);
-
-
- return 0;
-}
-
-/* use the fact we can read/write 4 bytes in one go via a single 32bit op */
-
-int s3c2440_read_block_data(struct nand_device_s *device, u8 *data, int data_size)
-{
- s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
- target_t *target = s3c24xx_info->target;
- u32 nfdata = s3c24xx_info->data;
- u32 tmp;
-
- INFO("%s: reading data: %p, %p, %d\n", __func__, device, data, data_size);
-
- if (target->state != TARGET_HALTED) {
- ERROR("target must be halted to use S3C24XX NAND flash controller");
- return ERROR_NAND_OPERATION_FAILED;
- }
-
- while (data_size >= 4) {
- target_read_u32(target, nfdata, &tmp);
-
- data[0] = tmp;
- data[1] = tmp >> 8;
- data[2] = tmp >> 16;
- data[3] = tmp >> 24;
-
- data_size -= 4;
- data += 4;
- }
-
- while (data_size > 0) {
- target_read_u8(target, nfdata, data);
-
- data_size -= 1;
- data += 1;
- }
-
- return ERROR_OK;
-}
-
-int s3c2440_write_block_data(struct nand_device_s *device, u8 *data, int data_size)
-{
- s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
- target_t *target = s3c24xx_info->target;
- u32 nfdata = s3c24xx_info->data;
- u32 tmp;
-
- if (target->state != TARGET_HALTED) {
- ERROR("target must be halted to use S3C24XX NAND flash controller");
- return ERROR_NAND_OPERATION_FAILED;
- }
-
- while (data_size >= 4) {
- tmp = le_to_h_u32(data);
- target_write_u32(target, nfdata, tmp);
-
- data_size -= 4;
- data += 4;
- }
-
- while (data_size > 0) {
- target_write_u8(target, nfdata, *data);
-
- data_size -= 1;
- data += 1;
- }
-
- return ERROR_OK;
-}
+/* src/flash/s3c2440_nand.c + * + * S3C2440 OpenOCD NAND Flash controller support. + * + * Copyright 2007,2008 Ben Dooks <ben@fluff.org> + * + * 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. + * + * Many thanks to Simtec Electronics for sponsoring this work. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "replacements.h" +#include "log.h" + +#include <stdlib.h> +#include <string.h> + +#include "nand.h" +#include "s3c24xx_nand.h" +#include "target.h" + +int s3c2440_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device); +int s3c2440_init(struct nand_device_s *device); +int s3c2440_nand_ready(struct nand_device_s *device, int timeout); + +nand_flash_controller_t s3c2440_nand_controller = +{ + .name = "s3c2440", + .nand_device_command = s3c2440_nand_device_command, + .register_commands = s3c24xx_register_commands, + .init = s3c2440_init, + .reset = s3c24xx_reset, + .command = s3c24xx_command, + .address = s3c24xx_address, + .write_data = s3c24xx_write_data, + .read_data = s3c24xx_read_data, + .write_page = s3c24xx_write_page, + .read_page = s3c24xx_read_page, + .write_block_data = s3c2440_write_block_data, + .read_block_data = s3c2440_read_block_data, + .controller_ready = s3c24xx_controller_ready, + .nand_ready = s3c2440_nand_ready, +}; + +int s3c2440_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, + char **args, int argc, + struct nand_device_s *device) +{ + s3c24xx_nand_controller_t *info; + + info = s3c24xx_nand_device_command(cmd_ctx, cmd, args, argc, device); + if (info == NULL) { + return ERROR_NAND_DEVICE_INVALID; + } + + /* fill in the address fields for the core device */ + info->cmd = S3C2440_NFCMD; + info->addr = S3C2440_NFADDR; + info->data = S3C2440_NFDATA; + info->nfstat = S3C2440_NFSTAT; + + return ERROR_OK; +} + +int s3c2440_init(struct nand_device_s *device) +{ + s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv; + target_t *target = s3c24xx_info->target; + u32 version; + + target_write_u32(target, S3C2410_NFCONF, + S3C2440_NFCONF_TACLS(3) | + S3C2440_NFCONF_TWRPH0(7) | + S3C2440_NFCONF_TWRPH1(7)); + + target_write_u32(target, S3C2440_NFCONT, + S3C2440_NFCONT_INITECC | S3C2440_NFCONT_ENABLE); + + return ERROR_OK; +} + +int s3c2440_nand_ready(struct nand_device_s *device, int timeout) +{ + s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv; + target_t *target = s3c24xx_info->target; + u8 status; + + if (target->state != TARGET_HALTED) { + ERROR("target must be halted to use S3C24XX NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + do { + target_read_u8(target, s3c24xx_info->nfstat, &status); + + if (status & S3C2440_NFSTAT_READY) + return 1; + + usleep(1000); + } while (timeout-- > 0); + + + return 0; +} + +/* use the fact we can read/write 4 bytes in one go via a single 32bit op */ + +int s3c2440_read_block_data(struct nand_device_s *device, u8 *data, int data_size) +{ + s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv; + target_t *target = s3c24xx_info->target; + u32 nfdata = s3c24xx_info->data; + u32 tmp; + + INFO("%s: reading data: %p, %p, %d\n", __func__, device, data, data_size); + + if (target->state != TARGET_HALTED) { + ERROR("target must be halted to use S3C24XX NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + while (data_size >= 4) { + target_read_u32(target, nfdata, &tmp); + + data[0] = tmp; + data[1] = tmp >> 8; + data[2] = tmp >> 16; + data[3] = tmp >> 24; + + data_size -= 4; + data += 4; + } + + while (data_size > 0) { + target_read_u8(target, nfdata, data); + + data_size -= 1; + data += 1; + } + + return ERROR_OK; +} + +int s3c2440_write_block_data(struct nand_device_s *device, u8 *data, int data_size) +{ + s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv; + target_t *target = s3c24xx_info->target; + u32 nfdata = s3c24xx_info->data; + u32 tmp; + + if (target->state != TARGET_HALTED) { + ERROR("target must be halted to use S3C24XX NAND flash controller"); + return ERROR_NAND_OPERATION_FAILED; + } + + while (data_size >= 4) { + tmp = le_to_h_u32(data); + target_write_u32(target, nfdata, tmp); + + data_size -= 4; + data += 4; + } + + while (data_size > 0) { + target_write_u8(target, nfdata, *data); + + data_size -= 1; + data += 1; + } + + return ERROR_OK; +} diff --git a/src/flash/str9xpec.c b/src/flash/str9xpec.c index 9df57dd..ea7aa97 100644 --- a/src/flash/str9xpec.c +++ b/src/flash/str9xpec.c @@ -1,1348 +1,1348 @@ -/***************************************************************************
- * 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 "str9xpec.h"
-#include "flash.h"
-#include "target.h"
-#include "log.h"
-#include "armv4_5.h"
-#include "arm7_9_common.h"
-#include "jtag.h"
-#include "binarybuffer.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-
-str9xpec_mem_layout_t mem_layout_str9pec[] = {
- {0x00000000, 0x10000, 0},
- {0x00010000, 0x10000, 1},
- {0x00020000, 0x10000, 2},
- {0x00030000, 0x10000, 3},
- {0x00040000, 0x10000, 4},
- {0x00050000, 0x10000, 5},
- {0x00060000, 0x10000, 6},
- {0x00070000, 0x10000, 7},
- {0x00080000, 0x02000, 32},
- {0x00082000, 0x02000, 33},
- {0x00084000, 0x02000, 34},
- {0x00086000, 0x02000, 35}
-};
-
-int str9xpec_register_commands(struct command_context_s *cmd_ctx);
-int str9xpec_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
-int str9xpec_erase(struct flash_bank_s *bank, int first, int last);
-int str9xpec_protect(struct flash_bank_s *bank, int set, int first, int last);
-int str9xpec_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
-int str9xpec_probe(struct flash_bank_s *bank);
-int str9xpec_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_protect_check(struct flash_bank_s *bank);
-int str9xpec_erase_check(struct flash_bank_s *bank);
-int str9xpec_info(struct flash_bank_s *bank, char *buf, int buf_size);
-
-int str9xpec_erase_area(struct flash_bank_s *bank, int first, int last);
-int str9xpec_set_address(struct flash_bank_s *bank, u8 sector);
-int str9xpec_write_options(struct flash_bank_s *bank);
-
-int str9xpec_handle_flash_options_cmap_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_options_lvdthd_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_options_lvdsel_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_options_lvdwarn_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_enable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int str9xpec_handle_flash_disable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-flash_driver_t str9xpec_flash =
-{
- .name = "str9xpec",
- .register_commands = str9xpec_register_commands,
- .flash_bank_command = str9xpec_flash_bank_command,
- .erase = str9xpec_erase,
- .protect = str9xpec_protect,
- .write = str9xpec_write,
- .probe = str9xpec_probe,
- .auto_probe = str9xpec_probe,
- .erase_check = str9xpec_erase_check,
- .protect_check = str9xpec_protect_check,
- .info = str9xpec_info
-};
-
-int str9xpec_register_commands(struct command_context_s *cmd_ctx)
-{
- command_t *str9xpec_cmd = register_command(cmd_ctx, NULL, "str9xpec", NULL, COMMAND_ANY, "str9xpec flash specific commands");
-
- register_command(cmd_ctx, str9xpec_cmd, "enable_turbo", str9xpec_handle_flash_enable_turbo_command, COMMAND_EXEC,
- "enable str9xpec turbo mode");
- register_command(cmd_ctx, str9xpec_cmd, "disable_turbo", str9xpec_handle_flash_disable_turbo_command, COMMAND_EXEC,
- "disable str9xpec turbo mode");
- register_command(cmd_ctx, str9xpec_cmd, "options_cmap", str9xpec_handle_flash_options_cmap_command, COMMAND_EXEC,
- "configure str9xpec boot sector");
- register_command(cmd_ctx, str9xpec_cmd, "options_lvdthd", str9xpec_handle_flash_options_lvdthd_command, COMMAND_EXEC,
- "configure str9xpec lvd threshold");
- register_command(cmd_ctx, str9xpec_cmd, "options_lvdsel", str9xpec_handle_flash_options_lvdsel_command, COMMAND_EXEC,
- "configure str9xpec lvd selection");
- register_command(cmd_ctx, str9xpec_cmd, "options_lvdwarn", str9xpec_handle_flash_options_lvdwarn_command, COMMAND_EXEC,
- "configure str9xpec lvd warning");
- register_command(cmd_ctx, str9xpec_cmd, "options_read", str9xpec_handle_flash_options_read_command, COMMAND_EXEC,
- "read str9xpec options");
- register_command(cmd_ctx, str9xpec_cmd, "options_write", str9xpec_handle_flash_options_write_command, COMMAND_EXEC,
- "write str9xpec options");
- register_command(cmd_ctx, str9xpec_cmd, "lock", str9xpec_handle_flash_lock_command, COMMAND_EXEC,
- "lock str9xpec device");
- register_command(cmd_ctx, str9xpec_cmd, "unlock", str9xpec_handle_flash_unlock_command, COMMAND_EXEC,
- "unlock str9xpec device");
- register_command(cmd_ctx, str9xpec_cmd, "part_id", str9xpec_handle_part_id_command, COMMAND_EXEC,
- "print part id of str9xpec flash bank <num>");
-
- return ERROR_OK;
-}
-
-int str9xpec_set_instr(int chain_pos, u32 new_instr, enum tap_state end_state)
-{
- jtag_device_t *device = jtag_get_device(chain_pos);
-
- if (device == NULL)
- {
- DEBUG("Invalid Target");
- return ERROR_TARGET_INVALID;
- }
-
- if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr)
- {
- scan_field_t field;
-
- field.device = chain_pos;
- field.num_bits = device->ir_length;
- field.out_value = calloc(CEIL(field.num_bits, 8), 1);
- buf_set_u32(field.out_value, 0, field.num_bits, new_instr);
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_ir_scan(1, &field, end_state);
-
- free(field.out_value);
- }
-
- return ERROR_OK;
-}
-
-u8 str9xpec_isc_status(int chain_pos)
-{
- scan_field_t field;
- u8 status;
-
- if (str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI) != ERROR_OK)
- return ISC_STATUS_ERROR;
-
- field.device = chain_pos;
- field.num_bits = 8;
- field.out_value = NULL;
- field.out_mask = NULL;
- field.in_value = &status;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_RTI);
- jtag_execute_queue();
-
- DEBUG("status: 0x%2.2x", status);
-
- if (status & ISC_STATUS_SECURITY)
- INFO("Device Security Bit Set");
-
- return status;
-}
-
-int str9xpec_isc_enable(struct flash_bank_s *bank)
-{
- u8 status;
- u32 chain_pos;
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
-
- chain_pos = str9xpec_info->chain_pos;
-
- if (str9xpec_info->isc_enable)
- return ERROR_OK;
-
- /* enter isc mode */
- if (str9xpec_set_instr(chain_pos, ISC_ENABLE, TAP_RTI) != ERROR_OK)
- return ERROR_TARGET_INVALID;
-
- /* check ISC status */
- status = str9xpec_isc_status(chain_pos);
- if (status & ISC_STATUS_MODE)
- {
- /* we have entered isc mode */
- str9xpec_info->isc_enable = 1;
- DEBUG("ISC_MODE Enabled");
- }
-
- return ERROR_OK;
-}
-
-int str9xpec_isc_disable(struct flash_bank_s *bank)
-{
- u8 status;
- u32 chain_pos;
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
-
- chain_pos = str9xpec_info->chain_pos;
-
- if (!str9xpec_info->isc_enable)
- return ERROR_OK;
-
- if (str9xpec_set_instr(chain_pos, ISC_DISABLE, TAP_RTI) != ERROR_OK)
- return ERROR_TARGET_INVALID;
-
- /* delay to handle aborts */
- jtag_add_sleep(50);
-
- /* check ISC status */
- status = str9xpec_isc_status(chain_pos);
- if (!(status & ISC_STATUS_MODE))
- {
- /* we have left isc mode */
- str9xpec_info->isc_enable = 0;
- DEBUG("ISC_MODE Disabled");
- }
-
- return ERROR_OK;
-}
-
-int str9xpec_read_config(struct flash_bank_s *bank)
-{
- scan_field_t field;
- u8 status;
- u32 chain_pos;
-
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
-
- chain_pos = str9xpec_info->chain_pos;
-
- DEBUG("ISC_CONFIGURATION");
-
- /* execute ISC_CONFIGURATION command */
- str9xpec_set_instr(chain_pos, ISC_CONFIGURATION, TAP_PI);
-
- field.device = chain_pos;
- field.num_bits = 64;
- field.out_value = NULL;
- field.out_mask = NULL;
- field.in_value = str9xpec_info->options;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_RTI);
- jtag_execute_queue();
-
- status = str9xpec_isc_status(chain_pos);
-
- return status;
-}
-
-int str9xpec_build_block_list(struct flash_bank_s *bank)
-{
- str9xpec_flash_controller_t *str9xpec_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);
- }
-
- /* include bank 1 sectors */
- num_sectors = b0_sectors + 4;
- bank->size += (32 * 1024);
-
- bank->num_sectors = num_sectors;
- bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
- str9xpec_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_str9pec[i].sector_start;
- bank->sectors[num_sectors].size = mem_layout_str9pec[i].sector_size;
- bank->sectors[num_sectors].is_erased = -1;
- bank->sectors[num_sectors].is_protected = 1;
- str9xpec_info->sector_bits[num_sectors++] = mem_layout_str9pec[i].sector_bit;
- }
-
- for (i = 8; i < 12; i++)
- {
- bank->sectors[num_sectors].offset = mem_layout_str9pec[i].sector_start;
- bank->sectors[num_sectors].size = mem_layout_str9pec[i].sector_size;
- bank->sectors[num_sectors].is_erased = -1;
- bank->sectors[num_sectors].is_protected = 1;
- str9xpec_info->sector_bits[num_sectors++] = mem_layout_str9pec[i].sector_bit;
- }
-
- return ERROR_OK;
-}
-
-/* flash bank str9x <base> <size> 0 0 <target#>
- */
-int str9xpec_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
-{
- str9xpec_flash_controller_t *str9xpec_info;
- armv4_5_common_t *armv4_5 = NULL;
- arm7_9_common_t *arm7_9 = NULL;
- arm_jtag_t *jtag_info = NULL;
-
- if (argc < 6)
- {
- WARNING("incomplete flash_bank str9x configuration");
- return ERROR_FLASH_BANK_INVALID;
- }
-
- str9xpec_info = malloc(sizeof(str9xpec_flash_controller_t));
- bank->driver_priv = str9xpec_info;
-
- if (bank->base != 0x00000000)
- {
- WARNING("overriding flash base address for STR91x device with 0x00000000");
- bank->base = 0x00000000;
- }
-
- /* find out jtag position of flash controller
- * it is always after the arm966 core */
-
- armv4_5 = bank->target->arch_info;
- arm7_9 = armv4_5->arch_info;
- jtag_info = &arm7_9->jtag_info;
-
- str9xpec_info->chain_pos = (jtag_info->chain_pos - 1);
- str9xpec_info->isc_enable = 0;
- str9xpec_info->devarm = NULL;
-
- str9xpec_build_block_list(bank);
-
- /* clear option byte register */
- buf_set_u32(str9xpec_info->options, 0, 64, 0);
-
- return ERROR_OK;
-}
-
-int str9xpec_blank_check(struct flash_bank_s *bank, int first, int last)
-{
- scan_field_t field;
- u8 status;
- u32 chain_pos;
- int i;
- u8 *buffer = NULL;
-
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
-
- chain_pos = str9xpec_info->chain_pos;
-
- if (!str9xpec_info->isc_enable) {
- str9xpec_isc_enable( bank );
- }
-
- if (!str9xpec_info->isc_enable) {
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- buffer = calloc(CEIL(64, 8), 1);
-
- DEBUG("blank check: first_bank: %i, last_bank: %i", first, last);
-
- for (i = first; i <= last; i++) {
- buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1);
- }
-
- /* execute ISC_BLANK_CHECK command */
- str9xpec_set_instr(chain_pos, ISC_BLANK_CHECK, TAP_PI);
-
- field.device = chain_pos;
- field.num_bits = 64;
- field.out_value = buffer;
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_RTI);
- jtag_add_sleep(40000);
-
- /* read blank check result */
- field.device = chain_pos;
- field.num_bits = 64;
- field.out_value = NULL;
- field.out_mask = NULL;
- field.in_value = buffer;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_PI);
- jtag_execute_queue();
-
- status = str9xpec_isc_status(chain_pos);
-
- for (i = first; i <= last; i++)
- {
- if (buf_get_u32(buffer, str9xpec_info->sector_bits[i], 1))
- bank->sectors[i].is_erased = 0;
- else
- bank->sectors[i].is_erased = 1;
- }
-
- free(buffer);
-
- str9xpec_isc_disable(bank);
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
- return ERROR_OK;
-}
-
-int str9xpec_protect_check(struct flash_bank_s *bank)
-{
- u8 status;
- int i;
-
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
-
- status = str9xpec_read_config(bank);
-
- for (i = 0; i < bank->num_sectors; i++)
- {
- if (buf_get_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1))
- bank->sectors[i].is_protected = 1;
- else
- bank->sectors[i].is_protected = 0;
- }
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
- return ERROR_OK;
-}
-
-int str9xpec_erase_area(struct flash_bank_s *bank, int first, int last)
-{
- scan_field_t field;
- u8 status;
- u32 chain_pos;
- int i;
- u8 *buffer = NULL;
-
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
-
- chain_pos = str9xpec_info->chain_pos;
-
- if (!str9xpec_info->isc_enable) {
- str9xpec_isc_enable( bank );
- }
-
- if (!str9xpec_info->isc_enable) {
- return ISC_STATUS_ERROR;
- }
-
- buffer = calloc(CEIL(64, 8), 1);
-
- DEBUG("erase: first_bank: %i, last_bank: %i", first, last);
-
- /* last bank: 0xFF signals a full erase (unlock complete device) */
- /* last bank: 0xFE signals a option byte erase */
- if (last == 0xFF)
- {
- for (i = 0; i < 64; i++) {
- buf_set_u32(buffer, i, 1, 1);
- }
- }
- else if (last == 0xFE)
- {
- buf_set_u32(buffer, 49, 1, 1);
- }
- else
- {
- for (i = first; i <= last; i++) {
- buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1);
- }
- }
-
- DEBUG("ISC_ERASE");
-
- /* execute ISC_ERASE command */
- str9xpec_set_instr(chain_pos, ISC_ERASE, TAP_PI);
-
- field.device = chain_pos;
- field.num_bits = 64;
- field.out_value = buffer;
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_RTI);
- jtag_execute_queue();
-
- jtag_add_sleep(10);
-
- /* wait for erase completion */
- while (!((status = str9xpec_isc_status(chain_pos)) & ISC_STATUS_BUSY)) {
- usleep(1000);
- }
-
- free(buffer);
-
- str9xpec_isc_disable(bank);
-
- return status;
-}
-
-int str9xpec_erase(struct flash_bank_s *bank, int first, int last)
-{
- int status;
-
- status = str9xpec_erase_area(bank, first, last);
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- return ERROR_OK;
-}
-
-int str9xpec_lock_device(struct flash_bank_s *bank)
-{
- scan_field_t field;
- u8 status;
- u32 chain_pos;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- str9xpec_info = bank->driver_priv;
- chain_pos = str9xpec_info->chain_pos;
-
- if (!str9xpec_info->isc_enable) {
- str9xpec_isc_enable( bank );
- }
-
- if (!str9xpec_info->isc_enable) {
- return ISC_STATUS_ERROR;
- }
-
- /* set security address */
- str9xpec_set_address(bank, 0x80);
-
- /* execute ISC_PROGRAM command */
- str9xpec_set_instr(chain_pos, ISC_PROGRAM_SECURITY, TAP_RTI);
-
- str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI);
-
- do {
- field.device = chain_pos;
- field.num_bits = 8;
- field.out_value = NULL;
- field.out_mask = NULL;
- field.in_value = &status;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, -1);
- jtag_execute_queue();
-
- } while(!(status & ISC_STATUS_BUSY));
-
- str9xpec_isc_disable(bank);
-
- return status;
-}
-
-int str9xpec_unlock_device(struct flash_bank_s *bank)
-{
- u8 status;
-
- status = str9xpec_erase_area(bank, 0, 255);
-
- return status;
-}
-
-int str9xpec_protect(struct flash_bank_s *bank, int set, int first, int last)
-{
- u8 status;
- int i;
-
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
-
- status = str9xpec_read_config(bank);
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- DEBUG("protect: first_bank: %i, last_bank: %i", first, last);
-
- /* last bank: 0xFF signals a full device protect */
- if (last == 0xFF)
- {
- if( set )
- {
- status = str9xpec_lock_device(bank);
- }
- else
- {
- /* perform full erase to unlock device */
- status = str9xpec_unlock_device(bank);
- }
- }
- else
- {
- for (i = first; i <= last; i++)
- {
- if( set )
- buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 1);
- else
- buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 0);
- }
-
- status = str9xpec_write_options(bank);
- }
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- return ERROR_OK;
-}
-
-int str9xpec_set_address(struct flash_bank_s *bank, u8 sector)
-{
- u32 chain_pos;
- scan_field_t field;
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
-
- chain_pos = str9xpec_info->chain_pos;
-
- /* set flash controller address */
- str9xpec_set_instr(chain_pos, ISC_ADDRESS_SHIFT, TAP_PI);
-
- field.device = chain_pos;
- field.num_bits = 8;
- field.out_value = §or;
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, -1);
-
- return ERROR_OK;
-}
-
-int str9xpec_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
-{
- str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv;
- u32 dwords_remaining = (count / 8);
- u32 bytes_remaining = (count & 0x00000007);
- u32 bytes_written = 0;
- u8 status;
- u32 check_address = offset;
- u32 chain_pos;
- scan_field_t field;
- u8 *scanbuf;
- int i;
- u32 first_sector = 0;
- u32 last_sector = 0;
-
- chain_pos = str9xpec_info->chain_pos;
-
- if (!str9xpec_info->isc_enable) {
- str9xpec_isc_enable(bank);
- }
-
- if (!str9xpec_info->isc_enable) {
- return ERROR_FLASH_OPERATION_FAILED;
- }
-
- if (offset & 0x7)
- {
- WARNING("offset 0x%x breaks required 8-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 ((offset >= sec_start) && (offset < sec_end)){
- first_sector = i;
- }
-
- if ((offset + count >= sec_start) && (offset + count < sec_end)){
- last_sector = i;
- }
- }
-
- if (check_address != offset + count)
- return ERROR_FLASH_DST_OUT_OF_BANK;
-
- DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);
-
- scanbuf = calloc(CEIL(64, 8), 1);
-
- DEBUG("ISC_PROGRAM");
-
- for (i = first_sector; i <= last_sector; i++)
- {
- str9xpec_set_address(bank, str9xpec_info->sector_bits[i]);
-
- dwords_remaining = dwords_remaining < (bank->sectors[i].size/8) ? dwords_remaining : (bank->sectors[i].size/8);
-
- while (dwords_remaining > 0)
- {
- str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI);
-
- field.device = chain_pos;
- field.num_bits = 64;
- field.out_value = (buffer + bytes_written);
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_RTI);
-
- /* small delay before polling */
- jtag_add_sleep(50);
-
- str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI);
-
- do {
- field.device = chain_pos;
- field.num_bits = 8;
- field.out_value = NULL;
- field.out_mask = NULL;
- field.in_value = scanbuf;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, -1);
- jtag_execute_queue();
-
- status = buf_get_u32(scanbuf, 0, 8);
-
- } while(!(status & ISC_STATUS_BUSY));
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- //if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL)
- // return ERROR_FLASH_OPERATION_FAILED;
-
- dwords_remaining--;
- bytes_written += 8;
- }
- }
-
- if (bytes_remaining)
- {
- u8 last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- int i = 0;
-
- while(bytes_remaining > 0)
- {
- last_dword[i++] = *(buffer + bytes_written);
- bytes_remaining--;
- bytes_written++;
- }
-
- str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI);
-
- field.device = chain_pos;
- field.num_bits = 64;
- field.out_value = last_dword;
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_RTI);
-
- /* small delay before polling */
- jtag_add_sleep(50);
-
- str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI);
-
- do {
- field.device = chain_pos;
- field.num_bits = 8;
- field.out_value = NULL;
- field.out_mask = NULL;
- field.in_value = scanbuf;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, -1);
- jtag_execute_queue();
-
- status = buf_get_u32(scanbuf, 0, 8);
-
- } while(!(status & ISC_STATUS_BUSY));
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- //if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL)
- // return ERROR_FLASH_OPERATION_FAILED;
- }
-
- free(scanbuf);
-
- str9xpec_isc_disable(bank);
-
- return ERROR_OK;
-}
-
-int str9xpec_probe(struct flash_bank_s *bank)
-{
- return ERROR_OK;
-}
-
-int str9xpec_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- scan_field_t field;
- u8 *buffer = NULL;
- u32 chain_pos;
- u32 idcode;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- if (argc < 1)
- {
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
- if (!bank)
- {
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
- return ERROR_OK;
- }
-
- str9xpec_info = bank->driver_priv;
- chain_pos = str9xpec_info->chain_pos;
-
- buffer = calloc(CEIL(32, 8), 1);
-
- str9xpec_set_instr(chain_pos, ISC_IDCODE, TAP_PI);
-
- field.device = chain_pos;
- field.num_bits = 32;
- field.out_value = NULL;
- field.out_mask = NULL;
- field.in_value = buffer;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_RTI);
- jtag_execute_queue();
-
- idcode = buf_get_u32(buffer, 0, 32);
-
- command_print(cmd_ctx, "str9xpec part id: 0x%8.8x", idcode);
-
- free(buffer);
-
- return ERROR_OK;
-}
-
-int str9xpec_erase_check(struct flash_bank_s *bank)
-{
- return str9xpec_blank_check(bank, 0, bank->num_sectors - 1);
-}
-
-int str9xpec_info(struct flash_bank_s *bank, char *buf, int buf_size)
-{
- snprintf(buf, buf_size, "str9xpec flash driver info" );
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- u8 status;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "str9xpec options_read <bank>");
- return ERROR_OK;
- }
-
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
- if (!bank)
- {
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
- return ERROR_OK;
- }
-
- str9xpec_info = bank->driver_priv;
-
- status = str9xpec_read_config(bank);
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- /* boot bank */
- if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1))
- command_print(cmd_ctx, "CS Map: bank1");
- else
- command_print(cmd_ctx, "CS Map: bank0");
-
- /* OTP lock */
- if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_OTPBIT, 1))
- command_print(cmd_ctx, "OTP Lock: OTP Locked");
- else
- command_print(cmd_ctx, "OTP Lock: OTP Unlocked");
-
- /* LVD Threshold */
- if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1))
- command_print(cmd_ctx, "LVD Threshold: 2.7v");
- else
- command_print(cmd_ctx, "LVD Threshold: 2.4v");
-
- /* LVD reset warning */
- if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1))
- command_print(cmd_ctx, "LVD Reset Warning: VDD or VDDQ Inputs");
- else
- command_print(cmd_ctx, "LVD Reset Warning: VDD Input Only");
-
- /* LVD reset select */
- if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1))
- command_print(cmd_ctx, "LVD Reset Selection: VDD or VDDQ Inputs");
- else
- command_print(cmd_ctx, "LVD Reset Selection: VDD Input Only");
-
- return ERROR_OK;
-}
-
-int str9xpec_write_options(struct flash_bank_s *bank)
-{
- scan_field_t field;
- u8 status;
- u32 chain_pos;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- str9xpec_info = bank->driver_priv;
- chain_pos = str9xpec_info->chain_pos;
-
- /* erase config options first */
- status = str9xpec_erase_area( bank, 0xFE, 0xFE );
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return status;
-
- if (!str9xpec_info->isc_enable) {
- str9xpec_isc_enable( bank );
- }
-
- if (!str9xpec_info->isc_enable) {
- return ISC_STATUS_ERROR;
- }
-
- /* according to data 64th bit has to be set */
- buf_set_u32(str9xpec_info->options, 63, 1, 1);
-
- /* set option byte address */
- str9xpec_set_address(bank, 0x50);
-
- /* execute ISC_PROGRAM command */
- str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI);
-
- field.device = chain_pos;
- field.num_bits = 64;
- field.out_value = str9xpec_info->options;
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, TAP_RTI);
-
- /* small delay before polling */
- jtag_add_sleep(50);
-
- str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI);
-
- do {
- field.device = chain_pos;
- field.num_bits = 8;
- field.out_value = NULL;
- field.out_mask = NULL;
- field.in_value = &status;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_dr_scan(1, &field, -1);
- jtag_execute_queue();
-
- } while(!(status & ISC_STATUS_BUSY));
-
- str9xpec_isc_disable(bank);
-
- return status;
-}
-
-int str9xpec_handle_flash_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- u8 status;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "str9xpec options_write <bank>");
- return ERROR_OK;
- }
-
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
- if (!bank)
- {
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
- return ERROR_OK;
- }
-
- status = str9xpec_write_options(bank);
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_options_cmap_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- if (argc < 2)
- {
- command_print(cmd_ctx, "str9xpec options_cmap <bank> <bank0|bank1>");
- return ERROR_OK;
- }
-
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
- if (!bank)
- {
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
- return ERROR_OK;
- }
-
- str9xpec_info = bank->driver_priv;
-
- if (strcmp(args[1], "bank1") == 0)
- {
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 1);
- }
- else
- {
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 0);
- }
-
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_options_lvdthd_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- if (argc < 2)
- {
- command_print(cmd_ctx, "str9xpec options_lvdthd <bank> <2.4v|2.7v>");
- return ERROR_OK;
- }
-
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
- if (!bank)
- {
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
- return ERROR_OK;
- }
-
- str9xpec_info = bank->driver_priv;
-
- if (strcmp(args[1], "2.7v") == 0)
- {
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 1);
- }
- else
- {
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 0);
- }
-
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_options_lvdsel_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- if (argc < 2)
- {
- command_print(cmd_ctx, "str9xpec options_lvdsel <bank> <vdd|vdd_vddq>");
- return ERROR_OK;
- }
-
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
- if (!bank)
- {
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
- return ERROR_OK;
- }
-
- str9xpec_info = bank->driver_priv;
-
- if (strcmp(args[1], "vdd_vddq") == 0)
- {
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 1);
- }
- else
- {
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 0);
- }
-
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_options_lvdwarn_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- if (argc < 2)
- {
- command_print(cmd_ctx, "str9xpec options_lvdwarn <bank> <vdd|vdd_vddq>");
- return ERROR_OK;
- }
-
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
- if (!bank)
- {
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
- return ERROR_OK;
- }
-
- str9xpec_info = bank->driver_priv;
-
- if (strcmp(args[1], "vdd_vddq") == 0)
- {
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 1);
- }
- else
- {
- buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 0);
- }
-
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- u8 status;
- flash_bank_t *bank;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "str9xpec lock <bank>");
- return ERROR_OK;
- }
-
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
- if (!bank)
- {
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
- return ERROR_OK;
- }
-
- status = str9xpec_lock_device(bank);
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- u8 status;
- flash_bank_t *bank;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "str9xpec unlock <bank>");
- return ERROR_OK;
- }
-
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
- if (!bank)
- {
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
- return ERROR_OK;
- }
-
- status = str9xpec_unlock_device(bank);
-
- if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS)
- return ERROR_FLASH_OPERATION_FAILED;
-
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_enable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- u32 chain_pos;
- jtag_device_t* dev0;
- jtag_device_t* dev2;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "str9xpec enable_turbo <bank>");
- return ERROR_OK;
- }
-
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
- if (!bank)
- {
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
- return ERROR_OK;
- }
-
- str9xpec_info = bank->driver_priv;
-
- chain_pos = str9xpec_info->chain_pos;
-
- /* remove arm core from chain - enter turbo mode */
-
- str9xpec_set_instr(chain_pos+2, 0xD, TAP_RTI);
- jtag_execute_queue();
-
- /* modify scan chain - str9 core has been removed */
- dev0 = jtag_get_device(chain_pos);
- str9xpec_info->devarm = jtag_get_device(chain_pos+1);
- dev2 = jtag_get_device(chain_pos+2);
- dev0->next = dev2;
- jtag_num_devices--;
-
- return ERROR_OK;
-}
-
-int str9xpec_handle_flash_disable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- flash_bank_t *bank;
- u32 chain_pos;
- jtag_device_t* dev0;
- str9xpec_flash_controller_t *str9xpec_info = NULL;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "str9xpec disable_turbo <bank>");
- return ERROR_OK;
- }
-
- bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
- if (!bank)
- {
- command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
- return ERROR_OK;
- }
-
- str9xpec_info = bank->driver_priv;
-
- chain_pos = str9xpec_info->chain_pos;
-
- dev0 = jtag_get_device(chain_pos);
-
- /* exit turbo mode via TLR */
- str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_TLR);
- jtag_execute_queue();
-
- /* restore previous scan chain */
- if( str9xpec_info->devarm ) {
- dev0->next = str9xpec_info->devarm;
- jtag_num_devices++;
- str9xpec_info->devarm = NULL;
- }
-
- return ERROR_OK;
-}
+/*************************************************************************** + * 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 "str9xpec.h" +#include "flash.h" +#include "target.h" +#include "log.h" +#include "armv4_5.h" +#include "arm7_9_common.h" +#include "jtag.h" +#include "binarybuffer.h" + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <getopt.h> + +str9xpec_mem_layout_t mem_layout_str9pec[] = { + {0x00000000, 0x10000, 0}, + {0x00010000, 0x10000, 1}, + {0x00020000, 0x10000, 2}, + {0x00030000, 0x10000, 3}, + {0x00040000, 0x10000, 4}, + {0x00050000, 0x10000, 5}, + {0x00060000, 0x10000, 6}, + {0x00070000, 0x10000, 7}, + {0x00080000, 0x02000, 32}, + {0x00082000, 0x02000, 33}, + {0x00084000, 0x02000, 34}, + {0x00086000, 0x02000, 35} +}; + +int str9xpec_register_commands(struct command_context_s *cmd_ctx); +int str9xpec_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank); +int str9xpec_erase(struct flash_bank_s *bank, int first, int last); +int str9xpec_protect(struct flash_bank_s *bank, int set, int first, int last); +int str9xpec_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count); +int str9xpec_probe(struct flash_bank_s *bank); +int str9xpec_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_protect_check(struct flash_bank_s *bank); +int str9xpec_erase_check(struct flash_bank_s *bank); +int str9xpec_info(struct flash_bank_s *bank, char *buf, int buf_size); + +int str9xpec_erase_area(struct flash_bank_s *bank, int first, int last); +int str9xpec_set_address(struct flash_bank_s *bank, u8 sector); +int str9xpec_write_options(struct flash_bank_s *bank); + +int str9xpec_handle_flash_options_cmap_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_options_lvdthd_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_options_lvdsel_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_options_lvdwarn_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_enable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_disable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +flash_driver_t str9xpec_flash = +{ + .name = "str9xpec", + .register_commands = str9xpec_register_commands, + .flash_bank_command = str9xpec_flash_bank_command, + .erase = str9xpec_erase, + .protect = str9xpec_protect, + .write = str9xpec_write, + .probe = str9xpec_probe, + .auto_probe = str9xpec_probe, + .erase_check = str9xpec_erase_check, + .protect_check = str9xpec_protect_check, + .info = str9xpec_info +}; + +int str9xpec_register_commands(struct command_context_s *cmd_ctx) +{ + command_t *str9xpec_cmd = register_command(cmd_ctx, NULL, "str9xpec", NULL, COMMAND_ANY, "str9xpec flash specific commands"); + + register_command(cmd_ctx, str9xpec_cmd, "enable_turbo", str9xpec_handle_flash_enable_turbo_command, COMMAND_EXEC, + "enable str9xpec turbo mode"); + register_command(cmd_ctx, str9xpec_cmd, "disable_turbo", str9xpec_handle_flash_disable_turbo_command, COMMAND_EXEC, + "disable str9xpec turbo mode"); + register_command(cmd_ctx, str9xpec_cmd, "options_cmap", str9xpec_handle_flash_options_cmap_command, COMMAND_EXEC, + "configure str9xpec boot sector"); + register_command(cmd_ctx, str9xpec_cmd, "options_lvdthd", str9xpec_handle_flash_options_lvdthd_command, COMMAND_EXEC, + "configure str9xpec lvd threshold"); + register_command(cmd_ctx, str9xpec_cmd, "options_lvdsel", str9xpec_handle_flash_options_lvdsel_command, COMMAND_EXEC, + "configure str9xpec lvd selection"); + register_command(cmd_ctx, str9xpec_cmd, "options_lvdwarn", str9xpec_handle_flash_options_lvdwarn_command, COMMAND_EXEC, + "configure str9xpec lvd warning"); + register_command(cmd_ctx, str9xpec_cmd, "options_read", str9xpec_handle_flash_options_read_command, COMMAND_EXEC, + "read str9xpec options"); + register_command(cmd_ctx, str9xpec_cmd, "options_write", str9xpec_handle_flash_options_write_command, COMMAND_EXEC, + "write str9xpec options"); + register_command(cmd_ctx, str9xpec_cmd, "lock", str9xpec_handle_flash_lock_command, COMMAND_EXEC, + "lock str9xpec device"); + register_command(cmd_ctx, str9xpec_cmd, "unlock", str9xpec_handle_flash_unlock_command, COMMAND_EXEC, + "unlock str9xpec device"); + register_command(cmd_ctx, str9xpec_cmd, "part_id", str9xpec_handle_part_id_command, COMMAND_EXEC, + "print part id of str9xpec flash bank <num>"); + + return ERROR_OK; +} + +int str9xpec_set_instr(int chain_pos, u32 new_instr, enum tap_state end_state) +{ + jtag_device_t *device = jtag_get_device(chain_pos); + + if (device == NULL) + { + DEBUG("Invalid Target"); + return ERROR_TARGET_INVALID; + } + + if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) + { + scan_field_t field; + + field.device = chain_pos; + field.num_bits = device->ir_length; + field.out_value = calloc(CEIL(field.num_bits, 8), 1); + buf_set_u32(field.out_value, 0, field.num_bits, new_instr); + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_ir_scan(1, &field, end_state); + + free(field.out_value); + } + + return ERROR_OK; +} + +u8 str9xpec_isc_status(int chain_pos) +{ + scan_field_t field; + u8 status; + + if (str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI) != ERROR_OK) + return ISC_STATUS_ERROR; + + field.device = chain_pos; + field.num_bits = 8; + field.out_value = NULL; + field.out_mask = NULL; + field.in_value = &status; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_RTI); + jtag_execute_queue(); + + DEBUG("status: 0x%2.2x", status); + + if (status & ISC_STATUS_SECURITY) + INFO("Device Security Bit Set"); + + return status; +} + +int str9xpec_isc_enable(struct flash_bank_s *bank) +{ + u8 status; + u32 chain_pos; + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + + chain_pos = str9xpec_info->chain_pos; + + if (str9xpec_info->isc_enable) + return ERROR_OK; + + /* enter isc mode */ + if (str9xpec_set_instr(chain_pos, ISC_ENABLE, TAP_RTI) != ERROR_OK) + return ERROR_TARGET_INVALID; + + /* check ISC status */ + status = str9xpec_isc_status(chain_pos); + if (status & ISC_STATUS_MODE) + { + /* we have entered isc mode */ + str9xpec_info->isc_enable = 1; + DEBUG("ISC_MODE Enabled"); + } + + return ERROR_OK; +} + +int str9xpec_isc_disable(struct flash_bank_s *bank) +{ + u8 status; + u32 chain_pos; + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + + chain_pos = str9xpec_info->chain_pos; + + if (!str9xpec_info->isc_enable) + return ERROR_OK; + + if (str9xpec_set_instr(chain_pos, ISC_DISABLE, TAP_RTI) != ERROR_OK) + return ERROR_TARGET_INVALID; + + /* delay to handle aborts */ + jtag_add_sleep(50); + + /* check ISC status */ + status = str9xpec_isc_status(chain_pos); + if (!(status & ISC_STATUS_MODE)) + { + /* we have left isc mode */ + str9xpec_info->isc_enable = 0; + DEBUG("ISC_MODE Disabled"); + } + + return ERROR_OK; +} + +int str9xpec_read_config(struct flash_bank_s *bank) +{ + scan_field_t field; + u8 status; + u32 chain_pos; + + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + + chain_pos = str9xpec_info->chain_pos; + + DEBUG("ISC_CONFIGURATION"); + + /* execute ISC_CONFIGURATION command */ + str9xpec_set_instr(chain_pos, ISC_CONFIGURATION, TAP_PI); + + field.device = chain_pos; + field.num_bits = 64; + field.out_value = NULL; + field.out_mask = NULL; + field.in_value = str9xpec_info->options; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_RTI); + jtag_execute_queue(); + + status = str9xpec_isc_status(chain_pos); + + return status; +} + +int str9xpec_build_block_list(struct flash_bank_s *bank) +{ + str9xpec_flash_controller_t *str9xpec_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); + } + + /* include bank 1 sectors */ + num_sectors = b0_sectors + 4; + bank->size += (32 * 1024); + + bank->num_sectors = num_sectors; + bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors); + str9xpec_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_str9pec[i].sector_start; + bank->sectors[num_sectors].size = mem_layout_str9pec[i].sector_size; + bank->sectors[num_sectors].is_erased = -1; + bank->sectors[num_sectors].is_protected = 1; + str9xpec_info->sector_bits[num_sectors++] = mem_layout_str9pec[i].sector_bit; + } + + for (i = 8; i < 12; i++) + { + bank->sectors[num_sectors].offset = mem_layout_str9pec[i].sector_start; + bank->sectors[num_sectors].size = mem_layout_str9pec[i].sector_size; + bank->sectors[num_sectors].is_erased = -1; + bank->sectors[num_sectors].is_protected = 1; + str9xpec_info->sector_bits[num_sectors++] = mem_layout_str9pec[i].sector_bit; + } + + return ERROR_OK; +} + +/* flash bank str9x <base> <size> 0 0 <target#> + */ +int str9xpec_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank) +{ + str9xpec_flash_controller_t *str9xpec_info; + armv4_5_common_t *armv4_5 = NULL; + arm7_9_common_t *arm7_9 = NULL; + arm_jtag_t *jtag_info = NULL; + + if (argc < 6) + { + WARNING("incomplete flash_bank str9x configuration"); + return ERROR_FLASH_BANK_INVALID; + } + + str9xpec_info = malloc(sizeof(str9xpec_flash_controller_t)); + bank->driver_priv = str9xpec_info; + + if (bank->base != 0x00000000) + { + WARNING("overriding flash base address for STR91x device with 0x00000000"); + bank->base = 0x00000000; + } + + /* find out jtag position of flash controller + * it is always after the arm966 core */ + + armv4_5 = bank->target->arch_info; + arm7_9 = armv4_5->arch_info; + jtag_info = &arm7_9->jtag_info; + + str9xpec_info->chain_pos = (jtag_info->chain_pos - 1); + str9xpec_info->isc_enable = 0; + str9xpec_info->devarm = NULL; + + str9xpec_build_block_list(bank); + + /* clear option byte register */ + buf_set_u32(str9xpec_info->options, 0, 64, 0); + + return ERROR_OK; +} + +int str9xpec_blank_check(struct flash_bank_s *bank, int first, int last) +{ + scan_field_t field; + u8 status; + u32 chain_pos; + int i; + u8 *buffer = NULL; + + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + + chain_pos = str9xpec_info->chain_pos; + + if (!str9xpec_info->isc_enable) { + str9xpec_isc_enable( bank ); + } + + if (!str9xpec_info->isc_enable) { + return ERROR_FLASH_OPERATION_FAILED; + } + + buffer = calloc(CEIL(64, 8), 1); + + DEBUG("blank check: first_bank: %i, last_bank: %i", first, last); + + for (i = first; i <= last; i++) { + buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1); + } + + /* execute ISC_BLANK_CHECK command */ + str9xpec_set_instr(chain_pos, ISC_BLANK_CHECK, TAP_PI); + + field.device = chain_pos; + field.num_bits = 64; + field.out_value = buffer; + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_RTI); + jtag_add_sleep(40000); + + /* read blank check result */ + field.device = chain_pos; + field.num_bits = 64; + field.out_value = NULL; + field.out_mask = NULL; + field.in_value = buffer; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_PI); + jtag_execute_queue(); + + status = str9xpec_isc_status(chain_pos); + + for (i = first; i <= last; i++) + { + if (buf_get_u32(buffer, str9xpec_info->sector_bits[i], 1)) + bank->sectors[i].is_erased = 0; + else + bank->sectors[i].is_erased = 1; + } + + free(buffer); + + str9xpec_isc_disable(bank); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + return ERROR_OK; +} + +int str9xpec_protect_check(struct flash_bank_s *bank) +{ + u8 status; + int i; + + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + + status = str9xpec_read_config(bank); + + for (i = 0; i < bank->num_sectors; i++) + { + if (buf_get_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1)) + bank->sectors[i].is_protected = 1; + else + bank->sectors[i].is_protected = 0; + } + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + return ERROR_OK; +} + +int str9xpec_erase_area(struct flash_bank_s *bank, int first, int last) +{ + scan_field_t field; + u8 status; + u32 chain_pos; + int i; + u8 *buffer = NULL; + + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + + chain_pos = str9xpec_info->chain_pos; + + if (!str9xpec_info->isc_enable) { + str9xpec_isc_enable( bank ); + } + + if (!str9xpec_info->isc_enable) { + return ISC_STATUS_ERROR; + } + + buffer = calloc(CEIL(64, 8), 1); + + DEBUG("erase: first_bank: %i, last_bank: %i", first, last); + + /* last bank: 0xFF signals a full erase (unlock complete device) */ + /* last bank: 0xFE signals a option byte erase */ + if (last == 0xFF) + { + for (i = 0; i < 64; i++) { + buf_set_u32(buffer, i, 1, 1); + } + } + else if (last == 0xFE) + { + buf_set_u32(buffer, 49, 1, 1); + } + else + { + for (i = first; i <= last; i++) { + buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1); + } + } + + DEBUG("ISC_ERASE"); + + /* execute ISC_ERASE command */ + str9xpec_set_instr(chain_pos, ISC_ERASE, TAP_PI); + + field.device = chain_pos; + field.num_bits = 64; + field.out_value = buffer; + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_RTI); + jtag_execute_queue(); + + jtag_add_sleep(10); + + /* wait for erase completion */ + while (!((status = str9xpec_isc_status(chain_pos)) & ISC_STATUS_BUSY)) { + usleep(1000); + } + + free(buffer); + + str9xpec_isc_disable(bank); + + return status; +} + +int str9xpec_erase(struct flash_bank_s *bank, int first, int last) +{ + int status; + + status = str9xpec_erase_area(bank, first, last); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + return ERROR_OK; +} + +int str9xpec_lock_device(struct flash_bank_s *bank) +{ + scan_field_t field; + u8 status; + u32 chain_pos; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + str9xpec_info = bank->driver_priv; + chain_pos = str9xpec_info->chain_pos; + + if (!str9xpec_info->isc_enable) { + str9xpec_isc_enable( bank ); + } + + if (!str9xpec_info->isc_enable) { + return ISC_STATUS_ERROR; + } + + /* set security address */ + str9xpec_set_address(bank, 0x80); + + /* execute ISC_PROGRAM command */ + str9xpec_set_instr(chain_pos, ISC_PROGRAM_SECURITY, TAP_RTI); + + str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI); + + do { + field.device = chain_pos; + field.num_bits = 8; + field.out_value = NULL; + field.out_mask = NULL; + field.in_value = &status; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, -1); + jtag_execute_queue(); + + } while(!(status & ISC_STATUS_BUSY)); + + str9xpec_isc_disable(bank); + + return status; +} + +int str9xpec_unlock_device(struct flash_bank_s *bank) +{ + u8 status; + + status = str9xpec_erase_area(bank, 0, 255); + + return status; +} + +int str9xpec_protect(struct flash_bank_s *bank, int set, int first, int last) +{ + u8 status; + int i; + + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + + status = str9xpec_read_config(bank); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + DEBUG("protect: first_bank: %i, last_bank: %i", first, last); + + /* last bank: 0xFF signals a full device protect */ + if (last == 0xFF) + { + if( set ) + { + status = str9xpec_lock_device(bank); + } + else + { + /* perform full erase to unlock device */ + status = str9xpec_unlock_device(bank); + } + } + else + { + for (i = first; i <= last; i++) + { + if( set ) + buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 1); + else + buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 0); + } + + status = str9xpec_write_options(bank); + } + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + return ERROR_OK; +} + +int str9xpec_set_address(struct flash_bank_s *bank, u8 sector) +{ + u32 chain_pos; + scan_field_t field; + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + + chain_pos = str9xpec_info->chain_pos; + + /* set flash controller address */ + str9xpec_set_instr(chain_pos, ISC_ADDRESS_SHIFT, TAP_PI); + + field.device = chain_pos; + field.num_bits = 8; + field.out_value = §or; + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, -1); + + return ERROR_OK; +} + +int str9xpec_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count) +{ + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + u32 dwords_remaining = (count / 8); + u32 bytes_remaining = (count & 0x00000007); + u32 bytes_written = 0; + u8 status; + u32 check_address = offset; + u32 chain_pos; + scan_field_t field; + u8 *scanbuf; + int i; + u32 first_sector = 0; + u32 last_sector = 0; + + chain_pos = str9xpec_info->chain_pos; + + if (!str9xpec_info->isc_enable) { + str9xpec_isc_enable(bank); + } + + if (!str9xpec_info->isc_enable) { + return ERROR_FLASH_OPERATION_FAILED; + } + + if (offset & 0x7) + { + WARNING("offset 0x%x breaks required 8-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 ((offset >= sec_start) && (offset < sec_end)){ + first_sector = i; + } + + if ((offset + count >= sec_start) && (offset + count < sec_end)){ + last_sector = i; + } + } + + if (check_address != offset + count) + return ERROR_FLASH_DST_OUT_OF_BANK; + + DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector); + + scanbuf = calloc(CEIL(64, 8), 1); + + DEBUG("ISC_PROGRAM"); + + for (i = first_sector; i <= last_sector; i++) + { + str9xpec_set_address(bank, str9xpec_info->sector_bits[i]); + + dwords_remaining = dwords_remaining < (bank->sectors[i].size/8) ? dwords_remaining : (bank->sectors[i].size/8); + + while (dwords_remaining > 0) + { + str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI); + + field.device = chain_pos; + field.num_bits = 64; + field.out_value = (buffer + bytes_written); + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_RTI); + + /* small delay before polling */ + jtag_add_sleep(50); + + str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI); + + do { + field.device = chain_pos; + field.num_bits = 8; + field.out_value = NULL; + field.out_mask = NULL; + field.in_value = scanbuf; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, -1); + jtag_execute_queue(); + + status = buf_get_u32(scanbuf, 0, 8); + + } while(!(status & ISC_STATUS_BUSY)); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + //if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL) + // return ERROR_FLASH_OPERATION_FAILED; + + dwords_remaining--; + bytes_written += 8; + } + } + + if (bytes_remaining) + { + u8 last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + int i = 0; + + while(bytes_remaining > 0) + { + last_dword[i++] = *(buffer + bytes_written); + bytes_remaining--; + bytes_written++; + } + + str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI); + + field.device = chain_pos; + field.num_bits = 64; + field.out_value = last_dword; + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_RTI); + + /* small delay before polling */ + jtag_add_sleep(50); + + str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI); + + do { + field.device = chain_pos; + field.num_bits = 8; + field.out_value = NULL; + field.out_mask = NULL; + field.in_value = scanbuf; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, -1); + jtag_execute_queue(); + + status = buf_get_u32(scanbuf, 0, 8); + + } while(!(status & ISC_STATUS_BUSY)); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + //if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL) + // return ERROR_FLASH_OPERATION_FAILED; + } + + free(scanbuf); + + str9xpec_isc_disable(bank); + + return ERROR_OK; +} + +int str9xpec_probe(struct flash_bank_s *bank) +{ + return ERROR_OK; +} + +int str9xpec_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + scan_field_t field; + u8 *buffer = NULL; + u32 chain_pos; + u32 idcode; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + if (argc < 1) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + str9xpec_info = bank->driver_priv; + chain_pos = str9xpec_info->chain_pos; + + buffer = calloc(CEIL(32, 8), 1); + + str9xpec_set_instr(chain_pos, ISC_IDCODE, TAP_PI); + + field.device = chain_pos; + field.num_bits = 32; + field.out_value = NULL; + field.out_mask = NULL; + field.in_value = buffer; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_RTI); + jtag_execute_queue(); + + idcode = buf_get_u32(buffer, 0, 32); + + command_print(cmd_ctx, "str9xpec part id: 0x%8.8x", idcode); + + free(buffer); + + return ERROR_OK; +} + +int str9xpec_erase_check(struct flash_bank_s *bank) +{ + return str9xpec_blank_check(bank, 0, bank->num_sectors - 1); +} + +int str9xpec_info(struct flash_bank_s *bank, char *buf, int buf_size) +{ + snprintf(buf, buf_size, "str9xpec flash driver info" ); + return ERROR_OK; +} + +int str9xpec_handle_flash_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + u8 status; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + if (argc < 1) + { + command_print(cmd_ctx, "str9xpec options_read <bank>"); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + str9xpec_info = bank->driver_priv; + + status = str9xpec_read_config(bank); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + /* boot bank */ + if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1)) + command_print(cmd_ctx, "CS Map: bank1"); + else + command_print(cmd_ctx, "CS Map: bank0"); + + /* OTP lock */ + if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_OTPBIT, 1)) + command_print(cmd_ctx, "OTP Lock: OTP Locked"); + else + command_print(cmd_ctx, "OTP Lock: OTP Unlocked"); + + /* LVD Threshold */ + if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1)) + command_print(cmd_ctx, "LVD Threshold: 2.7v"); + else + command_print(cmd_ctx, "LVD Threshold: 2.4v"); + + /* LVD reset warning */ + if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1)) + command_print(cmd_ctx, "LVD Reset Warning: VDD or VDDQ Inputs"); + else + command_print(cmd_ctx, "LVD Reset Warning: VDD Input Only"); + + /* LVD reset select */ + if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1)) + command_print(cmd_ctx, "LVD Reset Selection: VDD or VDDQ Inputs"); + else + command_print(cmd_ctx, "LVD Reset Selection: VDD Input Only"); + + return ERROR_OK; +} + +int str9xpec_write_options(struct flash_bank_s *bank) +{ + scan_field_t field; + u8 status; + u32 chain_pos; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + str9xpec_info = bank->driver_priv; + chain_pos = str9xpec_info->chain_pos; + + /* erase config options first */ + status = str9xpec_erase_area( bank, 0xFE, 0xFE ); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return status; + + if (!str9xpec_info->isc_enable) { + str9xpec_isc_enable( bank ); + } + + if (!str9xpec_info->isc_enable) { + return ISC_STATUS_ERROR; + } + + /* according to data 64th bit has to be set */ + buf_set_u32(str9xpec_info->options, 63, 1, 1); + + /* set option byte address */ + str9xpec_set_address(bank, 0x50); + + /* execute ISC_PROGRAM command */ + str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI); + + field.device = chain_pos; + field.num_bits = 64; + field.out_value = str9xpec_info->options; + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_RTI); + + /* small delay before polling */ + jtag_add_sleep(50); + + str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI); + + do { + field.device = chain_pos; + field.num_bits = 8; + field.out_value = NULL; + field.out_mask = NULL; + field.in_value = &status; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, -1); + jtag_execute_queue(); + + } while(!(status & ISC_STATUS_BUSY)); + + str9xpec_isc_disable(bank); + + return status; +} + +int str9xpec_handle_flash_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + u8 status; + + if (argc < 1) + { + command_print(cmd_ctx, "str9xpec options_write <bank>"); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + status = str9xpec_write_options(bank); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + return ERROR_OK; +} + +int str9xpec_handle_flash_options_cmap_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + if (argc < 2) + { + command_print(cmd_ctx, "str9xpec options_cmap <bank> <bank0|bank1>"); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + str9xpec_info = bank->driver_priv; + + if (strcmp(args[1], "bank1") == 0) + { + buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 1); + } + else + { + buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 0); + } + + return ERROR_OK; +} + +int str9xpec_handle_flash_options_lvdthd_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + if (argc < 2) + { + command_print(cmd_ctx, "str9xpec options_lvdthd <bank> <2.4v|2.7v>"); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + str9xpec_info = bank->driver_priv; + + if (strcmp(args[1], "2.7v") == 0) + { + buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 1); + } + else + { + buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 0); + } + + return ERROR_OK; +} + +int str9xpec_handle_flash_options_lvdsel_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + if (argc < 2) + { + command_print(cmd_ctx, "str9xpec options_lvdsel <bank> <vdd|vdd_vddq>"); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + str9xpec_info = bank->driver_priv; + + if (strcmp(args[1], "vdd_vddq") == 0) + { + buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 1); + } + else + { + buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 0); + } + + return ERROR_OK; +} + +int str9xpec_handle_flash_options_lvdwarn_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + if (argc < 2) + { + command_print(cmd_ctx, "str9xpec options_lvdwarn <bank> <vdd|vdd_vddq>"); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + str9xpec_info = bank->driver_priv; + + if (strcmp(args[1], "vdd_vddq") == 0) + { + buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 1); + } + else + { + buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 0); + } + + return ERROR_OK; +} + +int str9xpec_handle_flash_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + u8 status; + flash_bank_t *bank; + + if (argc < 1) + { + command_print(cmd_ctx, "str9xpec lock <bank>"); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + status = str9xpec_lock_device(bank); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + return ERROR_OK; +} + +int str9xpec_handle_flash_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + u8 status; + flash_bank_t *bank; + + if (argc < 1) + { + command_print(cmd_ctx, "str9xpec unlock <bank>"); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + status = str9xpec_unlock_device(bank); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + return ERROR_OK; +} + +int str9xpec_handle_flash_enable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + u32 chain_pos; + jtag_device_t* dev0; + jtag_device_t* dev2; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + if (argc < 1) + { + command_print(cmd_ctx, "str9xpec enable_turbo <bank>"); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + str9xpec_info = bank->driver_priv; + + chain_pos = str9xpec_info->chain_pos; + + /* remove arm core from chain - enter turbo mode */ + + str9xpec_set_instr(chain_pos+2, 0xD, TAP_RTI); + jtag_execute_queue(); + + /* modify scan chain - str9 core has been removed */ + dev0 = jtag_get_device(chain_pos); + str9xpec_info->devarm = jtag_get_device(chain_pos+1); + dev2 = jtag_get_device(chain_pos+2); + dev0->next = dev2; + jtag_num_devices--; + + return ERROR_OK; +} + +int str9xpec_handle_flash_disable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + u32 chain_pos; + jtag_device_t* dev0; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + if (argc < 1) + { + command_print(cmd_ctx, "str9xpec disable_turbo <bank>"); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + str9xpec_info = bank->driver_priv; + + chain_pos = str9xpec_info->chain_pos; + + dev0 = jtag_get_device(chain_pos); + + /* exit turbo mode via TLR */ + str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_TLR); + jtag_execute_queue(); + + /* restore previous scan chain */ + if( str9xpec_info->devarm ) { + dev0->next = str9xpec_info->devarm; + jtag_num_devices++; + str9xpec_info->devarm = NULL; + } + + return ERROR_OK; +} diff --git a/src/helper/command.c b/src/helper/command.c index f13a86c..15cddcd 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -1,607 +1,607 @@ -/***************************************************************************
- * Copyright (C) 2005 by Dominic Rath *
- * Dominic.Rath@gmx.de *
- * *
- * part of this file is taken from libcli (libcli.sourceforge.net) *
- * Copyright (C) David Parrish (david@dparrish.com) *
- * *
- * 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 "command.h"
-
-#include "log.h"
-#include "time_support.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <unistd.h>
-
-void command_print_help_line(command_context_t* context, struct command_s *command, int indent);
-
-int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-int build_unique_lengths(command_context_t *context, command_t *commands)
-{
- command_t *c, *p;
-
- /* iterate through all commands */
- for (c = commands; c; c = c->next)
- {
- /* find out how many characters are required to uniquely identify a command */
- for (c->unique_len = 1; c->unique_len <= strlen(c->name); c->unique_len++)
- {
- int foundmatch = 0;
-
- /* for every command, see if the current length is enough */
- for (p = commands; p; p = p->next)
- {
- /* ignore the command itself */
- if (c == p)
- continue;
-
- /* compare commands up to the current length */
- if (strncmp(p->name, c->name, c->unique_len) == 0)
- foundmatch++;
- }
-
- /* when none of the commands matched, we've found the minimum length required */
- if (!foundmatch)
- break;
- }
-
- /* if the current command has children, build the unique lengths for them */
- if (c->children)
- build_unique_lengths(context, c->children);
- }
-
- return ERROR_OK;
-}
-
-/* Avoid evaluating this each time we add a command. Reduces overhead from O(n^2) to O(n).
- * Makes a difference on ARM7 types machines and is not observable on GHz machines.
- */
-static int unique_length_dirty = 1;
-
-command_t* register_command(command_context_t *context, command_t *parent, char *name, int (*handler)(struct command_context_s *context, char* name, char** args, int argc), enum command_mode mode, char *help)
-{
- command_t *c, *p;
- unique_length_dirty = 1;
-
- if (!context || !name)
- return NULL;
-
- c = malloc(sizeof(command_t));
-
- c->name = strdup(name);
- c->parent = parent;
- c->children = NULL;
- c->handler = handler;
- c->mode = mode;
- if (help)
- c->help = strdup(help);
- else
- c->help = NULL;
- c->unique_len = 0;
- c->next = NULL;
-
- /* place command in tree */
- if (parent)
- {
- if (parent->children)
- {
- /* find last child */
- for (p = parent->children; p && p->next; p = p->next);
- if (p)
- p->next = c;
- }
- else
- {
- parent->children = c;
- }
- }
- else
- {
- if (context->commands)
- {
- /* find last command */
- for (p = context->commands; p && p->next; p = p->next);
- if (p)
- p->next = c;
- }
- else
- {
- context->commands = c;
- }
- }
-
- return c;
-}
-
-int unregister_command(command_context_t *context, char *name)
-{
- unique_length_dirty = 1;
-
- command_t *c, *p = NULL, *c2;
-
- if ((!context) || (!name))
- return ERROR_INVALID_ARGUMENTS;
-
- /* find command */
- for (c = context->commands; c; c = c->next)
- {
- if (strcmp(name, c->name) == 0)
- {
- /* unlink command */
- if (p)
- {
- p->next = c->next;
- }
- else
- {
- context->commands = c->next;
- }
-
- /* unregister children */
- if (c->children)
- {
- for (c2 = c->children; c2; c2 = c2->next)
- {
- free(c2->name);
- if (c2->help)
- free(c2->help);
- free(c2);
- }
- }
-
- /* delete command */
- free(c->name);
- if (c->help)
- free(c->help);
- free(c);
- }
-
- /* remember the last command for unlinking */
- p = c;
- }
-
- return ERROR_OK;
-}
-
-int parse_line(char *line, char *words[], int max_words)
-{
- int nwords = 0;
- char *p = line;
- char *word_start = line;
- int inquote = 0;
-
- while (nwords < max_words - 1)
- {
- /* check if we reached
- * a terminating NUL
- * a matching closing quote character " or '
- * we're inside a word but not a quote, and the current character is whitespace
- */
- if (!*p || *p == inquote || (word_start && !inquote && isspace(*p)))
- {
- /* we're inside a word or quote, and reached its end*/
- if (word_start)
- {
- int len;
- char *word_end=p;
-
- /* This will handle extra whitespace within quotes */
- while (isspace(*word_start)&&(word_start<word_end))
- word_start++;
- while (isspace(*(word_end-1))&&(word_start<word_end))
- word_end--;
- len = word_end - word_start;
-
- if (len>0)
- {
- /* copy the word */
- memcpy(words[nwords] = malloc(len + 1), word_start, len);
- /* add terminating NUL */
- words[nwords++][len] = 0;
- }
- }
- /* we're done parsing the line */
- if (!*p)
- break;
-
- /* skip over trailing quote or whitespace*/
- if (inquote || isspace(*p))
- p++;
- while (isspace(*p))
- p++;
-
- inquote = 0;
- word_start = 0;
- }
- else if (*p == '"' || *p == '\'')
- {
- /* we've reached the beginning of a quote */
- inquote = *p++;
- word_start = p;
- }
- else
- {
- /* we've reached the beginning of a new word */
- if (!word_start)
- word_start = p;
-
- /* normal character, skip */
- p++;
- }
- }
-
- return nwords;
-}
-
-void command_print(command_context_t *context, char *format, ...)
-{
- char *buffer = NULL;
- int n, size = 0;
- char *p;
-
- /* process format string */
- for (;;)
- {
- va_list ap;
- va_start(ap, format);
- if (!buffer || (n = vsnprintf(buffer, size, format, ap)) >= size)
- {
- /* increase buffer until it fits the whole string */
- if (!(p = realloc(buffer, size += 4096)))
- {
- /* gotta free up */
- if (buffer)
- free(buffer);
- va_end(ap);
- return;
- }
-
- buffer = p;
-
- va_end(ap);
- continue;
- }
- va_end(ap);
- break;
- }
-
- /* vsnprintf failed */
- if (n < 0)
- {
- if (buffer)
- free(buffer);
- return;
- }
-
- p = buffer;
-
- /* process lines in buffer */
- do {
- char *next = strchr(p, '\n');
-
- if (next)
- *next++ = 0;
-
- if (context->output_handler)
- context->output_handler(context, p);
-
- p = next;
- } while (p);
-
- if (buffer)
- free(buffer);
-}
-
-int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word)
-{
- command_t *c;
-
- if (unique_length_dirty)
- {
- unique_length_dirty = 0;
- /* update unique lengths */
- build_unique_lengths(context, context->commands);
- }
-
- for (c = commands; c; c = c->next)
- {
- if (strncasecmp(c->name, words[start_word], c->unique_len))
- continue;
-
- if (strncasecmp(c->name, words[start_word], strlen(words[start_word])))
- continue;
-
- if ((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode) )
- {
- if (!c->children)
- {
- if (!c->handler)
- {
- command_print(context, "No handler for command");
- break;
- }
- else
- {
- int retval = c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);
- if (retval == ERROR_COMMAND_SYNTAX_ERROR)
- {
- command_print(context, "Syntax error:");
- command_print_help_line(context, c, 0);
- }
- return retval;
- }
- }
- else
- {
- if (start_word == num_words - 1)
- {
- command_print(context, "Incomplete command");
- break;
- }
- return find_and_run_command(context, c->children, words, num_words, start_word + 1);
- }
- }
- }
-
- command_print(context, "Command %s not found", words[start_word]);
- return ERROR_OK;
-}
-
-int command_run_line(command_context_t *context, char *line)
-{
- int nwords;
- char *words[128] = {0};
- int retval;
- int i;
-
- if ((!context) || (!line))
- return ERROR_INVALID_ARGUMENTS;
-
- /* skip preceding whitespace */
- while (isspace(*line))
- line++;
-
- /* empty line, ignore */
- if (!*line)
- return ERROR_OK;
-
- /* ignore comments */
- if (*line && (line[0] == '#'))
- return ERROR_OK;
-
- if (context->echo)
- {
- command_print(context, "%s", line);
- }
-
- nwords = parse_line(line, words, sizeof(words) / sizeof(words[0]));
-
- if (nwords > 0)
- retval = find_and_run_command(context, context->commands, words, nwords, 0);
- else
- return ERROR_INVALID_ARGUMENTS;
-
- for (i = 0; i < nwords; i++)
- free(words[i]);
-
- return retval;
-}
-
-int command_run_file(command_context_t *context, FILE *file, enum command_mode mode)
-{
- int retval = ERROR_OK;
- int old_command_mode;
- char *buffer=malloc(4096);
- if (buffer==NULL)
- {
- return ERROR_INVALID_ARGUMENTS;
- }
-
- old_command_mode = context->mode;
- context->mode = mode;
-
- while (fgets(buffer, 4096, file))
- {
- char *p;
- char *cmd, *end;
-
- /* stop processing line after a comment (#, !) or a LF, CR were encountered */
- if ((p = strpbrk(buffer, "#!\r\n")))
- *p = 0;
-
- /* skip over leading whitespace */
- cmd = buffer;
- while (isspace(*cmd))
- cmd++;
-
- /* empty (all whitespace) line? */
- if (!*cmd)
- continue;
-
- /* search the end of the current line, ignore trailing whitespace */
- for (p = end = cmd; *p; p++)
- if (!isspace(*p))
- end = p;
-
- /* terminate end */
- *++end = 0;
- if (strcasecmp(cmd, "quit") == 0)
- break;
-
- /* run line */
- if ((retval = command_run_line(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION)
- break;
- }
-
- context->mode = old_command_mode;
-
-
- free(buffer);
-
- return retval;
-}
-
-void command_print_help_line(command_context_t* context, struct command_s *command, int indent)
-{
- command_t *c;
- char indents[32] = {0};
- char *help = "no help available";
- char name_buf[64];
- int i;
-
- for (i = 0; i < indent; i+=2)
- {
- indents[i*2] = ' ';
- indents[i*2+1] = '-';
- }
- indents[i*2] = 0;
-
- if (command->help)
- help = command->help;
-
- snprintf(name_buf, 64, command->name);
- strncat(name_buf, indents, 64);
- command_print(context, "%20s\t%s", name_buf, help);
-
- if (command->children)
- {
- for (c = command->children; c; c = c->next)
- {
- command_print_help_line(context, c, indent + 1);
- }
- }
-}
-
-int command_print_help(command_context_t* context, char* name, char** args, int argc)
-{
- command_t *c;
-
- for (c = context->commands; c; c = c->next)
- {
- if (argc == 1)
- {
- if (strncasecmp(c->name, args[0], c->unique_len))
- continue;
-
- if (strncasecmp(c->name, args[0], strlen(args[0])))
- continue;
- }
-
- command_print_help_line(context, c, 0);
- }
-
- return ERROR_OK;
-}
-
-void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, char* line), void *priv)
-{
- context->output_handler = output_handler;
- context->output_handler_priv = priv;
-}
-
-command_context_t* copy_command_context(command_context_t* context)
-{
- command_context_t* copy_context = malloc(sizeof(command_context_t));
-
- *copy_context = *context;
-
- return copy_context;
-}
-
-int command_done(command_context_t *context)
-{
- free(context);
- context = NULL;
-
- return ERROR_OK;
-}
-
-command_context_t* command_init()
-{
- command_context_t* context = malloc(sizeof(command_context_t));
-
- context->mode = COMMAND_EXEC;
- context->commands = NULL;
- context->current_target = 0;
- context->echo = 0;
- context->output_handler = NULL;
- context->output_handler_priv = NULL;
-
- register_command(context, NULL, "help", command_print_help,
- COMMAND_EXEC, "display this help");
-
- register_command(context, NULL, "sleep", handle_sleep_command,
- COMMAND_ANY, "sleep for <n> milliseconds");
-
- register_command(context, NULL, "time", handle_time_command,
- COMMAND_ANY, "time <cmd + args> - execute <cmd + args> and print time it took");
-
- return context;
-}
-
-/* sleep command sleeps for <n> miliseconds
- * this is useful in target startup scripts
- */
-int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- unsigned long duration = 0;
-
- if (argc == 1)
- {
- duration = strtoul(args[0], NULL, 0);
- usleep(duration * 1000);
- }
-
- return ERROR_OK;
-}
-
-int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc<1)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- duration_t duration;
- char *duration_text;
- int retval;
-
- duration_start_measure(&duration);
-
- retval = find_and_run_command(cmd_ctx, cmd_ctx->commands, args, argc, 0);
-
- duration_stop_measure(&duration, &duration_text);
-
- float t=duration.duration.tv_sec;
- t+=((float)duration.duration.tv_usec / 1000000.0);
- command_print(cmd_ctx, "%s took %fs", args[0], t);
-
- free(duration_text);
-
- return retval;
-}
+/*************************************************************************** + * Copyright (C) 2005 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * part of this file is taken from libcli (libcli.sourceforge.net) * + * Copyright (C) David Parrish (david@dparrish.com) * + * * + * 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 "command.h" + +#include "log.h" +#include "time_support.h" + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <stdarg.h> +#include <stdio.h> +#include <unistd.h> + +void command_print_help_line(command_context_t* context, struct command_s *command, int indent); + +int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int build_unique_lengths(command_context_t *context, command_t *commands) +{ + command_t *c, *p; + + /* iterate through all commands */ + for (c = commands; c; c = c->next) + { + /* find out how many characters are required to uniquely identify a command */ + for (c->unique_len = 1; c->unique_len <= strlen(c->name); c->unique_len++) + { + int foundmatch = 0; + + /* for every command, see if the current length is enough */ + for (p = commands; p; p = p->next) + { + /* ignore the command itself */ + if (c == p) + continue; + + /* compare commands up to the current length */ + if (strncmp(p->name, c->name, c->unique_len) == 0) + foundmatch++; + } + + /* when none of the commands matched, we've found the minimum length required */ + if (!foundmatch) + break; + } + + /* if the current command has children, build the unique lengths for them */ + if (c->children) + build_unique_lengths(context, c->children); + } + + return ERROR_OK; +} + +/* Avoid evaluating this each time we add a command. Reduces overhead from O(n^2) to O(n). + * Makes a difference on ARM7 types machines and is not observable on GHz machines. + */ +static int unique_length_dirty = 1; + +command_t* register_command(command_context_t *context, command_t *parent, char *name, int (*handler)(struct command_context_s *context, char* name, char** args, int argc), enum command_mode mode, char *help) +{ + command_t *c, *p; + unique_length_dirty = 1; + + if (!context || !name) + return NULL; + + c = malloc(sizeof(command_t)); + + c->name = strdup(name); + c->parent = parent; + c->children = NULL; + c->handler = handler; + c->mode = mode; + if (help) + c->help = strdup(help); + else + c->help = NULL; + c->unique_len = 0; + c->next = NULL; + + /* place command in tree */ + if (parent) + { + if (parent->children) + { + /* find last child */ + for (p = parent->children; p && p->next; p = p->next); + if (p) + p->next = c; + } + else + { + parent->children = c; + } + } + else + { + if (context->commands) + { + /* find last command */ + for (p = context->commands; p && p->next; p = p->next); + if (p) + p->next = c; + } + else + { + context->commands = c; + } + } + + return c; +} + +int unregister_command(command_context_t *context, char *name) +{ + unique_length_dirty = 1; + + command_t *c, *p = NULL, *c2; + + if ((!context) || (!name)) + return ERROR_INVALID_ARGUMENTS; + + /* find command */ + for (c = context->commands; c; c = c->next) + { + if (strcmp(name, c->name) == 0) + { + /* unlink command */ + if (p) + { + p->next = c->next; + } + else + { + context->commands = c->next; + } + + /* unregister children */ + if (c->children) + { + for (c2 = c->children; c2; c2 = c2->next) + { + free(c2->name); + if (c2->help) + free(c2->help); + free(c2); + } + } + + /* delete command */ + free(c->name); + if (c->help) + free(c->help); + free(c); + } + + /* remember the last command for unlinking */ + p = c; + } + + return ERROR_OK; +} + +int parse_line(char *line, char *words[], int max_words) +{ + int nwords = 0; + char *p = line; + char *word_start = line; + int inquote = 0; + + while (nwords < max_words - 1) + { + /* check if we reached + * a terminating NUL + * a matching closing quote character " or ' + * we're inside a word but not a quote, and the current character is whitespace + */ + if (!*p || *p == inquote || (word_start && !inquote && isspace(*p))) + { + /* we're inside a word or quote, and reached its end*/ + if (word_start) + { + int len; + char *word_end=p; + + /* This will handle extra whitespace within quotes */ + while (isspace(*word_start)&&(word_start<word_end)) + word_start++; + while (isspace(*(word_end-1))&&(word_start<word_end)) + word_end--; + len = word_end - word_start; + + if (len>0) + { + /* copy the word */ + memcpy(words[nwords] = malloc(len + 1), word_start, len); + /* add terminating NUL */ + words[nwords++][len] = 0; + } + } + /* we're done parsing the line */ + if (!*p) + break; + + /* skip over trailing quote or whitespace*/ + if (inquote || isspace(*p)) + p++; + while (isspace(*p)) + p++; + + inquote = 0; + word_start = 0; + } + else if (*p == '"' || *p == '\'') + { + /* we've reached the beginning of a quote */ + inquote = *p++; + word_start = p; + } + else + { + /* we've reached the beginning of a new word */ + if (!word_start) + word_start = p; + + /* normal character, skip */ + p++; + } + } + + return nwords; +} + +void command_print(command_context_t *context, char *format, ...) +{ + char *buffer = NULL; + int n, size = 0; + char *p; + + /* process format string */ + for (;;) + { + va_list ap; + va_start(ap, format); + if (!buffer || (n = vsnprintf(buffer, size, format, ap)) >= size) + { + /* increase buffer until it fits the whole string */ + if (!(p = realloc(buffer, size += 4096))) + { + /* gotta free up */ + if (buffer) + free(buffer); + va_end(ap); + return; + } + + buffer = p; + + va_end(ap); + continue; + } + va_end(ap); + break; + } + + /* vsnprintf failed */ + if (n < 0) + { + if (buffer) + free(buffer); + return; + } + + p = buffer; + + /* process lines in buffer */ + do { + char *next = strchr(p, '\n'); + + if (next) + *next++ = 0; + + if (context->output_handler) + context->output_handler(context, p); + + p = next; + } while (p); + + if (buffer) + free(buffer); +} + +int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word) +{ + command_t *c; + + if (unique_length_dirty) + { + unique_length_dirty = 0; + /* update unique lengths */ + build_unique_lengths(context, context->commands); + } + + for (c = commands; c; c = c->next) + { + if (strncasecmp(c->name, words[start_word], c->unique_len)) + continue; + + if (strncasecmp(c->name, words[start_word], strlen(words[start_word]))) + continue; + + if ((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode) ) + { + if (!c->children) + { + if (!c->handler) + { + command_print(context, "No handler for command"); + break; + } + else + { + int retval = c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1); + if (retval == ERROR_COMMAND_SYNTAX_ERROR) + { + command_print(context, "Syntax error:"); + command_print_help_line(context, c, 0); + } + return retval; + } + } + else + { + if (start_word == num_words - 1) + { + command_print(context, "Incomplete command"); + break; + } + return find_and_run_command(context, c->children, words, num_words, start_word + 1); + } + } + } + + command_print(context, "Command %s not found", words[start_word]); + return ERROR_OK; +} + +int command_run_line(command_context_t *context, char *line) +{ + int nwords; + char *words[128] = {0}; + int retval; + int i; + + if ((!context) || (!line)) + return ERROR_INVALID_ARGUMENTS; + + /* skip preceding whitespace */ + while (isspace(*line)) + line++; + + /* empty line, ignore */ + if (!*line) + return ERROR_OK; + + /* ignore comments */ + if (*line && (line[0] == '#')) + return ERROR_OK; + + if (context->echo) + { + command_print(context, "%s", line); + } + + nwords = parse_line(line, words, sizeof(words) / sizeof(words[0])); + + if (nwords > 0) + retval = find_and_run_command(context, context->commands, words, nwords, 0); + else + return ERROR_INVALID_ARGUMENTS; + + for (i = 0; i < nwords; i++) + free(words[i]); + + return retval; +} + +int command_run_file(command_context_t *context, FILE *file, enum command_mode mode) +{ + int retval = ERROR_OK; + int old_command_mode; + char *buffer=malloc(4096); + if (buffer==NULL) + { + return ERROR_INVALID_ARGUMENTS; + } + + old_command_mode = context->mode; + context->mode = mode; + + while (fgets(buffer, 4096, file)) + { + char *p; + char *cmd, *end; + + /* stop processing line after a comment (#, !) or a LF, CR were encountered */ + if ((p = strpbrk(buffer, "#!\r\n"))) + *p = 0; + + /* skip over leading whitespace */ + cmd = buffer; + while (isspace(*cmd)) + cmd++; + + /* empty (all whitespace) line? */ + if (!*cmd) + continue; + + /* search the end of the current line, ignore trailing whitespace */ + for (p = end = cmd; *p; p++) + if (!isspace(*p)) + end = p; + + /* terminate end */ + *++end = 0; + if (strcasecmp(cmd, "quit") == 0) + break; + + /* run line */ + if ((retval = command_run_line(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION) + break; + } + + context->mode = old_command_mode; + + + free(buffer); + + return retval; +} + +void command_print_help_line(command_context_t* context, struct command_s *command, int indent) +{ + command_t *c; + char indents[32] = {0}; + char *help = "no help available"; + char name_buf[64]; + int i; + + for (i = 0; i < indent; i+=2) + { + indents[i*2] = ' '; + indents[i*2+1] = '-'; + } + indents[i*2] = 0; + + if (command->help) + help = command->help; + + snprintf(name_buf, 64, command->name); + strncat(name_buf, indents, 64); + command_print(context, "%20s\t%s", name_buf, help); + + if (command->children) + { + for (c = command->children; c; c = c->next) + { + command_print_help_line(context, c, indent + 1); + } + } +} + +int command_print_help(command_context_t* context, char* name, char** args, int argc) +{ + command_t *c; + + for (c = context->commands; c; c = c->next) + { + if (argc == 1) + { + if (strncasecmp(c->name, args[0], c->unique_len)) + continue; + + if (strncasecmp(c->name, args[0], strlen(args[0]))) + continue; + } + + command_print_help_line(context, c, 0); + } + + return ERROR_OK; +} + +void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, char* line), void *priv) +{ + context->output_handler = output_handler; + context->output_handler_priv = priv; +} + +command_context_t* copy_command_context(command_context_t* context) +{ + command_context_t* copy_context = malloc(sizeof(command_context_t)); + + *copy_context = *context; + + return copy_context; +} + +int command_done(command_context_t *context) +{ + free(context); + context = NULL; + + return ERROR_OK; +} + +command_context_t* command_init() +{ + command_context_t* context = malloc(sizeof(command_context_t)); + + context->mode = COMMAND_EXEC; + context->commands = NULL; + context->current_target = 0; + context->echo = 0; + context->output_handler = NULL; + context->output_handler_priv = NULL; + + register_command(context, NULL, "help", command_print_help, + COMMAND_EXEC, "display this help"); + + register_command(context, NULL, "sleep", handle_sleep_command, + COMMAND_ANY, "sleep for <n> milliseconds"); + + register_command(context, NULL, "time", handle_time_command, + COMMAND_ANY, "time <cmd + args> - execute <cmd + args> and print time it took"); + + return context; +} + +/* sleep command sleeps for <n> miliseconds + * this is useful in target startup scripts + */ +int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + unsigned long duration = 0; + + if (argc == 1) + { + duration = strtoul(args[0], NULL, 0); + usleep(duration * 1000); + } + + return ERROR_OK; +} + +int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc<1) + return ERROR_COMMAND_SYNTAX_ERROR; + + duration_t duration; + char *duration_text; + int retval; + + duration_start_measure(&duration); + + retval = find_and_run_command(cmd_ctx, cmd_ctx->commands, args, argc, 0); + + duration_stop_measure(&duration, &duration_text); + + float t=duration.duration.tv_sec; + t+=((float)duration.duration.tv_usec / 1000000.0); + command_print(cmd_ctx, "%s took %fs", args[0], t); + + free(duration_text); + + return retval; +} diff --git a/src/helper/configuration.c b/src/helper/configuration.c index 1bed1e0..9b9c181 100644 --- a/src/helper/configuration.c +++ b/src/helper/configuration.c @@ -1,104 +1,104 @@ -/***************************************************************************
- * Copyright (C) 2004, 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 "types.h"
-#include "command.h"
-#include "configuration.h"
-#include "log.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-static size_t num_config_files;
-static char** config_file_names;
-
-static size_t num_script_dirs;
-static char** script_search_dirs;
-
-
-void add_script_search_dir (const char *dir)
-{
- num_script_dirs++;
- script_search_dirs = (char **)realloc(script_search_dirs, (num_script_dirs+1) * sizeof (char *));
-
- script_search_dirs[num_script_dirs-1] = strdup(dir);
- script_search_dirs[num_script_dirs] = NULL;
-}
-
-void add_config_file_name (const char *cfg)
-{
- num_config_files++;
- config_file_names = (char **)realloc(config_file_names, (num_config_files+1) * sizeof (char *));
-
- config_file_names[num_config_files-1] = strdup(cfg);
- config_file_names[num_config_files] = NULL;
-}
-
-FILE *open_file_from_path (command_context_t *cmd_ctx, char *file, char *mode)
-{
- FILE *fp = NULL;
- char **search_dirs = script_search_dirs;
- char *dir;
- char full_path[1024];
-
- /* Check absolute and relative to current working dir first.
- * This keeps full_path reporting belowing working. */
- snprintf(full_path, 1024, "%s", file);
- fp = fopen(full_path, mode);
-
- while (!fp)
- {
- dir = *search_dirs++;
-
- if (!dir)
- break;
-
- snprintf(full_path, 1024, "%s/%s", dir, file);
- fp = fopen(full_path, mode);
- }
-
- if (fp)
- command_print(cmd_ctx, "opened %s", full_path);
-
- return fp;
-}
-
-int parse_config_file(struct command_context_s *cmd_ctx)
-{
- char **cfg;
- FILE *config_file;
-
- if (!config_file_names)
- add_config_file_name ("script openocd.cfg");
-
- cfg = config_file_names;
-
- while (*cfg)
- {
- command_run_line(cmd_ctx, *cfg);
- cfg++;
- }
-
- return ERROR_OK;
-}
+/*************************************************************************** + * Copyright (C) 2004, 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 "types.h" +#include "command.h" +#include "configuration.h" +#include "log.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static size_t num_config_files; +static char** config_file_names; + +static size_t num_script_dirs; +static char** script_search_dirs; + + +void add_script_search_dir (const char *dir) +{ + num_script_dirs++; + script_search_dirs = (char **)realloc(script_search_dirs, (num_script_dirs+1) * sizeof (char *)); + + script_search_dirs[num_script_dirs-1] = strdup(dir); + script_search_dirs[num_script_dirs] = NULL; +} + +void add_config_file_name (const char *cfg) +{ + num_config_files++; + config_file_names = (char **)realloc(config_file_names, (num_config_files+1) * sizeof (char *)); + + config_file_names[num_config_files-1] = strdup(cfg); + config_file_names[num_config_files] = NULL; +} + +FILE *open_file_from_path (command_context_t *cmd_ctx, char *file, char *mode) +{ + FILE *fp = NULL; + char **search_dirs = script_search_dirs; + char *dir; + char full_path[1024]; + + /* Check absolute and relative to current working dir first. + * This keeps full_path reporting belowing working. */ + snprintf(full_path, 1024, "%s", file); + fp = fopen(full_path, mode); + + while (!fp) + { + dir = *search_dirs++; + + if (!dir) + break; + + snprintf(full_path, 1024, "%s/%s", dir, file); + fp = fopen(full_path, mode); + } + + if (fp) + command_print(cmd_ctx, "opened %s", full_path); + + return fp; +} + +int parse_config_file(struct command_context_s *cmd_ctx) +{ + char **cfg; + FILE *config_file; + + if (!config_file_names) + add_config_file_name ("script openocd.cfg"); + + cfg = config_file_names; + + while (*cfg) + { + command_run_line(cmd_ctx, *cfg); + cfg++; + } + + return ERROR_OK; +} diff --git a/src/helper/log.c b/src/helper/log.c index 90077ea..861e4b3 100644 --- a/src/helper/log.c +++ b/src/helper/log.c @@ -1,248 +1,248 @@ -/***************************************************************************
- * 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 "log.h"
-#include "configuration.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <time.h>
-
-int debug_level = -1;
-
-static FILE* log_output;
-static log_callback_t *log_callbacks = NULL;
-
-static time_t start;
-
-static char *log_strings[5] =
-{
- "User: ",
- "Error: ",
- "Warning:",
- "Info: ",
- "Debug: "
-};
-
-void log_printf(enum log_levels level, const char *file, int line, const char *function, const char *format, ...)
-{
- static int count = 0;
- count++;
- va_list args;
- char buffer[512];
- log_callback_t *cb;
-
- if (level > debug_level)
- return;
-
- va_start(args, format);
- vsnprintf(buffer, 512, format, args);
- va_end(args);
-
- if (level == LOG_OUTPUT)
- {
- /* do not prepend any headers, just print out what we were given and return */
- fputs(buffer, log_output);
- fflush(log_output);
- return;
- }
-
- char *f = strrchr(file, '/');
- if (f != NULL)
- file = f + 1;
-
- if (debug_level >= LOG_DEBUG)
- {
- /* print with count and time information */
- time_t t=time(NULL)-start;
- fprintf(log_output, "%s %d %ld %s:%d %s(): %s\n", log_strings[level+1], count, t, file, line, function, buffer);
- }
- else
- {
- /* do not print count and time */
- fprintf(log_output, "%s %s:%d %s(): %s\n", log_strings[level+1], file, line, function, buffer);
- }
-
- fflush(log_output);
-
- /* Never forward LOG_DEBUG, too verbose and they can be found in the log if need be */
- if (level <= LOG_INFO)
- {
- for (cb = log_callbacks; cb; cb = cb->next)
- {
- va_start(args, format);
- cb->fn(cb->priv, file, line, function, format, args);
- va_end(args);
- }
- }
-}
-
-/* change the current debug level on the fly
- * 0: only ERRORS
- * 1: + WARNINGS
- * 2: + INFORMATIONAL MSGS
- * 3: + DEBUG MSGS
- */
-int handle_debug_level_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 0)
- command_print(cmd_ctx, "debug_level: %i", debug_level);
-
- if (argc > 0)
- debug_level = strtoul(args[0], NULL, 0);
-
- if (debug_level < 0)
- debug_level = 0;
-
- if (debug_level > 3)
- debug_level = 3;
-
- return ERROR_OK;
-}
-
-int handle_log_output_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 1)
- {
- FILE* file = fopen(args[0], "w");
-
- if (file)
- {
- log_output = file;
- }
- }
-
- return ERROR_OK;
-}
-
-int log_register_commands(struct command_context_s *cmd_ctx)
-{
- start = time(NULL);
- register_command(cmd_ctx, NULL, "log_output", handle_log_output_command,
- COMMAND_ANY, "redirect logging to <file> (default: stderr)");
- register_command(cmd_ctx, NULL, "debug_level", handle_debug_level_command,
- COMMAND_ANY, "adjust debug level <0-3>");
-
- return ERROR_OK;
-}
-
-int log_init(struct command_context_s *cmd_ctx)
-{
- /* set defaults for daemon configuration, if not set by cmdline or cfgfile */
- if (debug_level == -1)
- debug_level = LOG_INFO;
-
- if (log_output == NULL)
- {
- log_output = stderr;
- }
-
- return ERROR_OK;
-}
-
-int set_log_output(struct command_context_s *cmd_ctx, FILE *output)
-{
- log_output = output;
- return ERROR_OK;
-}
-
-/* add/remove log callback handler */
-int log_add_callback(log_callback_fn fn, void *priv)
-{
- log_callback_t *cb;
-
- /* prevent the same callback to be registered more than once, just for sure */
- for (cb = log_callbacks; cb; cb = cb->next)
- {
- if (cb->fn == fn && cb->priv == priv)
- return ERROR_INVALID_ARGUMENTS;
- }
-
- /* alloc memory, it is safe just to return in case of an error, no need for the caller to check this */
- if ((cb = malloc(sizeof(log_callback_t))) == NULL)
- return ERROR_BUF_TOO_SMALL;
-
- /* add item to the beginning of the linked list */
- cb->fn = fn;
- cb->priv = priv;
- cb->next = log_callbacks;
- log_callbacks = cb;
-
- return ERROR_OK;
-}
-
-int log_remove_callback(log_callback_fn fn, void *priv)
-{
- log_callback_t *cb, **p;
-
- for (p = &log_callbacks; cb = *p; p = &(*p)->next)
- {
- if (cb->fn == fn && cb->priv == priv)
- {
- *p = cb->next;
- free(cb);
- return ERROR_OK;
- }
- }
-
- /* no such item */
- return ERROR_INVALID_ARGUMENTS;
-}
-
-/* return allocated string w/printf() result */
-char *alloc_printf(const char *fmt, va_list ap)
-{
- char *string = NULL;
-
- /* start by 0 to exercise all the code paths. Need minimum 2 bytes to
- * fit 1 char and 0 terminator. */
- int size = 0;
- int first = 1;
- for (;;)
- {
- if ((string == NULL) || (!first))
- {
- size = size * 2 + 2;
- char *t = string;
- string = realloc(string, size);
- if (string == NULL)
- {
- if (t != NULL)
- free(t);
- return NULL;
- }
- }
-
- int ret;
- ret = vsnprintf(string, size, fmt, ap);
- /* NB! The result of the vsnprintf() might be an *EMPTY* string! */
- if ((ret >= 0) && ((ret + 1) < size))
- {
- return string;
- }
- /* there was just enough or not enough space, allocate more. */
- first = 0;
- }
-}
+/*************************************************************************** + * 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 "log.h" +#include "configuration.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <time.h> + +int debug_level = -1; + +static FILE* log_output; +static log_callback_t *log_callbacks = NULL; + +static time_t start; + +static char *log_strings[5] = +{ + "User: ", + "Error: ", + "Warning:", + "Info: ", + "Debug: " +}; + +void log_printf(enum log_levels level, const char *file, int line, const char *function, const char *format, ...) +{ + static int count = 0; + count++; + va_list args; + char buffer[512]; + log_callback_t *cb; + + if (level > debug_level) + return; + + va_start(args, format); + vsnprintf(buffer, 512, format, args); + va_end(args); + + if (level == LOG_OUTPUT) + { + /* do not prepend any headers, just print out what we were given and return */ + fputs(buffer, log_output); + fflush(log_output); + return; + } + + char *f = strrchr(file, '/'); + if (f != NULL) + file = f + 1; + + if (debug_level >= LOG_DEBUG) + { + /* print with count and time information */ + time_t t=time(NULL)-start; + fprintf(log_output, "%s %d %ld %s:%d %s(): %s\n", log_strings[level+1], count, t, file, line, function, buffer); + } + else + { + /* do not print count and time */ + fprintf(log_output, "%s %s:%d %s(): %s\n", log_strings[level+1], file, line, function, buffer); + } + + fflush(log_output); + + /* Never forward LOG_DEBUG, too verbose and they can be found in the log if need be */ + if (level <= LOG_INFO) + { + for (cb = log_callbacks; cb; cb = cb->next) + { + va_start(args, format); + cb->fn(cb->priv, file, line, function, format, args); + va_end(args); + } + } +} + +/* change the current debug level on the fly + * 0: only ERRORS + * 1: + WARNINGS + * 2: + INFORMATIONAL MSGS + * 3: + DEBUG MSGS + */ +int handle_debug_level_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 0) + command_print(cmd_ctx, "debug_level: %i", debug_level); + + if (argc > 0) + debug_level = strtoul(args[0], NULL, 0); + + if (debug_level < 0) + debug_level = 0; + + if (debug_level > 3) + debug_level = 3; + + return ERROR_OK; +} + +int handle_log_output_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 1) + { + FILE* file = fopen(args[0], "w"); + + if (file) + { + log_output = file; + } + } + + return ERROR_OK; +} + +int log_register_commands(struct command_context_s *cmd_ctx) +{ + start = time(NULL); + register_command(cmd_ctx, NULL, "log_output", handle_log_output_command, + COMMAND_ANY, "redirect logging to <file> (default: stderr)"); + register_command(cmd_ctx, NULL, "debug_level", handle_debug_level_command, + COMMAND_ANY, "adjust debug level <0-3>"); + + return ERROR_OK; +} + +int log_init(struct command_context_s *cmd_ctx) +{ + /* set defaults for daemon configuration, if not set by cmdline or cfgfile */ + if (debug_level == -1) + debug_level = LOG_INFO; + + if (log_output == NULL) + { + log_output = stderr; + } + + return ERROR_OK; +} + +int set_log_output(struct command_context_s *cmd_ctx, FILE *output) +{ + log_output = output; + return ERROR_OK; +} + +/* add/remove log callback handler */ +int log_add_callback(log_callback_fn fn, void *priv) +{ + log_callback_t *cb; + + /* prevent the same callback to be registered more than once, just for sure */ + for (cb = log_callbacks; cb; cb = cb->next) + { + if (cb->fn == fn && cb->priv == priv) + return ERROR_INVALID_ARGUMENTS; + } + + /* alloc memory, it is safe just to return in case of an error, no need for the caller to check this */ + if ((cb = malloc(sizeof(log_callback_t))) == NULL) + return ERROR_BUF_TOO_SMALL; + + /* add item to the beginning of the linked list */ + cb->fn = fn; + cb->priv = priv; + cb->next = log_callbacks; + log_callbacks = cb; + + return ERROR_OK; +} + +int log_remove_callback(log_callback_fn fn, void *priv) +{ + log_callback_t *cb, **p; + + for (p = &log_callbacks; cb = *p; p = &(*p)->next) + { + if (cb->fn == fn && cb->priv == priv) + { + *p = cb->next; + free(cb); + return ERROR_OK; + } + } + + /* no such item */ + return ERROR_INVALID_ARGUMENTS; +} + +/* return allocated string w/printf() result */ +char *alloc_printf(const char *fmt, va_list ap) +{ + char *string = NULL; + + /* start by 0 to exercise all the code paths. Need minimum 2 bytes to + * fit 1 char and 0 terminator. */ + int size = 0; + int first = 1; + for (;;) + { + if ((string == NULL) || (!first)) + { + size = size * 2 + 2; + char *t = string; + string = realloc(string, size); + if (string == NULL) + { + if (t != NULL) + free(t); + return NULL; + } + } + + int ret; + ret = vsnprintf(string, size, fmt, ap); + /* NB! The result of the vsnprintf() might be an *EMPTY* string! */ + if ((ret >= 0) && ((ret + 1) < size)) + { + return string; + } + /* there was just enough or not enough space, allocate more. */ + first = 0; + } +} diff --git a/src/helper/log.h b/src/helper/log.h index 6105000..6c7c3de 100644 --- a/src/helper/log.h +++ b/src/helper/log.h @@ -1,113 +1,113 @@ -/***************************************************************************
- * 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 ERROR_H
-#define ERROR_H
-
-#include "replacements.h"
-#include "command.h"
-
-#include <stdarg.h>
-
-/* logging priorities
- * LOG_USER - user messages. Could be anything from information
- * to progress messags. These messages do not represent
- * incorrect or unexpected behaviour, just normal execution.
- * LOG_ERROR - fatal errors, that are likely to cause program abort
- * LOG_WARNING - non-fatal errors, that may be resolved later
- * LOG_INFO - state information, etc.
- * LOG_DEBUG - debug statements, execution trace
- */
-enum log_levels
-{
- LOG_OUTPUT = -2,
- LOG_USER = -1,
- LOG_ERROR = 0,
- LOG_WARNING = 1,
- LOG_INFO = 2,
- LOG_DEBUG = 3
-};
-
-extern void log_printf(enum log_levels level, const char *file, int line,
- const char *function, const char *format, ...)
- __attribute__ ((format (printf, 5, 6)));
-extern int log_register_commands(struct command_context_s *cmd_ctx);
-extern int log_init(struct command_context_s *cmd_ctx);
-extern int set_log_output(struct command_context_s *cmd_ctx, FILE *output);
-
-typedef void (*log_callback_fn)(void *priv, const char *file, int line,
- const char *function, const char *format, va_list args);
-
-typedef struct log_callback_s
-{
- log_callback_fn fn;
- void *priv;
- struct log_callback_s *next;
-} log_callback_t;
-
-extern int log_add_callback(log_callback_fn fn, void *priv);
-extern int log_remove_callback(log_callback_fn fn, void *priv);
-
-char *alloc_printf(const char *fmt, va_list ap);
-
-extern int debug_level;
-
-/* Avoid fn call and building parameter list if we're not outputting the information.
- * Matters on feeble CPUs for DEBUG/INFO statements that are involved frequently */
-
-#define DEBUG(expr ...) \
- do { if (debug_level >= LOG_DEBUG) \
- log_printf (LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, expr); \
- } while(0)
-
-#define INFO(expr ...) \
- do { if (debug_level >= LOG_INFO) \
- log_printf (LOG_INFO, __FILE__, __LINE__, __FUNCTION__, expr); \
- } while(0)
-
-#define WARNING(expr ...) \
- do { \
- log_printf (LOG_WARNING, __FILE__, __LINE__, __FUNCTION__, expr); \
- } while(0)
-
-#define ERROR(expr ...) \
- do { \
- log_printf (LOG_ERROR, __FILE__, __LINE__, __FUNCTION__, expr); \
- } while(0)
-
-#define USER(expr ...) \
- do { \
- log_printf (LOG_USER, __FILE__, __LINE__, __FUNCTION__, expr); \
- } while(0)
-
-#define OUTPUT(expr ...) \
- do { \
- log_printf (LOG_OUTPUT, __FILE__, __LINE__, __FUNCTION__, expr); \
- } while(0)
-
-
-/* general failures
- * error codes < 100
- */
-#define ERROR_OK (0)
-#define ERROR_INVALID_ARGUMENTS (-1)
-#define ERROR_NO_CONFIG_FILE (-2)
-#define ERROR_BUF_TOO_SMALL (-3)
-
-#endif /* LOG_H */
+/*************************************************************************** + * 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 ERROR_H +#define ERROR_H + +#include "replacements.h" +#include "command.h" + +#include <stdarg.h> + +/* logging priorities + * LOG_USER - user messages. Could be anything from information + * to progress messags. These messages do not represent + * incorrect or unexpected behaviour, just normal execution. + * LOG_ERROR - fatal errors, that are likely to cause program abort + * LOG_WARNING - non-fatal errors, that may be resolved later + * LOG_INFO - state information, etc. + * LOG_DEBUG - debug statements, execution trace + */ +enum log_levels +{ + LOG_OUTPUT = -2, + LOG_USER = -1, + LOG_ERROR = 0, + LOG_WARNING = 1, + LOG_INFO = 2, + LOG_DEBUG = 3 +}; + +extern void log_printf(enum log_levels level, const char *file, int line, + const char *function, const char *format, ...) + __attribute__ ((format (printf, 5, 6))); +extern int log_register_commands(struct command_context_s *cmd_ctx); +extern int log_init(struct command_context_s *cmd_ctx); +extern int set_log_output(struct command_context_s *cmd_ctx, FILE *output); + +typedef void (*log_callback_fn)(void *priv, const char *file, int line, + const char *function, const char *format, va_list args); + +typedef struct log_callback_s +{ + log_callback_fn fn; + void *priv; + struct log_callback_s *next; +} log_callback_t; + +extern int log_add_callback(log_callback_fn fn, void *priv); +extern int log_remove_callback(log_callback_fn fn, void *priv); + +char *alloc_printf(const char *fmt, va_list ap); + +extern int debug_level; + +/* Avoid fn call and building parameter list if we're not outputting the information. + * Matters on feeble CPUs for DEBUG/INFO statements that are involved frequently */ + +#define DEBUG(expr ...) \ + do { if (debug_level >= LOG_DEBUG) \ + log_printf (LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, expr); \ + } while(0) + +#define INFO(expr ...) \ + do { if (debug_level >= LOG_INFO) \ + log_printf (LOG_INFO, __FILE__, __LINE__, __FUNCTION__, expr); \ + } while(0) + +#define WARNING(expr ...) \ + do { \ + log_printf (LOG_WARNING, __FILE__, __LINE__, __FUNCTION__, expr); \ + } while(0) + +#define ERROR(expr ...) \ + do { \ + log_printf (LOG_ERROR, __FILE__, __LINE__, __FUNCTION__, expr); \ + } while(0) + +#define USER(expr ...) \ + do { \ + log_printf (LOG_USER, __FILE__, __LINE__, __FUNCTION__, expr); \ + } while(0) + +#define OUTPUT(expr ...) \ + do { \ + log_printf (LOG_OUTPUT, __FILE__, __LINE__, __FUNCTION__, expr); \ + } while(0) + + +/* general failures + * error codes < 100 + */ +#define ERROR_OK (0) +#define ERROR_INVALID_ARGUMENTS (-1) +#define ERROR_NO_CONFIG_FILE (-2) +#define ERROR_BUF_TOO_SMALL (-3) + +#endif /* LOG_H */ diff --git a/src/helper/options.c b/src/helper/options.c index 4232cb4..89bf1f9 100644 --- a/src/helper/options.c +++ b/src/helper/options.c @@ -1,153 +1,153 @@ -/***************************************************************************
- * Copyright (C) 2004, 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 "types.h"
-#include "command.h"
-#include "configuration.h"
-#include "log.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <string.h>
-
-
-static int help_flag;
-
-static struct option long_options[] =
-{
- {"help", no_argument, &help_flag, 1},
-
- {"debug", optional_argument, 0, 'd'},
- {"file", required_argument, 0, 'f'},
- {"search", required_argument, 0, 's'},
- {"log_output", required_argument, 0, 'l'},
- {"command", required_argument, 0, 'c'},
-
- {0, 0, 0, 0}
-};
-
-
-
-int configuration_output_handler(struct command_context_s *context, char* line)
-{
- INFO(line);
-
- return ERROR_OK;
-}
-
-
-int parse_cmdline_args(struct command_context_s *cmd_ctx, int argc, char *argv[])
-{
- int c;
- char command_buffer[128];
-
- while (1)
- {
- /* getopt_long stores the option index here. */
- int option_index = 0;
-
- c = getopt_long(argc, argv, "hd::l:f:s:c:", long_options, &option_index);
-
- /* Detect the end of the options. */
- if (c == -1)
- break;
-
- switch (c)
- {
- case 0:
- break;
- case 'h': /* --help | -h */
- help_flag = 1;
- break;
- case 'f': /* --file | -f */
- snprintf(command_buffer, 128, "script %s", optarg);
- add_config_file_name(command_buffer);
- break;
- case 's': /* --search | -s */
- add_script_search_dir(optarg);
- break;
- case 'd': /* --debug | -d */
- if (optarg)
- snprintf(command_buffer, 128, "debug_level %s", optarg);
- else
- snprintf(command_buffer, 128, "debug_level 3");
- command_run_line(cmd_ctx, command_buffer);
- break;
- case 'l': /* --log_output | -l */
- if (optarg)
- {
- snprintf(command_buffer, 128, "log_output %s", optarg);
- command_run_line(cmd_ctx, command_buffer);
- }
- break;
- case 'c': /* --command | -c */
- if (optarg)
- {
- add_config_file_name(optarg);
- }
- break;
-
- }
- }
-
- if (help_flag)
- {
- OUTPUT("Open On-Chip Debugger\n(c) 2005 by Dominic Rath\n\n");
- OUTPUT("--help | -h\tdisplay this help\n");
- OUTPUT("--file | -f\tuse configuration file <name>\n");
- OUTPUT("--search | -s\tdir to search for config files and scripts.\n");
- OUTPUT("--debug | -d\tset debug level <0-3>\n");
- OUTPUT("--log_output | -l\tredirect log output to file <name>\n");
- OUTPUT("--command | -c\trun <command>\n");
- exit(-1);
- }
-
-#ifdef _WIN32
- /* Add the parent of the directory where openocd.exe resides to the
- * config script search path.
- * Directory layout:
- * bin\openocd.exe
- * lib\openocd
- * event\at91eb40a_reset.cfg
- * target\at91eb40a.cfg
- */
- {
- char strExePath [MAX_PATH];
- GetModuleFileName (NULL, strExePath, MAX_PATH);
- /* Either this code will *always* work or it will SEGFAULT giving
- * excellent information on the culprit.
- */
- *strrchr(strExePath, '\\')=0;
- strcat(strExePath, "\\..");
- add_script_search_dir(strExePath);
- }
-#else
- /* Add dir for openocd supplied scripts last so that user can over
- ride those scripts if desired. */
- add_script_search_dir(PKGDATADIR);
- add_script_search_dir(PKGLIBDIR);
-#endif
-
- return ERROR_OK;
-}
+/*************************************************************************** + * Copyright (C) 2004, 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 "types.h" +#include "command.h" +#include "configuration.h" +#include "log.h" + +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <string.h> + + +static int help_flag; + +static struct option long_options[] = +{ + {"help", no_argument, &help_flag, 1}, + + {"debug", optional_argument, 0, 'd'}, + {"file", required_argument, 0, 'f'}, + {"search", required_argument, 0, 's'}, + {"log_output", required_argument, 0, 'l'}, + {"command", required_argument, 0, 'c'}, + + {0, 0, 0, 0} +}; + + + +int configuration_output_handler(struct command_context_s *context, char* line) +{ + INFO(line); + + return ERROR_OK; +} + + +int parse_cmdline_args(struct command_context_s *cmd_ctx, int argc, char *argv[]) +{ + int c; + char command_buffer[128]; + + while (1) + { + /* getopt_long stores the option index here. */ + int option_index = 0; + + c = getopt_long(argc, argv, "hd::l:f:s:c:", long_options, &option_index); + + /* Detect the end of the options. */ + if (c == -1) + break; + + switch (c) + { + case 0: + break; + case 'h': /* --help | -h */ + help_flag = 1; + break; + case 'f': /* --file | -f */ + snprintf(command_buffer, 128, "script %s", optarg); + add_config_file_name(command_buffer); + break; + case 's': /* --search | -s */ + add_script_search_dir(optarg); + break; + case 'd': /* --debug | -d */ + if (optarg) + snprintf(command_buffer, 128, "debug_level %s", optarg); + else + snprintf(command_buffer, 128, "debug_level 3"); + command_run_line(cmd_ctx, command_buffer); + break; + case 'l': /* --log_output | -l */ + if (optarg) + { + snprintf(command_buffer, 128, "log_output %s", optarg); + command_run_line(cmd_ctx, command_buffer); + } + break; + case 'c': /* --command | -c */ + if (optarg) + { + add_config_file_name(optarg); + } + break; + + } + } + + if (help_flag) + { + OUTPUT("Open On-Chip Debugger\n(c) 2005 by Dominic Rath\n\n"); + OUTPUT("--help | -h\tdisplay this help\n"); + OUTPUT("--file | -f\tuse configuration file <name>\n"); + OUTPUT("--search | -s\tdir to search for config files and scripts.\n"); + OUTPUT("--debug | -d\tset debug level <0-3>\n"); + OUTPUT("--log_output | -l\tredirect log output to file <name>\n"); + OUTPUT("--command | -c\trun <command>\n"); + exit(-1); + } + +#ifdef _WIN32 + /* Add the parent of the directory where openocd.exe resides to the + * config script search path. + * Directory layout: + * bin\openocd.exe + * lib\openocd + * event\at91eb40a_reset.cfg + * target\at91eb40a.cfg + */ + { + char strExePath [MAX_PATH]; + GetModuleFileName (NULL, strExePath, MAX_PATH); + /* Either this code will *always* work or it will SEGFAULT giving + * excellent information on the culprit. + */ + *strrchr(strExePath, '\\')=0; + strcat(strExePath, "\\.."); + add_script_search_dir(strExePath); + } +#else + /* Add dir for openocd supplied scripts last so that user can over + ride those scripts if desired. */ + add_script_search_dir(PKGDATADIR); + add_script_search_dir(PKGLIBDIR); +#endif + + return ERROR_OK; +} diff --git a/src/helper/replacements.h b/src/helper/replacements.h index 84705c5..296afdb 100644 --- a/src/helper/replacements.h +++ b/src/helper/replacements.h @@ -67,38 +67,38 @@ struct timezone { }; extern int gettimeofday(struct timeval *tv, struct timezone *tz); -#endif
-
+#endif + /**** clear_malloc & fill_malloc ****/ void *clear_malloc(size_t size); void *fill_malloc(size_t size); -
-/*
- * Now you have 3 ways for the malloc function:
- *
- * 1. Do not change anything, use the original malloc
- *
- * 2. Use the clear_malloc function instead of the original malloc.
- * In this case you must use the following define:
- * #define malloc((_a)) clear_malloc((_a))
- *
- * 3. Use the fill_malloc function instead of the original malloc.
- * In this case you must use the following define:
- * #define malloc((_a)) fill_malloc((_a))
- *
- * We have figured out that there could exist some malloc problems
- * where variables are using without to be initialise. To find this
- * places, use the fill_malloc function. With this function we want
- * to initialize memory to some known bad state. This is quite easily
- * spotted in the debugger and will trap to an invalid address.
- *
- * clear_malloc can be used if you want to set not initialise
- * variable to 0.
- *
- * If you do not want to change the malloc function, to not use one of
- * the following macros. Which is the default way.
- */
-
+ +/* + * Now you have 3 ways for the malloc function: + * + * 1. Do not change anything, use the original malloc + * + * 2. Use the clear_malloc function instead of the original malloc. + * In this case you must use the following define: + * #define malloc((_a)) clear_malloc((_a)) + * + * 3. Use the fill_malloc function instead of the original malloc. + * In this case you must use the following define: + * #define malloc((_a)) fill_malloc((_a)) + * + * We have figured out that there could exist some malloc problems + * where variables are using without to be initialise. To find this + * places, use the fill_malloc function. With this function we want + * to initialize memory to some known bad state. This is quite easily + * spotted in the debugger and will trap to an invalid address. + * + * clear_malloc can be used if you want to set not initialise + * variable to 0. + * + * If you do not want to change the malloc function, to not use one of + * the following macros. Which is the default way. + */ + //#define malloc(_a) clear_malloc(_a) //#define malloc(_a) fill_malloc(_a) diff --git a/src/jtag/bitq.c b/src/jtag/bitq.c index 4e53bc5..7c47b8e 100644 --- a/src/jtag/bitq.c +++ b/src/jtag/bitq.c @@ -1,366 +1,366 @@ -/***************************************************************************
- * Copyright (C) 2007 by Pavel Chromy *
- * chromy@asix.cz *
- * *
- * 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 "bitq.h"
-
-/* project specific includes */
-#include "log.h"
-#include "types.h"
-#include "jtag.h"
-#include "configuration.h"
-
-/* system includes */
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <sys/time.h>
-#include <time.h>
-
-
-bitq_interface_t *bitq_interface; /* low level bit queue interface */
-
-bitq_state_t bitq_in_state; /* state of input queue */
-
-u8 *bitq_in_buffer; /* buffer dynamically reallocated as needed */
-unsigned long bitq_in_bufsize=32; /* min. buffer size */
-
-
-/*
- * input queue processing does not use jtag_read_buffer() to avoid unnecessary overhead
- * also the buffer for incomming data is reallocated only if necessary
- * no parameters, makes use of stored state information
- */
-void bitq_in_proc(void)
-{
- /* static information preserved between calls to increase performance */
- static u8 *in_buff; /* pointer to buffer for scanned data */
- static int in_idx; /* index of byte being scanned */
- static u8 in_mask; /* mask of next bit to be scanned */
-
- scan_field_t *field;
- int tdo;
-
- /* loop through the queue */
- while (bitq_in_state.cmd) {
- /* only JTAG_SCAN command may return data */
- if (bitq_in_state.cmd->type==JTAG_SCAN) {
- /* loop through the fields */
- while (bitq_in_state.field_idx<bitq_in_state.cmd->cmd.scan->num_fields) {
-
- field=&bitq_in_state.cmd->cmd.scan->fields[bitq_in_state.field_idx];
- if ( field->in_value || field->in_handler) {
-
- if (bitq_in_state.bit_pos==0) {
- /* initialize field scanning */
- in_mask=0x01;
- in_idx=0;
- if (field->in_value) in_buff=field->in_value;
- else {
- /* buffer reallocation needed? */
- if (field->num_bits>bitq_in_bufsize*8) {
- /* buffer previously allocated? */
- if (bitq_in_buffer!=NULL) {
- /* free it */
- free(bitq_in_buffer);
- bitq_in_buffer=NULL;
- }
- /* double the buffer size until it fits */
- while (field->num_bits>bitq_in_bufsize*8) bitq_in_bufsize*=2;
- }
- /* if necessary, allocate buffer and check for malloc error */
- if (bitq_in_buffer==NULL && (bitq_in_buffer=malloc(bitq_in_bufsize))==NULL) {
- ERROR("malloc error");
- exit(-1);
- }
- in_buff=(void *)bitq_in_buffer;
- }
- }
-
- /* field scanning */
- while (bitq_in_state.bit_pos<field->num_bits) {
- if ((tdo=bitq_interface->in())<0) {
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("bitq in EOF");
-#endif
- return;
- }
- if (in_mask==0x01) in_buff[in_idx]=0;
- if (tdo) in_buff[in_idx]|=in_mask;
- if (in_mask==0x80) {
- in_mask=0x01;
- in_idx++;
- }
- else in_mask<<=1;
- bitq_in_state.bit_pos++;
- }
-
-
- if (field->in_handler && bitq_in_state.status==ERROR_OK) {
- bitq_in_state.status=(*field->in_handler)(in_buff, field->in_handler_priv, field);
- }
-
- }
-
- bitq_in_state.field_idx++; /* advance to next field */
- bitq_in_state.bit_pos=0; /* start next field from the first bit */
- }
-
- }
- bitq_in_state.cmd=bitq_in_state.cmd->next; /* advance to next command */
- bitq_in_state.field_idx=0; /* preselect first field */
- }
-}
-
-
-
-void bitq_io(int tms, int tdi, int tdo_req)
-{
- bitq_interface->out(tms, tdi, tdo_req);
- /* check and process the input queue */
- if (bitq_interface->in_rdy()) bitq_in_proc();
-}
-
-
-void bitq_end_state(enum tap_state state)
-{
- if (state==-1) return;
- if (tap_move_map[state]==-1) {
- ERROR("BUG: %i is not a valid end state", state);
- exit(-1);
- }
- end_state = state;
-}
-
-
-void bitq_state_move(enum tap_state new_state)
-{
- int i=0;
- u8 tms_scan;
-
- if (tap_move_map[cur_state]==-1 || tap_move_map[new_state]==-1) {
- ERROR("TAP move from or to unstable state");
- exit(-1);
- }
-
- tms_scan=TAP_MOVE(cur_state, new_state);
-
- for (i=0; i<7; i++) {
- bitq_io(tms_scan&1, 0, 0);
- tms_scan>>=1;
- }
-
- cur_state = new_state;
-}
-
-
-void bitq_path_move(pathmove_command_t *cmd)
-{
- int i;
-
- for (i=0; i<=cmd->num_states; i++) {
- if (tap_transitions[cur_state].low == cmd->path[i]) bitq_io(0, 0, 0);
- else if (tap_transitions[cur_state].high == cmd->path[i]) bitq_io(1, 0, 0);
- else {
- ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_strings[cur_state], tap_state_strings[cmd->path[i]]);
- exit(-1);
- }
-
- cur_state = cmd->path[i];
- }
-
- end_state = cur_state;
-}
-
-
-void bitq_runtest(int num_cycles)
-{
- int i;
-
- /* only do a state_move when we're not already in RTI */
- if (cur_state != TAP_RTI) bitq_state_move(TAP_RTI);
-
- /* execute num_cycles */
- for (i = 0; i < num_cycles; i++)
- bitq_io(0, 0, 0);
-
- /* finish in end_state */
- if (cur_state != end_state) bitq_state_move(end_state);
-}
-
-
-void bitq_scan_field(scan_field_t *field, int pause)
-{
- int bit_cnt;
- int tdo_req;
-
- u8 *out_ptr;
- u8 out_mask;
-
- if ( field->in_value || field->in_handler) tdo_req=1;
- else tdo_req=0;
-
- if (field->out_value==NULL) {
- /* just send zeros and request data from TDO */
- for (bit_cnt=field->num_bits; bit_cnt>1; bit_cnt--)
- bitq_io(0, 0, tdo_req);
- bitq_io(pause, 0, tdo_req);
- }
- else {
- /* send data, and optionally request TDO */
- out_mask=0x01;
- out_ptr=field->out_value;
- for (bit_cnt=field->num_bits; bit_cnt>1; bit_cnt--) {
- bitq_io(0, ((*out_ptr)&out_mask)!=0, tdo_req);
- if (out_mask==0x80) {
- out_mask=0x01;
- out_ptr++;
- }
- else out_mask<<=1;
- }
- bitq_io(pause, ((*out_ptr)&out_mask)!=0, tdo_req);
- }
-
- if (pause) {
- bitq_io(0,0,0);
- if (cur_state==TAP_SI) cur_state=TAP_PI;
- else if (cur_state==TAP_SD) cur_state=TAP_PD;
- }
-}
-
-
-void bitq_scan(scan_command_t *cmd)
-{
- int i;
-
- if (cmd->ir_scan) bitq_state_move(TAP_SI);
- else bitq_state_move(TAP_SD);
-
- for (i=0; i < cmd->num_fields-1; i++)
- bitq_scan_field(&cmd->fields[i], 0);
- bitq_scan_field(&cmd->fields[i], 1);
-}
-
-
-int bitq_execute_queue(void)
-{
- jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
-
- bitq_in_state.cmd = jtag_command_queue;
- bitq_in_state.field_idx = 0;
- bitq_in_state.bit_pos = 0;
- bitq_in_state.status = ERROR_OK;
-
- while (cmd) {
-
- switch (cmd->type) {
-
- case JTAG_END_STATE:
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("end_state: %i", cmd->cmd.end_state->end_state);
-#endif
- bitq_end_state(cmd->cmd.end_state->end_state);
- break;
-
- case JTAG_RESET:
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
-#endif
- bitq_interface->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
- if (bitq_interface->in_rdy()) bitq_in_proc();
- break;
-
- case JTAG_RUNTEST:
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state);
-#endif
- bitq_end_state(cmd->cmd.runtest->end_state);
- bitq_runtest(cmd->cmd.runtest->num_cycles);
- break;
-
- case JTAG_STATEMOVE:
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("statemove end in %i", cmd->cmd.statemove->end_state);
-#endif
- bitq_end_state(cmd->cmd.statemove->end_state);
- bitq_state_move(end_state); /* uncoditional TAP move */
- break;
-
- case JTAG_PATHMOVE:
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
-#endif
- bitq_path_move(cmd->cmd.pathmove);
- break;
-
- case JTAG_SCAN:
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("scan end in %i", cmd->cmd.scan->end_state);
- if (cmd->cmd.scan->ir_scan) DEBUG("scan ir");
- else DEBUG("scan dr");
-#endif
- bitq_end_state(cmd->cmd.scan->end_state);
- bitq_scan(cmd->cmd.scan);
- if (cur_state != end_state) bitq_state_move(end_state);
- break;
-
- case JTAG_SLEEP:
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("sleep %i", cmd->cmd.sleep->us);
-#endif
- bitq_interface->sleep(cmd->cmd.sleep->us);
- if (bitq_interface->in_rdy()) bitq_in_proc();
- break;
-
- default:
- ERROR("BUG: unknown JTAG command type encountered");
- exit(-1);
- }
-
- cmd = cmd->next;
- }
-
- bitq_interface->flush();
- bitq_in_proc();
-
- if (bitq_in_state.cmd) {
- ERROR("missing data from bitq interface");
- return ERROR_JTAG_QUEUE_FAILED;
- }
- if (bitq_interface->in()>=0) {
- ERROR("extra data from bitq interface");
- return ERROR_JTAG_QUEUE_FAILED;
- }
-
- return bitq_in_state.status;
-}
-
-
-void bitq_cleanup(void)
-{
- if (bitq_in_buffer!=NULL)
- {
- free(bitq_in_buffer);
- bitq_in_buffer=NULL;
- }
-}
+/*************************************************************************** + * Copyright (C) 2007 by Pavel Chromy * + * chromy@asix.cz * + * * + * 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 "bitq.h" + +/* project specific includes */ +#include "log.h" +#include "types.h" +#include "jtag.h" +#include "configuration.h" + +/* system includes */ +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include <sys/time.h> +#include <time.h> + + +bitq_interface_t *bitq_interface; /* low level bit queue interface */ + +bitq_state_t bitq_in_state; /* state of input queue */ + +u8 *bitq_in_buffer; /* buffer dynamically reallocated as needed */ +unsigned long bitq_in_bufsize=32; /* min. buffer size */ + + +/* + * input queue processing does not use jtag_read_buffer() to avoid unnecessary overhead + * also the buffer for incomming data is reallocated only if necessary + * no parameters, makes use of stored state information + */ +void bitq_in_proc(void) +{ + /* static information preserved between calls to increase performance */ + static u8 *in_buff; /* pointer to buffer for scanned data */ + static int in_idx; /* index of byte being scanned */ + static u8 in_mask; /* mask of next bit to be scanned */ + + scan_field_t *field; + int tdo; + + /* loop through the queue */ + while (bitq_in_state.cmd) { + /* only JTAG_SCAN command may return data */ + if (bitq_in_state.cmd->type==JTAG_SCAN) { + /* loop through the fields */ + while (bitq_in_state.field_idx<bitq_in_state.cmd->cmd.scan->num_fields) { + + field=&bitq_in_state.cmd->cmd.scan->fields[bitq_in_state.field_idx]; + if ( field->in_value || field->in_handler) { + + if (bitq_in_state.bit_pos==0) { + /* initialize field scanning */ + in_mask=0x01; + in_idx=0; + if (field->in_value) in_buff=field->in_value; + else { + /* buffer reallocation needed? */ + if (field->num_bits>bitq_in_bufsize*8) { + /* buffer previously allocated? */ + if (bitq_in_buffer!=NULL) { + /* free it */ + free(bitq_in_buffer); + bitq_in_buffer=NULL; + } + /* double the buffer size until it fits */ + while (field->num_bits>bitq_in_bufsize*8) bitq_in_bufsize*=2; + } + /* if necessary, allocate buffer and check for malloc error */ + if (bitq_in_buffer==NULL && (bitq_in_buffer=malloc(bitq_in_bufsize))==NULL) { + ERROR("malloc error"); + exit(-1); + } + in_buff=(void *)bitq_in_buffer; + } + } + + /* field scanning */ + while (bitq_in_state.bit_pos<field->num_bits) { + if ((tdo=bitq_interface->in())<0) { +#ifdef _DEBUG_JTAG_IO_ + DEBUG("bitq in EOF"); +#endif + return; + } + if (in_mask==0x01) in_buff[in_idx]=0; + if (tdo) in_buff[in_idx]|=in_mask; + if (in_mask==0x80) { + in_mask=0x01; + in_idx++; + } + else in_mask<<=1; + bitq_in_state.bit_pos++; + } + + + if (field->in_handler && bitq_in_state.status==ERROR_OK) { + bitq_in_state.status=(*field->in_handler)(in_buff, field->in_handler_priv, field); + } + + } + + bitq_in_state.field_idx++; /* advance to next field */ + bitq_in_state.bit_pos=0; /* start next field from the first bit */ + } + + } + bitq_in_state.cmd=bitq_in_state.cmd->next; /* advance to next command */ + bitq_in_state.field_idx=0; /* preselect first field */ + } +} + + + +void bitq_io(int tms, int tdi, int tdo_req) +{ + bitq_interface->out(tms, tdi, tdo_req); + /* check and process the input queue */ + if (bitq_interface->in_rdy()) bitq_in_proc(); +} + + +void bitq_end_state(enum tap_state state) +{ + if (state==-1) return; + if (tap_move_map[state]==-1) { + ERROR("BUG: %i is not a valid end state", state); + exit(-1); + } + end_state = state; +} + + +void bitq_state_move(enum tap_state new_state) +{ + int i=0; + u8 tms_scan; + + if (tap_move_map[cur_state]==-1 || tap_move_map[new_state]==-1) { + ERROR("TAP move from or to unstable state"); + exit(-1); + } + + tms_scan=TAP_MOVE(cur_state, new_state); + + for (i=0; i<7; i++) { + bitq_io(tms_scan&1, 0, 0); + tms_scan>>=1; + } + + cur_state = new_state; +} + + +void bitq_path_move(pathmove_command_t *cmd) +{ + int i; + + for (i=0; i<=cmd->num_states; i++) { + if (tap_transitions[cur_state].low == cmd->path[i]) bitq_io(0, 0, 0); + else if (tap_transitions[cur_state].high == cmd->path[i]) bitq_io(1, 0, 0); + else { + ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_strings[cur_state], tap_state_strings[cmd->path[i]]); + exit(-1); + } + + cur_state = cmd->path[i]; + } + + end_state = cur_state; +} + + +void bitq_runtest(int num_cycles) +{ + int i; + + /* only do a state_move when we're not already in RTI */ + if (cur_state != TAP_RTI) bitq_state_move(TAP_RTI); + + /* execute num_cycles */ + for (i = 0; i < num_cycles; i++) + bitq_io(0, 0, 0); + + /* finish in end_state */ + if (cur_state != end_state) bitq_state_move(end_state); +} + + +void bitq_scan_field(scan_field_t *field, int pause) +{ + int bit_cnt; + int tdo_req; + + u8 *out_ptr; + u8 out_mask; + + if ( field->in_value || field->in_handler) tdo_req=1; + else tdo_req=0; + + if (field->out_value==NULL) { + /* just send zeros and request data from TDO */ + for (bit_cnt=field->num_bits; bit_cnt>1; bit_cnt--) + bitq_io(0, 0, tdo_req); + bitq_io(pause, 0, tdo_req); + } + else { + /* send data, and optionally request TDO */ + out_mask=0x01; + out_ptr=field->out_value; + for (bit_cnt=field->num_bits; bit_cnt>1; bit_cnt--) { + bitq_io(0, ((*out_ptr)&out_mask)!=0, tdo_req); + if (out_mask==0x80) { + out_mask=0x01; + out_ptr++; + } + else out_mask<<=1; + } + bitq_io(pause, ((*out_ptr)&out_mask)!=0, tdo_req); + } + + if (pause) { + bitq_io(0,0,0); + if (cur_state==TAP_SI) cur_state=TAP_PI; + else if (cur_state==TAP_SD) cur_state=TAP_PD; + } +} + + +void bitq_scan(scan_command_t *cmd) +{ + int i; + + if (cmd->ir_scan) bitq_state_move(TAP_SI); + else bitq_state_move(TAP_SD); + + for (i=0; i < cmd->num_fields-1; i++) + bitq_scan_field(&cmd->fields[i], 0); + bitq_scan_field(&cmd->fields[i], 1); +} + + +int bitq_execute_queue(void) +{ + jtag_command_t *cmd = jtag_command_queue; /* currently processed command */ + + bitq_in_state.cmd = jtag_command_queue; + bitq_in_state.field_idx = 0; + bitq_in_state.bit_pos = 0; + bitq_in_state.status = ERROR_OK; + + while (cmd) { + + switch (cmd->type) { + + case JTAG_END_STATE: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("end_state: %i", cmd->cmd.end_state->end_state); +#endif + bitq_end_state(cmd->cmd.end_state->end_state); + break; + + case JTAG_RESET: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); +#endif + bitq_interface->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + if (bitq_interface->in_rdy()) bitq_in_proc(); + break; + + case JTAG_RUNTEST: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); +#endif + bitq_end_state(cmd->cmd.runtest->end_state); + bitq_runtest(cmd->cmd.runtest->num_cycles); + break; + + case JTAG_STATEMOVE: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("statemove end in %i", cmd->cmd.statemove->end_state); +#endif + bitq_end_state(cmd->cmd.statemove->end_state); + bitq_state_move(end_state); /* uncoditional TAP move */ + break; + + case JTAG_PATHMOVE: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); +#endif + bitq_path_move(cmd->cmd.pathmove); + break; + + case JTAG_SCAN: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("scan end in %i", cmd->cmd.scan->end_state); + if (cmd->cmd.scan->ir_scan) DEBUG("scan ir"); + else DEBUG("scan dr"); +#endif + bitq_end_state(cmd->cmd.scan->end_state); + bitq_scan(cmd->cmd.scan); + if (cur_state != end_state) bitq_state_move(end_state); + break; + + case JTAG_SLEEP: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("sleep %i", cmd->cmd.sleep->us); +#endif + bitq_interface->sleep(cmd->cmd.sleep->us); + if (bitq_interface->in_rdy()) bitq_in_proc(); + break; + + default: + ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); + } + + cmd = cmd->next; + } + + bitq_interface->flush(); + bitq_in_proc(); + + if (bitq_in_state.cmd) { + ERROR("missing data from bitq interface"); + return ERROR_JTAG_QUEUE_FAILED; + } + if (bitq_interface->in()>=0) { + ERROR("extra data from bitq interface"); + return ERROR_JTAG_QUEUE_FAILED; + } + + return bitq_in_state.status; +} + + +void bitq_cleanup(void) +{ + if (bitq_in_buffer!=NULL) + { + free(bitq_in_buffer); + bitq_in_buffer=NULL; + } +} diff --git a/src/jtag/ep93xx.c b/src/jtag/ep93xx.c index ebedfdf..aa62ad5 100644 --- a/src/jtag/ep93xx.c +++ b/src/jtag/ep93xx.c @@ -1,237 +1,237 @@ -/***************************************************************************
- * 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 "log.h"
-#include "jtag.h"
-#include "bitbang.h"
-
-#define TDO_BIT 1
-#define TDI_BIT 2
-#define TCK_BIT 4
-#define TMS_BIT 8
-#define TRST_BIT 16
-#define SRST_BIT 32
-#define VCC_BIT 64
-
-/* system includes */
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/mman.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-static u8 output_value = 0x0;
-static int dev_mem_fd;
-static void *gpio_controller;
-static volatile u8 *gpio_data_register;
-static volatile u8 *gpio_data_direction_register;
-
-/* low level command set
- */
-int ep93xx_read(void);
-void ep93xx_write(int tck, int tms, int tdi);
-void ep93xx_reset(int trst, int srst);
-
-int ep93xx_speed(int speed);
-int ep93xx_register_commands(struct command_context_s *cmd_ctx);
-int ep93xx_init(void);
-int ep93xx_quit(void);
-
-struct timespec ep93xx_zzzz;
-
-jtag_interface_t ep93xx_interface =
-{
- .name = "ep93xx",
-
- .execute_queue = bitbang_execute_queue,
-
- .speed = ep93xx_speed,
- .register_commands = ep93xx_register_commands,
- .init = ep93xx_init,
- .quit = ep93xx_quit,
-};
-
-bitbang_interface_t ep93xx_bitbang =
-{
- .read = ep93xx_read,
- .write = ep93xx_write,
- .reset = ep93xx_reset,
- .blink = 0;
-};
-
-int ep93xx_read(void)
-{
- return !!(*gpio_data_register & TDO_BIT);
-}
-
-void ep93xx_write(int tck, int tms, int tdi)
-{
- if (tck)
- output_value |= TCK_BIT;
- else
- output_value &= TCK_BIT;
-
- if (tms)
- output_value |= TMS_BIT;
- else
- output_value &= TMS_BIT;
-
- if (tdi)
- output_value |= TDI_BIT;
- else
- output_value &= TDI_BIT;
-
- *gpio_data_register = output_value;
- nanosleep(ep93xx_zzzz);
-}
-
-/* (1) assert or (0) deassert reset lines */
-void ep93xx_reset(int trst, int srst)
-{
- if (trst == 0)
- output_value |= TRST_BIT;
- else if (trst == 1)
- output_value &= TRST_BIT;
-
- if (srst == 0)
- output_value |= SRST_BIT;
- else if (srst == 1)
- output_value &= SRST_BIT;
-
- *gpio_data_register = output_value;
- nanosleep(ep93xx_zzzz);
-}
-
-int ep93xx_speed(int speed)
-{
-
- return ERROR_OK;
-}
-
-int ep93xx_register_commands(struct command_context_s *cmd_ctx)
-{
-
- return ERROR_OK;
-}
-
-static int set_gonk_mode(void)
-{
- void *syscon;
- u32 devicecfg;
-
- syscon = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
- MAP_SHARED, dev_mem_fd, 0x80930000);
- if (syscon == MAP_FAILED) {
- perror("mmap");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- devicecfg = *((volatile int *)(syscon + 0x80));
- *((volatile int *)(syscon + 0xc0)) = 0xaa;
- *((volatile int *)(syscon + 0x80)) = devicecfg | 0x08000000;
-
- munmap(syscon, 4096);
-
- return ERROR_OK;
-}
-
-int ep93xx_init(void)
-{
- int ret;
-
- bitbang_interface = &ep93xx_bitbang;
-
- ep93xx_zzzz.tv_sec = 0;
- ep93xx_zzzz.tv_nsec = 10000000;
-
- dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
- if (dev_mem_fd < 0) {
- perror("open");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- gpio_controller = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
- MAP_SHARED, dev_mem_fd, 0x80840000);
- if (gpio_controller == MAP_FAILED) {
- perror("mmap");
- close(dev_mem_fd);
- return ERROR_JTAG_INIT_FAILED;
- }
-
- ret = set_gonk_mode();
- if (ret != ERROR_OK) {
- munmap(gpio_controller, 4096);
- close(dev_mem_fd);
- return ret;
- }
-
-#if 0
- /* Use GPIO port A. */
- gpio_data_register = gpio_controller + 0x00;
- gpio_data_direction_register = gpio_controller + 0x10;
-
-
- /* Use GPIO port B. */
- gpio_data_register = gpio_controller + 0x04;
- gpio_data_direction_register = gpio_controller + 0x14;
-
- /* Use GPIO port C. */
- gpio_data_register = gpio_controller + 0x08;
- gpio_data_direction_register = gpio_controller + 0x18;
-
- /* Use GPIO port D. */
- gpio_data_register = gpio_controller + 0x0c;
- gpio_data_direction_register = gpio_controller + 0x1c;
-#endif
-
- /* Use GPIO port C. */
- gpio_data_register = gpio_controller + 0x08;
- gpio_data_direction_register = gpio_controller + 0x18;
-
- INFO("gpio_data_register = %p\n", gpio_data_register);
- INFO("gpio_data_direction_reg = %p\n", gpio_data_direction_register);
- /*
- * Configure bit 0 (TDO) as an input, and bits 1-5 (TDI, TCK
- * TMS, TRST, SRST) as outputs. Drive TDI and TCK low, and
- * TMS/TRST/SRST high.
- */
- output_value = TMS_BIT | TRST_BIT | SRST_BIT | VCC_BIT;
- *gpio_data_register = output_value;
- nanosleep(ep93xx_zzzz);
-
- /*
- * Configure the direction register. 1 = output, 0 = input.
- */
- *gpio_data_direction_register =
- TDI_BIT | TCK_BIT | TMS_BIT | TRST_BIT | SRST_BIT | VCC_BIT;
-
- nanosleep(ep93xx_zzzz);
- return ERROR_OK;
-}
-
-int ep93xx_quit(void)
-{
-
- return ERROR_OK;
-}
+/*************************************************************************** + * 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 "log.h" +#include "jtag.h" +#include "bitbang.h" + +#define TDO_BIT 1 +#define TDI_BIT 2 +#define TCK_BIT 4 +#define TMS_BIT 8 +#define TRST_BIT 16 +#define SRST_BIT 32 +#define VCC_BIT 64 + +/* system includes */ +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/mman.h> +#include <unistd.h> +#include <fcntl.h> + +static u8 output_value = 0x0; +static int dev_mem_fd; +static void *gpio_controller; +static volatile u8 *gpio_data_register; +static volatile u8 *gpio_data_direction_register; + +/* low level command set + */ +int ep93xx_read(void); +void ep93xx_write(int tck, int tms, int tdi); +void ep93xx_reset(int trst, int srst); + +int ep93xx_speed(int speed); +int ep93xx_register_commands(struct command_context_s *cmd_ctx); +int ep93xx_init(void); +int ep93xx_quit(void); + +struct timespec ep93xx_zzzz; + +jtag_interface_t ep93xx_interface = +{ + .name = "ep93xx", + + .execute_queue = bitbang_execute_queue, + + .speed = ep93xx_speed, + .register_commands = ep93xx_register_commands, + .init = ep93xx_init, + .quit = ep93xx_quit, +}; + +bitbang_interface_t ep93xx_bitbang = +{ + .read = ep93xx_read, + .write = ep93xx_write, + .reset = ep93xx_reset, + .blink = 0; +}; + +int ep93xx_read(void) +{ + return !!(*gpio_data_register & TDO_BIT); +} + +void ep93xx_write(int tck, int tms, int tdi) +{ + if (tck) + output_value |= TCK_BIT; + else + output_value &= TCK_BIT; + + if (tms) + output_value |= TMS_BIT; + else + output_value &= TMS_BIT; + + if (tdi) + output_value |= TDI_BIT; + else + output_value &= TDI_BIT; + + *gpio_data_register = output_value; + nanosleep(ep93xx_zzzz); +} + +/* (1) assert or (0) deassert reset lines */ +void ep93xx_reset(int trst, int srst) +{ + if (trst == 0) + output_value |= TRST_BIT; + else if (trst == 1) + output_value &= TRST_BIT; + + if (srst == 0) + output_value |= SRST_BIT; + else if (srst == 1) + output_value &= SRST_BIT; + + *gpio_data_register = output_value; + nanosleep(ep93xx_zzzz); +} + +int ep93xx_speed(int speed) +{ + + return ERROR_OK; +} + +int ep93xx_register_commands(struct command_context_s *cmd_ctx) +{ + + return ERROR_OK; +} + +static int set_gonk_mode(void) +{ + void *syscon; + u32 devicecfg; + + syscon = mmap(NULL, 4096, PROT_READ | PROT_WRITE, + MAP_SHARED, dev_mem_fd, 0x80930000); + if (syscon == MAP_FAILED) { + perror("mmap"); + return ERROR_JTAG_INIT_FAILED; + } + + devicecfg = *((volatile int *)(syscon + 0x80)); + *((volatile int *)(syscon + 0xc0)) = 0xaa; + *((volatile int *)(syscon + 0x80)) = devicecfg | 0x08000000; + + munmap(syscon, 4096); + + return ERROR_OK; +} + +int ep93xx_init(void) +{ + int ret; + + bitbang_interface = &ep93xx_bitbang; + + ep93xx_zzzz.tv_sec = 0; + ep93xx_zzzz.tv_nsec = 10000000; + + dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC); + if (dev_mem_fd < 0) { + perror("open"); + return ERROR_JTAG_INIT_FAILED; + } + + gpio_controller = mmap(NULL, 4096, PROT_READ | PROT_WRITE, + MAP_SHARED, dev_mem_fd, 0x80840000); + if (gpio_controller == MAP_FAILED) { + perror("mmap"); + close(dev_mem_fd); + return ERROR_JTAG_INIT_FAILED; + } + + ret = set_gonk_mode(); + if (ret != ERROR_OK) { + munmap(gpio_controller, 4096); + close(dev_mem_fd); + return ret; + } + +#if 0 + /* Use GPIO port A. */ + gpio_data_register = gpio_controller + 0x00; + gpio_data_direction_register = gpio_controller + 0x10; + + + /* Use GPIO port B. */ + gpio_data_register = gpio_controller + 0x04; + gpio_data_direction_register = gpio_controller + 0x14; + + /* Use GPIO port C. */ + gpio_data_register = gpio_controller + 0x08; + gpio_data_direction_register = gpio_controller + 0x18; + + /* Use GPIO port D. */ + gpio_data_register = gpio_controller + 0x0c; + gpio_data_direction_register = gpio_controller + 0x1c; +#endif + + /* Use GPIO port C. */ + gpio_data_register = gpio_controller + 0x08; + gpio_data_direction_register = gpio_controller + 0x18; + + INFO("gpio_data_register = %p\n", gpio_data_register); + INFO("gpio_data_direction_reg = %p\n", gpio_data_direction_register); + /* + * Configure bit 0 (TDO) as an input, and bits 1-5 (TDI, TCK + * TMS, TRST, SRST) as outputs. Drive TDI and TCK low, and + * TMS/TRST/SRST high. + */ + output_value = TMS_BIT | TRST_BIT | SRST_BIT | VCC_BIT; + *gpio_data_register = output_value; + nanosleep(ep93xx_zzzz); + + /* + * Configure the direction register. 1 = output, 0 = input. + */ + *gpio_data_direction_register = + TDI_BIT | TCK_BIT | TMS_BIT | TRST_BIT | SRST_BIT | VCC_BIT; + + nanosleep(ep93xx_zzzz); + return ERROR_OK; +} + +int ep93xx_quit(void) +{ + + return ERROR_OK; +} diff --git a/src/jtag/ft2232.c b/src/jtag/ft2232.c index 011eead..d5c4af2 100644 --- a/src/jtag/ft2232.c +++ b/src/jtag/ft2232.c @@ -1,2139 +1,2139 @@ -/***************************************************************************
- * Copyright (C) 2004, 2006 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
-
-#if IS_CYGWIN == 1
-#include "windows.h"
-#undef ERROR
-#endif
-
-#include "replacements.h"
-
-/* project specific includes */
-#include "log.h"
-#include "types.h"
-#include "jtag.h"
-#include "configuration.h"
-#include "time_support.h"
-
-/* system includes */
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-/* FT2232 access library includes */
-#if BUILD_FT2232_FTD2XX == 1
-#include <ftd2xx.h>
-#elif BUILD_FT2232_LIBFTDI == 1
-#include <ftdi.h>
-#endif
-
-#include <sys/time.h>
-#include <time.h>
-
-/* enable this to debug io latency
- */
-#if 0
-#define _DEBUG_USB_IO_
-#endif
-
-/* enable this to debug communication
- */
-#if 0
-#define _DEBUG_USB_COMMS_
-#endif
-
-int ft2232_execute_queue(void);
-
-int ft2232_speed(int speed);
-int ft2232_register_commands(struct command_context_s *cmd_ctx);
-int ft2232_init(void);
-int ft2232_quit(void);
-
-int ft2232_handle_device_desc_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int ft2232_handle_serial_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int ft2232_handle_layout_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int ft2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int ft2232_handle_latency_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-char *ft2232_device_desc = NULL;
-char *ft2232_serial = NULL;
-char *ft2232_layout = NULL;
-unsigned char ft2232_latency = 2;
-
-#define MAX_USB_IDS 8
-/* vid = pid = 0 marks the end of the list */
-static u16 ft2232_vid[MAX_USB_IDS+1] = { 0x0403, 0 };
-static u16 ft2232_pid[MAX_USB_IDS+1] = { 0x6010, 0 };
-
-typedef struct ft2232_layout_s
-{
- char* name;
- int(*init)(void);
- void(*reset)(int trst, int srst);
- void(*blink)(void);
-} ft2232_layout_t;
-
-/* init procedures for supported layouts */
-int usbjtag_init(void);
-int jtagkey_init(void);
-int olimex_jtag_init(void);
-int flyswatter_init(void);
-int turtle_init(void);
-int comstick_init(void);
-int stm32stick_init(void);
-
-/* reset procedures for supported layouts */
-void usbjtag_reset(int trst, int srst);
-void jtagkey_reset(int trst, int srst);
-void olimex_jtag_reset(int trst, int srst);
-void flyswatter_reset(int trst, int srst);
-void turtle_reset(int trst, int srst);
-void comstick_reset(int trst, int srst);
-void stm32stick_reset(int trst, int srst);
-
-/* blink procedures for layouts that support a blinking led */
-void olimex_jtag_blink(void);
-void turtle_jtag_blink(void);
-
-ft2232_layout_t ft2232_layouts[] =
-{
- {"usbjtag", usbjtag_init, usbjtag_reset, NULL},
- {"jtagkey", jtagkey_init, jtagkey_reset, NULL},
- {"jtagkey_prototype_v1", jtagkey_init, jtagkey_reset, NULL},
- {"oocdlink", jtagkey_init, jtagkey_reset, NULL},
- {"signalyzer", usbjtag_init, usbjtag_reset, NULL},
- {"evb_lm3s811", usbjtag_init, usbjtag_reset, NULL},
- {"olimex-jtag", olimex_jtag_init, olimex_jtag_reset, olimex_jtag_blink},
- {"flyswatter", flyswatter_init, flyswatter_reset, NULL},
- {"turtelizer2", turtle_init, turtle_reset, turtle_jtag_blink},
- {"comstick", comstick_init, comstick_reset, NULL},
- {"stm32stick", stm32stick_init, stm32stick_reset, NULL},
- {NULL, NULL, NULL},
-};
-
-static u8 nTRST, nTRSTnOE, nSRST, nSRSTnOE;
-
-static ft2232_layout_t *layout;
-static u8 low_output = 0x0;
-static u8 low_direction = 0x0;
-static u8 high_output = 0x0;
-static u8 high_direction = 0x0;
-
-#if BUILD_FT2232_FTD2XX == 1
-static FT_HANDLE ftdih = NULL;
-#elif BUILD_FT2232_LIBFTDI == 1
-static struct ftdi_context ftdic;
-#endif
-
-static u8 *ft2232_buffer = NULL;
-static int ft2232_buffer_size = 0;
-static int ft2232_read_pointer = 0;
-static int ft2232_expect_read = 0;
-#define FT2232_BUFFER_SIZE 131072
-#define BUFFER_ADD ft2232_buffer[ft2232_buffer_size++]
-#define BUFFER_READ ft2232_buffer[ft2232_read_pointer++]
-
-jtag_interface_t ft2232_interface =
-{
-
- .name = "ft2232",
-
- .execute_queue = ft2232_execute_queue,
-
- .speed = ft2232_speed,
- .register_commands = ft2232_register_commands,
- .init = ft2232_init,
- .quit = ft2232_quit,
-};
-
-int ft2232_write(u8 *buf, int size, u32* bytes_written)
-{
-#if BUILD_FT2232_FTD2XX == 1
- FT_STATUS status;
- DWORD dw_bytes_written;
- if ((status = FT_Write(ftdih, buf, size, &dw_bytes_written)) != FT_OK)
- {
- *bytes_written = dw_bytes_written;
- ERROR("FT_Write returned: %lu", status);
- return ERROR_JTAG_DEVICE_ERROR;
- }
- else
- {
- *bytes_written = dw_bytes_written;
- return ERROR_OK;
- }
-#elif BUILD_FT2232_LIBFTDI == 1
- int retval;
- if ((retval = ftdi_write_data(&ftdic, buf, size)) < 0)
- {
- *bytes_written = 0;
- ERROR("ftdi_write_data: %s", ftdi_get_error_string(&ftdic));
- return ERROR_JTAG_DEVICE_ERROR;
- }
- else
- {
- *bytes_written = retval;
- return ERROR_OK;
- }
-#endif
-}
-
-int ft2232_read(u8* buf, int size, u32* bytes_read)
-{
-#if BUILD_FT2232_FTD2XX == 1
- DWORD dw_bytes_read;
- FT_STATUS status;
- int timeout = 5;
- *bytes_read = 0;
-
- while ((*bytes_read < size) && timeout--)
- {
- if ((status = FT_Read(ftdih, buf + *bytes_read, size -
- *bytes_read, &dw_bytes_read)) != FT_OK)
- {
- *bytes_read = 0;
- ERROR("FT_Read returned: %lu", status);
- return ERROR_JTAG_DEVICE_ERROR;
- }
- *bytes_read += dw_bytes_read;
- }
-#elif BUILD_FT2232_LIBFTDI == 1
- int retval;
- int timeout = 100;
- *bytes_read = 0;
-
- while ((*bytes_read < size) && timeout--)
- {
- if ((retval = ftdi_read_data(&ftdic, buf + *bytes_read, size - *bytes_read)) < 0)
- {
- *bytes_read = 0;
- ERROR("ftdi_read_data: %s", ftdi_get_error_string(&ftdic));
- return ERROR_JTAG_DEVICE_ERROR;
- }
- *bytes_read += retval;
- }
-#endif
-
- if (*bytes_read < size)
- {
- ERROR("couldn't read the requested number of bytes from FT2232 device (%i < %i)", *bytes_read, size);
- return ERROR_JTAG_DEVICE_ERROR;
- }
-
- return ERROR_OK;
-}
-
-int ft2232_speed(int speed)
-{
- u8 buf[3];
- int retval;
- u32 bytes_written;
-
- buf[0] = 0x86; /* command "set divisor" */
- buf[1] = speed & 0xff; /* valueL (0=6MHz, 1=3MHz, 2=2.0MHz, ...*/
- buf[2] = (speed >> 8) & 0xff; /* valueH */
-
- DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
- if (((retval = ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
- {
- ERROR("couldn't set FT2232 TCK speed");
- return retval;
- }
-
- jtag_speed = speed;
-
- return ERROR_OK;
-}
-
-int ft2232_register_commands(struct command_context_s *cmd_ctx)
-{
- register_command(cmd_ctx, NULL, "ft2232_device_desc", ft2232_handle_device_desc_command,
- COMMAND_CONFIG, NULL);
- register_command(cmd_ctx, NULL, "ft2232_serial", ft2232_handle_serial_command,
- COMMAND_CONFIG, NULL);
- register_command(cmd_ctx, NULL, "ft2232_layout", ft2232_handle_layout_command,
- COMMAND_CONFIG, NULL);
- register_command(cmd_ctx, NULL, "ft2232_vid_pid", ft2232_handle_vid_pid_command,
- COMMAND_CONFIG, NULL);
- register_command(cmd_ctx, NULL, "ft2232_latency", ft2232_handle_latency_command,
- COMMAND_CONFIG, NULL);
- return ERROR_OK;
-}
-
-void ft2232_end_state(enum tap_state state)
-{
- if (tap_move_map[state] != -1)
- end_state = state;
- else
- {
- ERROR("BUG: %i is not a valid end state", state);
- exit(-1);
- }
-}
-
-void ft2232_read_scan(enum scan_type type, u8* buffer, int scan_size)
-{
- int num_bytes = ((scan_size + 7) / 8);
- int bits_left = scan_size;
- int cur_byte = 0;
-
- while(num_bytes-- > 1)
- {
- buffer[cur_byte] = BUFFER_READ;
- cur_byte++;
- bits_left -= 8;
- }
-
- buffer[cur_byte] = 0x0;
-
- if (bits_left > 1)
- {
- buffer[cur_byte] = BUFFER_READ >> 1;
- }
-
- buffer[cur_byte] = (buffer[cur_byte] | ((BUFFER_READ & 0x02) << 6)) >> (8 - bits_left);
-
-}
-
-void ft2232_debug_dump_buffer(void)
-{
- int i;
- char line[256];
- char *line_p = line;
-
- for (i = 0; i < ft2232_buffer_size; i++)
- {
- line_p += snprintf(line_p, 256 - (line_p - line), "%2.2x ", ft2232_buffer[i]);
- if (i % 16 == 15)
- {
- DEBUG("%s", line);
- line_p = line;
- }
- }
-
- if (line_p != line)
- DEBUG("%s", line);
-}
-
-int ft2232_send_and_recv(jtag_command_t *first, jtag_command_t *last)
-{
- jtag_command_t *cmd;
- u8 *buffer;
- int scan_size;
- enum scan_type type;
- int retval;
- u32 bytes_written;
- u32 bytes_read;
-
-#ifdef _DEBUG_USB_IO_
- struct timeval start, inter, inter2, end;
- struct timeval d_inter, d_inter2, d_end;
-#endif
-
-#ifdef _DEBUG_USB_COMMS_
- DEBUG("write buffer (size %i):", ft2232_buffer_size);
- ft2232_debug_dump_buffer();
-#endif
-
-#ifdef _DEBUG_USB_IO_
- gettimeofday(&start, NULL);
-#endif
-
- if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK)
- {
- ERROR("couldn't write MPSSE commands to FT2232");
- exit(-1);
- }
-
-#ifdef _DEBUG_USB_IO_
- gettimeofday(&inter, NULL);
-#endif
-
- if (ft2232_expect_read)
- {
- int timeout = 100;
- ft2232_buffer_size = 0;
-
-#ifdef _DEBUG_USB_IO_
- gettimeofday(&inter2, NULL);
-#endif
-
- if ((retval = ft2232_read(ft2232_buffer, ft2232_expect_read, &bytes_read)) != ERROR_OK)
- {
- ERROR("couldn't read from FT2232");
- exit(-1);
- }
-
-#ifdef _DEBUG_USB_IO_
- gettimeofday(&end, NULL);
-
- timeval_subtract(&d_inter, &inter, &start);
- timeval_subtract(&d_inter2, &inter2, &start);
- timeval_subtract(&d_end, &end, &start);
-
- INFO("inter: %i.%i, inter2: %i.%i end: %i.%i", d_inter.tv_sec, d_inter.tv_usec, d_inter2.tv_sec, d_inter2.tv_usec, d_end.tv_sec, d_end.tv_usec);
-#endif
-
-
- ft2232_buffer_size = bytes_read;
-
- if (ft2232_expect_read != ft2232_buffer_size)
- {
- ERROR("ft2232_expect_read (%i) != ft2232_buffer_size (%i) (%i retries)", ft2232_expect_read, ft2232_buffer_size, 100 - timeout);
- ft2232_debug_dump_buffer();
-
- exit(-1);
- }
-
-#ifdef _DEBUG_USB_COMMS_
- DEBUG("read buffer (%i retries): %i bytes", 100 - timeout, ft2232_buffer_size);
- ft2232_debug_dump_buffer();
-#endif
- }
-
- ft2232_expect_read = 0;
- ft2232_read_pointer = 0;
-
- /* return ERROR_OK, unless a jtag_read_buffer returns a failed check
- * that wasn't handled by a caller-provided error handler
- */
- retval = ERROR_OK;
-
- cmd = first;
- while (cmd != last)
- {
- switch (cmd->type)
- {
- case JTAG_SCAN:
- type = jtag_scan_type(cmd->cmd.scan);
- if (type != SCAN_OUT)
- {
- scan_size = jtag_scan_size(cmd->cmd.scan);
- buffer = calloc(CEIL(scan_size, 8), 1);
- ft2232_read_scan(type, buffer, scan_size);
- if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
- retval = ERROR_JTAG_QUEUE_FAILED;
- free(buffer);
- }
- break;
- default:
- break;
- }
- cmd = cmd->next;
- }
-
- ft2232_buffer_size = 0;
-
- return retval;
-}
-
-void ft2232_add_pathmove(pathmove_command_t *cmd)
-{
- int num_states = cmd->num_states;
- u8 tms_byte;
- int state_count;
-
- state_count = 0;
- while (num_states)
- {
- tms_byte = 0x0;
- int bit_count = 0;
-
- /* command "Clock Data to TMS/CS Pin (no Read)" */
- BUFFER_ADD = 0x4b;
- /* number of states remaining */
- BUFFER_ADD = (num_states % 7) - 1;
-
- while (num_states % 7)
- {
- if (tap_transitions[cur_state].low == cmd->path[state_count])
- buf_set_u32(&tms_byte, bit_count++, 1, 0x0);
- else if (tap_transitions[cur_state].high == cmd->path[state_count])
- buf_set_u32(&tms_byte, bit_count++, 1, 0x1);
- else
- {
- ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_strings[cur_state], tap_state_strings[cmd->path[state_count]]);
- exit(-1);
- }
-
- cur_state = cmd->path[state_count];
- state_count++;
- num_states--;
- }
-
- BUFFER_ADD = tms_byte;
- }
-
- end_state = cur_state;
-}
-
-void ft2232_add_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
-{
- int num_bytes = (scan_size + 7) / 8;
- int bits_left = scan_size;
- int cur_byte = 0;
- int last_bit;
-
- if (!((!ir_scan && (cur_state == TAP_SD)) || (ir_scan && (cur_state == TAP_SI))))
- {
- /* command "Clock Data to TMS/CS Pin (no Read)" */
- BUFFER_ADD = 0x4b;
- /* scan 7 bit */
- BUFFER_ADD = 0x6;
- /* TMS data bits */
- if (ir_scan)
- {
- BUFFER_ADD = TAP_MOVE(cur_state, TAP_SI);
- cur_state = TAP_SI;
- }
- else
- {
- BUFFER_ADD = TAP_MOVE(cur_state, TAP_SD);
- cur_state = TAP_SD;
- }
- //DEBUG("added TMS scan (no read)");
- }
-
- /* add command for complete bytes */
- while (num_bytes > 1)
- {
- int thisrun_bytes;
- if (type == SCAN_IO)
- {
- /* Clock Data Bytes In and Out LSB First */
- BUFFER_ADD = 0x39;
- //DEBUG("added TDI bytes (io %i)", num_bytes);
- }
- else if (type == SCAN_OUT)
- {
- /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */
- BUFFER_ADD = 0x19;
- //DEBUG("added TDI bytes (o)");
- }
- else if (type == SCAN_IN)
- {
- /* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */
- BUFFER_ADD = 0x28;
- //DEBUG("added TDI bytes (i %i)", num_bytes);
- }
- thisrun_bytes = (num_bytes > 65537) ? 65536 : (num_bytes - 1);
- num_bytes -= thisrun_bytes;
- BUFFER_ADD = (thisrun_bytes - 1) & 0xff;
- BUFFER_ADD = ((thisrun_bytes - 1) >> 8) & 0xff;
- if (type != SCAN_IN)
- {
- /* add complete bytes */
- while(thisrun_bytes-- > 0)
- {
- BUFFER_ADD = buffer[cur_byte];
- cur_byte++;
- bits_left -= 8;
- }
- }
- else /* (type == SCAN_IN) */
- {
- bits_left -= 8 * (thisrun_bytes);
- }
- }
-
- /* the most signifcant bit is scanned during TAP movement */
- if (type != SCAN_IN)
- last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1;
- else
- last_bit = 0;
-
- /* process remaining bits but the last one */
- if (bits_left > 1)
- {
- if (type == SCAN_IO)
- {
- /* Clock Data Bits In and Out LSB First */
- BUFFER_ADD = 0x3b;
- //DEBUG("added TDI bits (io) %i", bits_left - 1);
- }
- else if (type == SCAN_OUT)
- {
- /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */
- BUFFER_ADD = 0x1b;
- //DEBUG("added TDI bits (o)");
- }
- else if (type == SCAN_IN)
- {
- /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */
- BUFFER_ADD = 0x2a;
- //DEBUG("added TDI bits (i %i)", bits_left - 1);
- }
- BUFFER_ADD = bits_left - 2;
- if (type != SCAN_IN)
- BUFFER_ADD = buffer[cur_byte];
- }
-
- if ((ir_scan && (end_state == TAP_SI)) ||
- (!ir_scan && (end_state == TAP_SD)))
- {
- if (type == SCAN_IO)
- {
- /* Clock Data Bits In and Out LSB First */
- BUFFER_ADD = 0x3b;
- //DEBUG("added TDI bits (io) %i", bits_left - 1);
- }
- else if (type == SCAN_OUT)
- {
- /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */
- BUFFER_ADD = 0x1b;
- //DEBUG("added TDI bits (o)");
- }
- else if (type == SCAN_IN)
- {
- /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */
- BUFFER_ADD = 0x2a;
- //DEBUG("added TDI bits (i %i)", bits_left - 1);
- }
- BUFFER_ADD = 0x0;
- BUFFER_ADD = last_bit;
- }
- else
- {
- /* move from Shift-IR/DR to end state */
- if (type != SCAN_OUT)
- {
- /* Clock Data to TMS/CS Pin with Read */
- BUFFER_ADD = 0x6b;
- //DEBUG("added TMS scan (read)");
- }
- else
- {
- /* Clock Data to TMS/CS Pin (no Read) */
- BUFFER_ADD = 0x4b;
- //DEBUG("added TMS scan (no read)");
- }
- BUFFER_ADD = 0x6;
- BUFFER_ADD = TAP_MOVE(cur_state, end_state) | (last_bit << 7);
- cur_state = end_state;
- }
-}
-
-int ft2232_large_scan(scan_command_t *cmd, enum scan_type type, u8 *buffer, int scan_size)
-{
- int num_bytes = (scan_size + 7) / 8;
- int bits_left = scan_size;
- int cur_byte = 0;
- int last_bit;
- u8 *receive_buffer = malloc(CEIL(scan_size, 8));
- u8 *receive_pointer = receive_buffer;
- u32 bytes_written;
- u32 bytes_read;
- int retval;
- int thisrun_read = 0;
-
- if (cmd->ir_scan)
- {
- ERROR("BUG: large IR scans are not supported");
- exit(-1);
- }
-
- if (cur_state != TAP_SD)
- {
- /* command "Clock Data to TMS/CS Pin (no Read)" */
- BUFFER_ADD = 0x4b;
- /* scan 7 bit */
- BUFFER_ADD = 0x6;
- /* TMS data bits */
- BUFFER_ADD = TAP_MOVE(cur_state, TAP_SD);
- cur_state = TAP_SD;
- }
-
- if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK)
- {
- ERROR("couldn't write MPSSE commands to FT2232");
- exit(-1);
- }
- DEBUG("ft2232_buffer_size: %i, bytes_written: %i", ft2232_buffer_size, bytes_written);
- ft2232_buffer_size = 0;
-
- /* add command for complete bytes */
- while (num_bytes > 1)
- {
- int thisrun_bytes;
-
- if (type == SCAN_IO)
- {
- /* Clock Data Bytes In and Out LSB First */
- BUFFER_ADD = 0x39;
- //DEBUG("added TDI bytes (io %i)", num_bytes);
- }
- else if (type == SCAN_OUT)
- {
- /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */
- BUFFER_ADD = 0x19;
- //DEBUG("added TDI bytes (o)");
- }
- else if (type == SCAN_IN)
- {
- /* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */
- BUFFER_ADD = 0x28;
- //DEBUG("added TDI bytes (i %i)", num_bytes);
- }
- thisrun_bytes = (num_bytes > 65537) ? 65536 : (num_bytes - 1);
- thisrun_read = thisrun_bytes;
- num_bytes -= thisrun_bytes;
- BUFFER_ADD = (thisrun_bytes - 1) & 0xff;
- BUFFER_ADD = ((thisrun_bytes - 1) >> 8) & 0xff;
- if (type != SCAN_IN)
- {
- /* add complete bytes */
- while(thisrun_bytes-- > 0)
- {
- BUFFER_ADD = buffer[cur_byte];
- cur_byte++;
- bits_left -= 8;
- }
- }
- else /* (type == SCAN_IN) */
- {
- bits_left -= 8 * (thisrun_bytes);
- }
-
- if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK)
- {
- ERROR("couldn't write MPSSE commands to FT2232");
- exit(-1);
- }
- DEBUG("ft2232_buffer_size: %i, bytes_written: %i", ft2232_buffer_size, bytes_written);
- ft2232_buffer_size = 0;
-
- if (type != SCAN_OUT)
- {
- if ((retval = ft2232_read(receive_pointer, thisrun_read, &bytes_read)) != ERROR_OK)
- {
- ERROR("couldn't read from FT2232");
- exit(-1);
- }
- DEBUG("thisrun_read: %i, bytes_read: %i", thisrun_read, bytes_read);
- receive_pointer += bytes_read;
- }
- }
-
- thisrun_read = 0;
-
- /* the most signifcant bit is scanned during TAP movement */
- if (type != SCAN_IN)
- last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1;
- else
- last_bit = 0;
-
- /* process remaining bits but the last one */
- if (bits_left > 1)
- {
- if (type == SCAN_IO)
- {
- /* Clock Data Bits In and Out LSB First */
- BUFFER_ADD = 0x3b;
- //DEBUG("added TDI bits (io) %i", bits_left - 1);
- }
- else if (type == SCAN_OUT)
- {
- /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */
- BUFFER_ADD = 0x1b;
- //DEBUG("added TDI bits (o)");
- }
- else if (type == SCAN_IN)
- {
- /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */
- BUFFER_ADD = 0x2a;
- //DEBUG("added TDI bits (i %i)", bits_left - 1);
- }
- BUFFER_ADD = bits_left - 2;
- if (type != SCAN_IN)
- BUFFER_ADD = buffer[cur_byte];
-
- if (type != SCAN_OUT)
- thisrun_read += 2;
- }
-
- if (end_state == TAP_SD)
- {
- if (type == SCAN_IO)
- {
- /* Clock Data Bits In and Out LSB First */
- BUFFER_ADD = 0x3b;
- //DEBUG("added TDI bits (io) %i", bits_left - 1);
- }
- else if (type == SCAN_OUT)
- {
- /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */
- BUFFER_ADD = 0x1b;
- //DEBUG("added TDI bits (o)");
- }
- else if (type == SCAN_IN)
- {
- /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */
- BUFFER_ADD = 0x2a;
- //DEBUG("added TDI bits (i %i)", bits_left - 1);
- }
- BUFFER_ADD = 0x0;
- BUFFER_ADD = last_bit;
- }
- else
- {
- /* move from Shift-IR/DR to end state */
- if (type != SCAN_OUT)
- {
- /* Clock Data to TMS/CS Pin with Read */
- BUFFER_ADD = 0x6b;
- //DEBUG("added TMS scan (read)");
- }
- else
- {
- /* Clock Data to TMS/CS Pin (no Read) */
- BUFFER_ADD = 0x4b;
- //DEBUG("added TMS scan (no read)");
- }
- BUFFER_ADD = 0x6;
- BUFFER_ADD = TAP_MOVE(cur_state, end_state) | (last_bit << 7);
- cur_state = end_state;
- }
-
- if (type != SCAN_OUT)
- thisrun_read += 1;
-
- if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK)
- {
- ERROR("couldn't write MPSSE commands to FT2232");
- exit(-1);
- }
- DEBUG("ft2232_buffer_size: %i, bytes_written: %i", ft2232_buffer_size, bytes_written);
- ft2232_buffer_size = 0;
-
- if (type != SCAN_OUT)
- {
- if ((retval = ft2232_read(receive_pointer, thisrun_read, &bytes_read)) != ERROR_OK)
- {
- ERROR("couldn't read from FT2232");
- exit(-1);
- }
- DEBUG("thisrun_read: %i, bytes_read: %i", thisrun_read, bytes_read);
- receive_pointer += bytes_read;
- }
-
- return ERROR_OK;
-}
-
-int ft2232_predict_scan_out(int scan_size, enum scan_type type)
-{
- int predicted_size = 3;
- int num_bytes = (scan_size - 1) / 8;
-
- if (cur_state != TAP_SD)
- predicted_size += 3;
-
- if (type == SCAN_IN) /* only from device to host */
- {
- /* complete bytes */
- predicted_size += (CEIL(num_bytes, 65536)) * 3;
- /* remaining bits - 1 (up to 7) */
- predicted_size += ((scan_size - 1) % 8) ? 2 : 0;
- }
- else /* host to device, or bidirectional */
- {
- /* complete bytes */
- predicted_size += num_bytes + (CEIL(num_bytes, 65536)) * 3;
- /* remaining bits -1 (up to 7) */
- predicted_size += ((scan_size - 1) % 8) ? 3 : 0;
- }
-
- return predicted_size;
-}
-
-int ft2232_predict_scan_in(int scan_size, enum scan_type type)
-{
- int predicted_size = 0;
-
- if (type != SCAN_OUT)
- {
- /* complete bytes */
- predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) - 1) : 0;
- /* remaining bits - 1 */
- predicted_size += ((scan_size - 1) % 8) ? 1 : 0;
- /* last bit (from TMS scan) */
- predicted_size += 1;
- }
-
- //DEBUG("scan_size: %i, predicted_size: %i", scan_size, predicted_size);
-
- return predicted_size;
-}
-
-void usbjtag_reset(int trst, int srst)
-{
- if (trst == 1)
- {
- cur_state = TAP_TLR;
- if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
- low_direction |= nTRSTnOE; /* switch to output pin (output is low) */
- else
- low_output &= ~nTRST; /* switch output low */
- }
- else if (trst == 0)
- {
- if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
- low_direction &= ~nTRSTnOE; /* switch to input pin (high-Z + internal and external pullup) */
- else
- low_output |= nTRST; /* switch output high */
- }
-
- if (srst == 1)
- {
- if (jtag_reset_config & RESET_SRST_PUSH_PULL)
- low_output &= ~nSRST; /* switch output low */
- else
- low_direction |= nSRSTnOE; /* switch to output pin (output is low) */
- }
- else if (srst == 0)
- {
- if (jtag_reset_config & RESET_SRST_PUSH_PULL)
- low_output |= nSRST; /* switch output high */
- else
- low_direction &= ~nSRSTnOE; /* switch to input pin (high-Z) */
- }
-
- /* command "set data bits low byte" */
- BUFFER_ADD = 0x80;
- BUFFER_ADD = low_output;
- BUFFER_ADD = low_direction;
-
-}
-
-void jtagkey_reset(int trst, int srst)
-{
- if (trst == 1)
- {
- cur_state = TAP_TLR;
- if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
- high_output &= ~nTRSTnOE;
- else
- high_output &= ~nTRST;
- }
- else if (trst == 0)
- {
- if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
- high_output |= nTRSTnOE;
- else
- high_output |= nTRST;
- }
-
- if (srst == 1)
- {
- if (jtag_reset_config & RESET_SRST_PUSH_PULL)
- high_output &= ~nSRST;
- else
- high_output &= ~nSRSTnOE;
- }
- else if (srst == 0)
- {
- if (jtag_reset_config & RESET_SRST_PUSH_PULL)
- high_output |= nSRST;
- else
- high_output |= nSRSTnOE;
- }
-
- /* command "set data bits high byte" */
- BUFFER_ADD = 0x82;
- BUFFER_ADD = high_output;
- BUFFER_ADD = high_direction;
- DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction);
-}
-
-void olimex_jtag_reset(int trst, int srst)
-{
- if (trst == 1)
- {
- cur_state = TAP_TLR;
- if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
- high_output &= ~nTRSTnOE;
- else
- high_output &= ~nTRST;
- }
- else if (trst == 0)
- {
- if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
- high_output |= nTRSTnOE;
- else
- high_output |= nTRST;
- }
-
- if (srst == 1)
- {
- high_output |= nSRST;
- }
- else if (srst == 0)
- {
- high_output &= ~nSRST;
- }
-
- /* command "set data bits high byte" */
- BUFFER_ADD = 0x82;
- BUFFER_ADD = high_output;
- BUFFER_ADD = high_direction;
- DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction);
-}
-
-void flyswatter_reset(int trst, int srst)
-{
- if (trst == 1)
- {
- cur_state = TAP_TLR;
- low_output &= ~nTRST;
- }
- else if (trst == 0)
- {
- low_output |= nTRST;
- }
-
- if (srst == 1)
- {
- low_output |= nSRST;
- }
- else if (srst == 0)
- {
- low_output &= ~nSRST;
- }
-
- /* command "set data bits low byte" */
- BUFFER_ADD = 0x80;
- BUFFER_ADD = low_output;
- BUFFER_ADD = low_direction;
- DEBUG("trst: %i, srst: %i, low_output: 0x%2.2x, low_direction: 0x%2.2x", trst, srst, low_output, low_direction);
-}
-
-void turtle_reset(int trst, int srst)
-{
- trst = trst;
-
- if (srst == 1)
- {
- low_output |= nSRST;
- }
- else if (srst == 0)
- {
- low_output &= ~nSRST;
- }
-
- /* command "set data bits low byte" */
- BUFFER_ADD = 0x80;
- BUFFER_ADD = low_output;
- BUFFER_ADD = low_direction;
- DEBUG("srst: %i, low_output: 0x%2.2x, low_direction: 0x%2.2x", srst, low_output, low_direction);
-}
-
-void comstick_reset(int trst, int srst)
-{
- if (trst == 1)
- {
- cur_state = TAP_TLR;
- high_output &= ~nTRST;
- }
- else if (trst == 0)
- {
- high_output |= nTRST;
- }
-
- if (srst == 1)
- {
- high_output &= ~nSRST;
- }
- else if (srst == 0)
- {
- high_output |= nSRST;
- }
-
- /* command "set data bits high byte" */
- BUFFER_ADD = 0x82;
- BUFFER_ADD = high_output;
- BUFFER_ADD = high_direction;
- DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction);
-}
-
-void stm32stick_reset(int trst, int srst)
-{
- if (trst == 1)
- {
- cur_state = TAP_TLR;
- high_output &= ~nTRST;
- }
- else if (trst == 0)
- {
- high_output |= nTRST;
- }
-
- if (srst == 1)
- {
- low_output &= ~nSRST;
- }
- else if (srst == 0)
- {
- low_output |= nSRST;
- }
-
- /* command "set data bits low byte" */
- BUFFER_ADD = 0x80;
- BUFFER_ADD = low_output;
- BUFFER_ADD = low_direction;
-
- /* command "set data bits high byte" */
- BUFFER_ADD = 0x82;
- BUFFER_ADD = high_output;
- BUFFER_ADD = high_direction;
- DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction);
-}
-
-int ft2232_execute_queue()
-{
- jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
- jtag_command_t *first_unsent = cmd; /* next command that has to be sent */
- u8 *buffer;
- int scan_size; /* size of IR or DR scan */
- enum scan_type type;
- int i;
- int predicted_size = 0;
- int require_send = 0;
- int retval;
-
- /* return ERROR_OK, unless ft2232_send_and_recv reports a failed check
- * that wasn't handled by a caller-provided error handler
- */
- retval = ERROR_OK;
-
- ft2232_buffer_size = 0;
- ft2232_expect_read = 0;
-
- /* blink, if the current layout has that feature */
- if (layout->blink)
- layout->blink();
-
- while (cmd)
- {
- switch(cmd->type)
- {
- case JTAG_END_STATE:
- if (cmd->cmd.end_state->end_state != -1)
- ft2232_end_state(cmd->cmd.end_state->end_state);
- break;
- case JTAG_RESET:
- /* only send the maximum buffer size that FT2232C can handle */
- predicted_size = 3;
- if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
- {
- if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
- retval = ERROR_JTAG_QUEUE_FAILED;
- require_send = 0;
- first_unsent = cmd;
- }
-
- layout->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
- require_send = 1;
-
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("trst: %i, srst: %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
-#endif
- break;
- case JTAG_RUNTEST:
- /* only send the maximum buffer size that FT2232C can handle */
- predicted_size = 0;
- if (cur_state != TAP_RTI)
- predicted_size += 3;
- predicted_size += 3 * CEIL(cmd->cmd.runtest->num_cycles, 7);
- if ((cmd->cmd.runtest->end_state != -1) && (cmd->cmd.runtest->end_state != TAP_RTI))
- predicted_size += 3;
- if ((cmd->cmd.runtest->end_state == -1) && (end_state != TAP_RTI))
- predicted_size += 3;
- if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
- {
- if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
- retval = ERROR_JTAG_QUEUE_FAILED;
- require_send = 0;
- first_unsent = cmd;
- }
- if (cur_state != TAP_RTI)
- {
- /* command "Clock Data to TMS/CS Pin (no Read)" */
- BUFFER_ADD = 0x4b;
- /* scan 7 bit */
- BUFFER_ADD = 0x6;
- /* TMS data bits */
- BUFFER_ADD = TAP_MOVE(cur_state, TAP_RTI);
- cur_state = TAP_RTI;
- require_send = 1;
- }
- i = cmd->cmd.runtest->num_cycles;
- while (i > 0)
- {
- /* command "Clock Data to TMS/CS Pin (no Read)" */
- BUFFER_ADD = 0x4b;
- /* scan 7 bit */
- BUFFER_ADD = (i > 7) ? 6 : (i - 1);
- /* TMS data bits */
- BUFFER_ADD = 0x0;
- cur_state = TAP_RTI;
- i -= (i > 7) ? 7 : i;
- //DEBUG("added TMS scan (no read)");
- }
- if (cmd->cmd.runtest->end_state != -1)
- ft2232_end_state(cmd->cmd.runtest->end_state);
- if (cur_state != end_state)
- {
- /* command "Clock Data to TMS/CS Pin (no Read)" */
- BUFFER_ADD = 0x4b;
- /* scan 7 bit */
- BUFFER_ADD = 0x6;
- /* TMS data bits */
- BUFFER_ADD = TAP_MOVE(cur_state, end_state);
- cur_state = end_state;
- //DEBUG("added TMS scan (no read)");
- }
- require_send = 1;
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("runtest: %i, end in %i", cmd->cmd.runtest->num_cycles, end_state);
-#endif
- break;
- case JTAG_STATEMOVE:
- /* only send the maximum buffer size that FT2232C can handle */
- predicted_size = 3;
- if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
- {
- if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
- retval = ERROR_JTAG_QUEUE_FAILED;
- require_send = 0;
- first_unsent = cmd;
- }
- if (cmd->cmd.statemove->end_state != -1)
- ft2232_end_state(cmd->cmd.statemove->end_state);
- /* command "Clock Data to TMS/CS Pin (no Read)" */
- BUFFER_ADD = 0x4b;
- /* scan 7 bit */
- BUFFER_ADD = 0x6;
- /* TMS data bits */
- BUFFER_ADD = TAP_MOVE(cur_state, end_state);
- //DEBUG("added TMS scan (no read)");
- cur_state = end_state;
- require_send = 1;
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("statemove: %i", end_state);
-#endif
- break;
- case JTAG_PATHMOVE:
- /* only send the maximum buffer size that FT2232C can handle */
- predicted_size = 3 * CEIL(cmd->cmd.pathmove->num_states, 7);
- if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
- {
- if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
- retval = ERROR_JTAG_QUEUE_FAILED;
- require_send = 0;
- first_unsent = cmd;
- }
- ft2232_add_pathmove(cmd->cmd.pathmove);
- require_send = 1;
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
-#endif
- break;
- case JTAG_SCAN:
- scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
- type = jtag_scan_type(cmd->cmd.scan);
- predicted_size = ft2232_predict_scan_out(scan_size, type);
- if ((predicted_size + 1) > FT2232_BUFFER_SIZE)
- {
- DEBUG("oversized ft2232 scan (predicted_size > FT2232_BUFFER_SIZE)");
- /* unsent commands before this */
- if (first_unsent != cmd)
- if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
- retval = ERROR_JTAG_QUEUE_FAILED;
-
- /* current command */
- if (cmd->cmd.scan->end_state != -1)
- ft2232_end_state(cmd->cmd.scan->end_state);
- ft2232_large_scan(cmd->cmd.scan, type, buffer, scan_size);
- require_send = 0;
- first_unsent = cmd->next;
- if (buffer)
- free(buffer);
- break;
- }
- else if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE)
- {
- DEBUG("ft2232 buffer size reached, sending queued commands (first_unsent: %p, cmd: %p)", first_unsent, cmd);
- if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
- retval = ERROR_JTAG_QUEUE_FAILED;
- require_send = 0;
- first_unsent = cmd;
- }
- ft2232_expect_read += ft2232_predict_scan_in(scan_size, type);
- //DEBUG("new read size: %i", ft2232_expect_read);
- if (cmd->cmd.scan->end_state != -1)
- ft2232_end_state(cmd->cmd.scan->end_state);
- ft2232_add_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
- require_send = 1;
- if (buffer)
- free(buffer);
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("%s scan, %i bit, end in %i", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size, end_state);
-#endif
- break;
- case JTAG_SLEEP:
- if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
- retval = ERROR_JTAG_QUEUE_FAILED;
- first_unsent = cmd->next;
- jtag_sleep(cmd->cmd.sleep->us);
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("sleep %i usec", cmd->cmd.sleep->us);
-#endif
- break;
- default:
- ERROR("BUG: unknown JTAG command type encountered");
- exit(-1);
- }
- cmd = cmd->next;
- }
-
- if (require_send > 0)
- if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK)
- retval = ERROR_JTAG_QUEUE_FAILED;
-
- return retval;
-}
-
-#if BUILD_FT2232_FTD2XX == 1
-static int ft2232_init_ftd2xx(u16 vid, u16 pid, int more, int *try_more)
-{
- FT_STATUS status;
- DWORD openex_flags = 0;
- char *openex_string = NULL;
- u8 latency_timer;
-
- DEBUG("'ft2232' interface using FTD2XX with '%s' layout (%4.4x:%4.4x)",
- ft2232_layout, vid, pid);
-
-#if IS_WIN32 == 0
- /* Add non-standard Vid/Pid to the linux driver */
- if ((status = FT_SetVIDPID(vid, pid)) != FT_OK)
- {
- WARNING("couldn't add %4.4x:%4.4x",
- vid, pid);
- }
-#endif
-
- if (ft2232_device_desc && ft2232_serial)
- {
- WARNING("can't open by device description and serial number, giving precedence to serial");
- ft2232_device_desc = NULL;
- }
-
- if (ft2232_device_desc)
- {
- openex_string = ft2232_device_desc;
- openex_flags = FT_OPEN_BY_DESCRIPTION;
- }
- else if (ft2232_serial)
- {
- openex_string = ft2232_serial;
- openex_flags = FT_OPEN_BY_SERIAL_NUMBER;
- }
- else
- {
- ERROR("neither device description nor serial number specified");
- ERROR("please add \"ft2232_device_desc <string>\" or \"ft2232_serial <string>\" to your .cfg file");
-
- return ERROR_JTAG_INIT_FAILED;
- }
-
- if ((status = FT_OpenEx(openex_string, openex_flags, &ftdih)) != FT_OK)
- {
- DWORD num_devices;
-
- if (more) {
- WARNING("unable to open ftdi device (trying more): %lu",
- status);
- *try_more = 1;
- return ERROR_JTAG_INIT_FAILED;
- }
- ERROR("unable to open ftdi device: %lu", status);
- status = FT_ListDevices(&num_devices, NULL, FT_LIST_NUMBER_ONLY);
- if (status == FT_OK)
- {
- char **desc_array = malloc(sizeof(char*) * (num_devices + 1));
- int i;
-
- for (i = 0; i < num_devices; i++)
- desc_array[i] = malloc(64);
- desc_array[num_devices] = NULL;
-
- status = FT_ListDevices(desc_array, &num_devices, FT_LIST_ALL | openex_flags);
-
- if (status == FT_OK)
- {
- ERROR("ListDevices: %lu\n", num_devices);
- for (i = 0; i < num_devices; i++)
- ERROR("%i: %s", i, desc_array[i]);
- }
-
- for (i = 0; i < num_devices; i++)
- free(desc_array[i]);
- free(desc_array);
- }
- else
- {
- ERROR("ListDevices: NONE\n");
- }
- return ERROR_JTAG_INIT_FAILED;
- }
-
- if ((status = FT_SetLatencyTimer(ftdih, ft2232_latency)) != FT_OK)
- {
- ERROR("unable to set latency timer: %lu", status);
- return ERROR_JTAG_INIT_FAILED;
- }
-
- if ((status = FT_GetLatencyTimer(ftdih, &latency_timer)) != FT_OK)
- {
- ERROR("unable to get latency timer: %lu", status);
- return ERROR_JTAG_INIT_FAILED;
- }
- else
- {
- DEBUG("current latency timer: %i", latency_timer);
- }
-
- if ((status = FT_SetTimeouts(ftdih, 5000, 5000)) != FT_OK)
- {
- ERROR("unable to set timeouts: %lu", status);
- return ERROR_JTAG_INIT_FAILED;
- }
-
- if ((status = FT_SetBitMode(ftdih, 0x0b, 2)) != FT_OK)
- {
- ERROR("unable to enable bit i/o mode: %lu", status);
- return ERROR_JTAG_INIT_FAILED;
- }
-
- return ERROR_OK;
-}
-
-static int ft2232_purge_ftd2xx(void)
-{
- FT_STATUS status;
-
- if ((status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX)) != FT_OK)
- {
- ERROR("error purging ftd2xx device: %lu", status);
- return ERROR_JTAG_INIT_FAILED;
- }
-
- return ERROR_OK;
-}
-#endif /* BUILD_FT2232_FTD2XX == 1 */
-
-#if BUILD_FT2232_LIBFTDI == 1
-static int ft2232_init_libftdi(u16 vid, u16 pid, int more, int *try_more)
-{
- u8 latency_timer;
-
- DEBUG("'ft2232' interface using libftdi with '%s' layout (%4.4x:%4.4x)",
- ft2232_layout, vid, pid);
-
- if (ftdi_init(&ftdic) < 0)
- return ERROR_JTAG_INIT_FAILED;
-
- /* context, vendor id, product id */
- if (ftdi_usb_open_desc(&ftdic, vid, pid, ft2232_device_desc,
- ft2232_serial) < 0) {
- if (more)
- WARNING("unable to open ftdi device (trying more): %s",
- ftdic.error_str);
- else
- ERROR("unable to open ftdi device: %s", ftdic.error_str);
- *try_more = 1;
- return ERROR_JTAG_INIT_FAILED;
- }
-
- if (ftdi_set_interface(&ftdic, INTERFACE_A) < 0)
- {
- ERROR("unable to select FT2232 channel A: %s", ftdic.error_str);
- return ERROR_JTAG_INIT_FAILED;
- }
-
- if (ftdi_usb_reset(&ftdic) < 0)
- {
- ERROR("unable to reset ftdi device");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- if (ftdi_set_latency_timer(&ftdic, ft2232_latency) < 0)
- {
- ERROR("unable to set latency timer");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- if (ftdi_get_latency_timer(&ftdic, &latency_timer) < 0)
- {
- ERROR("unable to get latency timer");
- return ERROR_JTAG_INIT_FAILED;
- }
- else
- {
- DEBUG("current latency timer: %i", latency_timer);
- }
-
- ftdi_set_bitmode(&ftdic, 0x0b, 2); /* ctx, JTAG I/O mask */
-
- return ERROR_OK;
-}
-
-static int ft2232_purge_libftdi(void)
-{
- if (ftdi_usb_purge_buffers(&ftdic) < 0)
- {
- ERROR("ftdi_purge_buffers: %s", ftdic.error_str);
- return ERROR_JTAG_INIT_FAILED;
- }
-
- return ERROR_OK;
-}
-#endif /* BUILD_FT2232_LIBFTDI == 1 */
-
-int ft2232_init(void)
-{
- u8 buf[1];
- int retval;
- u32 bytes_written;
- ft2232_layout_t *cur_layout = ft2232_layouts;
- int i;
-
- if ((ft2232_layout == NULL) || (ft2232_layout[0] == 0))
- {
- ft2232_layout = "usbjtag";
- WARNING("No ft2232 layout specified, using default 'usbjtag'");
- }
-
- while (cur_layout->name)
- {
- if (strcmp(cur_layout->name, ft2232_layout) == 0)
- {
- layout = cur_layout;
- break;
- }
- cur_layout++;
- }
-
- if (!layout)
- {
- ERROR("No matching layout found for %s", ft2232_layout);
- return ERROR_JTAG_INIT_FAILED;
- }
-
- for (i = 0; 1; i++) {
- /*
- * "more indicates that there are more IDs to try, so we should
- * not print an error for an ID mismatch (but for anything
- * else, we should).
- *
- * try_more indicates that the error code returned indicates an
- * ID mismatch (and nothing else) and that we should proceeed
- * with the next ID pair.
- */
- int more = ft2232_vid[i+1] || ft2232_pid[i+1];
- int try_more = 0;
-
-#if BUILD_FT2232_FTD2XX == 1
- retval = ft2232_init_ftd2xx(ft2232_vid[i], ft2232_pid[i],
- more, &try_more);
-#elif BUILD_FT2232_LIBFTDI == 1
- retval = ft2232_init_libftdi(ft2232_vid[i], ft2232_pid[i],
- more, &try_more);
-#endif
- if (retval >= 0)
- break;
- if (!more || !try_more)
- return retval;
- }
-
- ft2232_buffer_size = 0;
- ft2232_buffer = malloc(FT2232_BUFFER_SIZE);
-
- if (layout->init() != ERROR_OK)
- return ERROR_JTAG_INIT_FAILED;
-
- ft2232_speed(jtag_speed);
-
- buf[0] = 0x85; /* Disconnect TDI/DO to TDO/DI for Loopback */
- if (((retval = ft2232_write(buf, 1, &bytes_written)) != ERROR_OK) || (bytes_written != 1))
- {
- ERROR("couldn't write to FT2232 to disable loopback");
- return ERROR_JTAG_INIT_FAILED;
- }
-
-#if BUILD_FT2232_FTD2XX == 1
- return ft2232_purge_ftd2xx();
-#elif BUILD_FT2232_LIBFTDI == 1
- return ft2232_purge_libftdi();
-#endif
-
- return ERROR_OK;
-}
-
-int usbjtag_init(void)
-{
- u8 buf[3];
- u32 bytes_written;
-
- low_output = 0x08;
- low_direction = 0x0b;
-
- if (strcmp(ft2232_layout, "usbjtag") == 0)
- {
- nTRST = 0x10;
- nTRSTnOE = 0x10;
- nSRST = 0x40;
- nSRSTnOE = 0x40;
- }
- else if (strcmp(ft2232_layout, "signalyzer") == 0)
- {
- nTRST = 0x10;
- nTRSTnOE = 0x10;
- nSRST = 0x20;
- nSRSTnOE = 0x20;
- }
- else if (strcmp(ft2232_layout, "evb_lm3s811") == 0)
- {
- nTRST = 0x0;
- nTRSTnOE = 0x00;
- nSRST = 0x20;
- nSRSTnOE = 0x20;
- low_output = 0x88;
- low_direction = 0x8b;
- }
- else
- {
- ERROR("BUG: usbjtag_init called for unknown layout '%s'", ft2232_layout);
- return ERROR_JTAG_INIT_FAILED;
- }
-
- if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
- {
- low_direction &= ~nTRSTnOE; /* nTRST input */
- low_output &= ~nTRST; /* nTRST = 0 */
- }
- else
- {
- low_direction |= nTRSTnOE; /* nTRST output */
- low_output |= nTRST; /* nTRST = 1 */
- }
-
- if (jtag_reset_config & RESET_SRST_PUSH_PULL)
- {
- low_direction |= nSRSTnOE; /* nSRST output */
- low_output |= nSRST; /* nSRST = 1 */
- }
- else
- {
- low_direction &= ~nSRSTnOE; /* nSRST input */
- low_output &= ~nSRST; /* nSRST = 0 */
- }
-
- /* initialize low byte for jtag */
- buf[0] = 0x80; /* command "set data bits low byte" */
- buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, xRST high) */
- buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in */
- DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
-
- if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
- {
- ERROR("couldn't initialize FT2232 with 'USBJTAG' layout");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- return ERROR_OK;
-}
-
-int jtagkey_init(void)
-{
- u8 buf[3];
- u32 bytes_written;
-
- low_output = 0x08;
- low_direction = 0x1b;
-
- /* initialize low byte for jtag */
- buf[0] = 0x80; /* command "set data bits low byte" */
- buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */
- buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */
- DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
-
- if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
- {
- ERROR("couldn't initialize FT2232 with 'JTAGkey' layout");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- if (strcmp(layout->name, "jtagkey") == 0)
- {
- nTRST = 0x01;
- nTRSTnOE = 0x4;
- nSRST = 0x02;
- nSRSTnOE = 0x08;
- }
- else if ((strcmp(layout->name, "jtagkey_prototype_v1") == 0) ||
- (strcmp(layout->name, "oocdlink") == 0))
- {
- nTRST = 0x02;
- nTRSTnOE = 0x1;
- nSRST = 0x08;
- nSRSTnOE = 0x04;
- }
- else
- {
- ERROR("BUG: jtagkey_init called for non jtagkey layout");
- exit(-1);
- }
-
- high_output = 0x0;
- high_direction = 0x0f;
-
- if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
- {
- high_output |= nTRSTnOE;
- high_output &= ~nTRST;
- }
- else
- {
- high_output &= ~nTRSTnOE;
- high_output |= nTRST;
- }
-
- if (jtag_reset_config & RESET_SRST_PUSH_PULL)
- {
- high_output &= ~nSRSTnOE;
- high_output |= nSRST;
- }
- else
- {
- high_output |= nSRSTnOE;
- high_output &= ~nSRST;
- }
-
- /* initialize high port */
- buf[0] = 0x82; /* command "set data bits high byte" */
- buf[1] = high_output; /* value */
- buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */
- DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
-
- if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
- {
- ERROR("couldn't initialize FT2232 with 'JTAGkey' layout");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- return ERROR_OK;
-}
-
-int olimex_jtag_init(void)
-{
- u8 buf[3];
- u32 bytes_written;
-
- low_output = 0x08;
- low_direction = 0x1b;
-
- /* initialize low byte for jtag */
- buf[0] = 0x80; /* command "set data bits low byte" */
- buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */
- buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */
- DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
-
- if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
- {
- ERROR("couldn't initialize FT2232 with 'JTAGkey' layout");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- nTRST = 0x01;
- nTRSTnOE = 0x4;
- nSRST = 0x02;
- nSRSTnOE = 0x00; /* no output enable for nSRST */
-
- high_output = 0x0;
- high_direction = 0x0f;
-
- if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
- {
- high_output |= nTRSTnOE;
- high_output &= ~nTRST;
- }
- else
- {
- high_output &= ~nTRSTnOE;
- high_output |= nTRST;
- }
-
- if (jtag_reset_config & RESET_SRST_PUSH_PULL)
- {
- ERROR("can't set nSRST to push-pull on the Olimex ARM-USB-OCD");
- }
- else
- {
- high_output &= ~nSRST;
- }
-
- /* turn red LED on */
- high_output |= 0x08;
-
- /* initialize high port */
- buf[0] = 0x82; /* command "set data bits high byte" */
- buf[1] = high_output; /* value */
- buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */
- DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
-
- if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
- {
- ERROR("couldn't initialize FT2232 with 'JTAGkey' layout");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- return ERROR_OK;
-}
-
-int flyswatter_init(void)
-{
- u8 buf[3];
- u32 bytes_written;
-
- low_output = 0x18;
- low_direction = 0xfb;
-
- /* initialize low byte for jtag */
- buf[0] = 0x80; /* command "set data bits low byte" */
- buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */
- buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE[12]=out, n[ST]srst=out */
- DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
-
- if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
- {
- ERROR("couldn't initialize FT2232 with 'flyswatter' layout");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- nTRST = 0x10;
- nTRSTnOE = 0x0; /* not output enable for nTRST */
- nSRST = 0x20;
- nSRSTnOE = 0x00; /* no output enable for nSRST */
-
- high_output = 0x00;
- high_direction = 0x0c;
-
- /* turn red LED1 on, LED2 off */
- high_output |= 0x08;
-
- /* initialize high port */
- buf[0] = 0x82; /* command "set data bits high byte" */
- buf[1] = high_output; /* value */
- buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */
- DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
-
- if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
- {
- ERROR("couldn't initialize FT2232 with 'flyswatter' layout");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- return ERROR_OK;
-}
-
-int turtle_init(void)
-{
- u8 buf[3];
- u32 bytes_written;
-
- low_output = 0x08;
- low_direction = 0x5b;
-
- /* initialize low byte for jtag */
- buf[0] = 0x80; /* command "set data bits low byte" */
- buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */
- buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */
- DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
-
- if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
- {
- ERROR("couldn't initialize FT2232 with 'turtelizer2' layout");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- nSRST = 0x40;
-
- high_output = 0x00;
- high_direction = 0x0C;
-
- /* initialize high port */
- buf[0] = 0x82; /* command "set data bits high byte" */
- buf[1] = high_output;
- buf[2] = high_direction;
- DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
-
- if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
- {
- ERROR("couldn't initialize FT2232 with 'turtelizer2' layout");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- return ERROR_OK;
-}
-
-int comstick_init(void)
-{
- u8 buf[3];
- u32 bytes_written;
-
- low_output = 0x08;
- low_direction = 0x0b;
-
- /* initialize low byte for jtag */
- buf[0] = 0x80; /* command "set data bits low byte" */
- buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */
- buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */
- DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
-
- if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
- {
- ERROR("couldn't initialize FT2232 with 'comstick' layout");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- nTRST = 0x01;
- nTRSTnOE = 0x00; /* no output enable for nTRST */
- nSRST = 0x02;
- nSRSTnOE = 0x00; /* no output enable for nSRST */
-
- high_output = 0x03;
- high_direction = 0x03;
-
- /* initialize high port */
- buf[0] = 0x82; /* command "set data bits high byte" */
- buf[1] = high_output;
- buf[2] = high_direction;
- DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
-
- if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
- {
- ERROR("couldn't initialize FT2232 with 'comstick' layout");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- return ERROR_OK;
-}
-
-int stm32stick_init(void)
-{
- u8 buf[3];
- u32 bytes_written;
-
- low_output = 0x88;
- low_direction = 0x8b;
-
- /* initialize low byte for jtag */
- buf[0] = 0x80; /* command "set data bits low byte" */
- buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */
- buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */
- DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
-
- if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
- {
- ERROR("couldn't initialize FT2232 with 'stm32stick' layout");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- nTRST = 0x01;
- nTRSTnOE = 0x00; /* no output enable for nTRST */
- nSRST = 0x80;
- nSRSTnOE = 0x00; /* no output enable for nSRST */
-
- high_output = 0x01;
- high_direction = 0x03;
-
- /* initialize high port */
- buf[0] = 0x82; /* command "set data bits high byte" */
- buf[1] = high_output;
- buf[2] = high_direction;
- DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
-
- if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3))
- {
- ERROR("couldn't initialize FT2232 with 'stm32stick' layout");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- return ERROR_OK;
-}
-
-void olimex_jtag_blink(void)
-{
- /* Olimex ARM-USB-OCD has a LED connected to ACBUS3
- * ACBUS3 is bit 3 of the GPIOH port
- */
- if (high_output & 0x08)
- {
- /* set port pin high */
- high_output &= 0x07;
- }
- else
- {
- /* set port pin low */
- high_output |= 0x08;
- }
-
- BUFFER_ADD = 0x82;
- BUFFER_ADD = high_output;
- BUFFER_ADD = high_direction;
-}
-
-void turtle_jtag_blink(void)
-{
- /*
- * Turtelizer2 has two LEDs connected to ACBUS2 and ACBUS3
- */
- if (high_output & 0x08)
- {
- high_output = 0x04;
- }
- else
- {
- high_output = 0x08;
- }
-
- BUFFER_ADD = 0x82;
- BUFFER_ADD = high_output;
- BUFFER_ADD = high_direction;
-}
-
-
-int ft2232_quit(void)
-{
-#if BUILD_FT2232_FTD2XX == 1
- FT_STATUS status;
-
- status = FT_Close(ftdih);
-#elif BUILD_FT2232_LIBFTDI == 1
- ftdi_disable_bitbang(&ftdic);
-
- ftdi_usb_close(&ftdic);
-
- ftdi_deinit(&ftdic);
-#endif
-
- free(ft2232_buffer);
- ft2232_buffer = NULL;
-
- return ERROR_OK;
-}
-
-int ft2232_handle_device_desc_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 1)
- {
- ft2232_device_desc = strdup(args[0]);
- }
- else
- {
- ERROR("expected exactly one argument to ft2232_device_desc <description>");
- }
-
- return ERROR_OK;
-}
-
-int ft2232_handle_serial_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 1)
- {
- ft2232_serial = strdup(args[0]);
- }
- else
- {
- ERROR("expected exactly one argument to ft2232_serial <serial-number>");
- }
-
- return ERROR_OK;
-}
-
-int ft2232_handle_layout_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 0)
- return ERROR_OK;
-
- ft2232_layout = malloc(strlen(args[0]) + 1);
- strcpy(ft2232_layout, args[0]);
-
- return ERROR_OK;
-}
-
-int ft2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- int i;
-
- if (argc > MAX_USB_IDS*2) {
- WARNING("ignoring extra IDs in ft2232_vid_pid "
- "(maximum is %d pairs)", MAX_USB_IDS);
- argc = MAX_USB_IDS*2;
- }
- if (argc < 2 || (argc & 1))
- {
- WARNING("incomplete ft2232_vid_pid configuration directive");
- if (argc < 2)
- return ERROR_OK;
- }
-
- for (i = 0; i+1 < argc; i += 2) {
- ft2232_vid[i >> 1] = strtol(args[i], NULL, 0);
- ft2232_pid[i >> 1] = strtol(args[i+1], NULL, 0);
- }
- /*
- * Explicitly terminate, in case there are multiples instances of
- * ft2232_vid_pid.
- */
- ft2232_vid[i >> 1] = ft2232_pid[i >> 1] = 0;
-
- return ERROR_OK;
-}
-
-int ft2232_handle_latency_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 1)
- {
- ft2232_latency = atoi(args[0]);
- }
- else
- {
- ERROR("expected exactly one argument to ft2232_latency <ms>");
- }
-
- return ERROR_OK;
-}
-
-
+/*************************************************************************** + * Copyright (C) 2004, 2006 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 + +#if IS_CYGWIN == 1 +#include "windows.h" +#undef ERROR +#endif + +#include "replacements.h" + +/* project specific includes */ +#include "log.h" +#include "types.h" +#include "jtag.h" +#include "configuration.h" +#include "time_support.h" + +/* system includes */ +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +/* FT2232 access library includes */ +#if BUILD_FT2232_FTD2XX == 1 +#include <ftd2xx.h> +#elif BUILD_FT2232_LIBFTDI == 1 +#include <ftdi.h> +#endif + +#include <sys/time.h> +#include <time.h> + +/* enable this to debug io latency + */ +#if 0 +#define _DEBUG_USB_IO_ +#endif + +/* enable this to debug communication + */ +#if 0 +#define _DEBUG_USB_COMMS_ +#endif + +int ft2232_execute_queue(void); + +int ft2232_speed(int speed); +int ft2232_register_commands(struct command_context_s *cmd_ctx); +int ft2232_init(void); +int ft2232_quit(void); + +int ft2232_handle_device_desc_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int ft2232_handle_serial_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int ft2232_handle_layout_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int ft2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int ft2232_handle_latency_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +char *ft2232_device_desc = NULL; +char *ft2232_serial = NULL; +char *ft2232_layout = NULL; +unsigned char ft2232_latency = 2; + +#define MAX_USB_IDS 8 +/* vid = pid = 0 marks the end of the list */ +static u16 ft2232_vid[MAX_USB_IDS+1] = { 0x0403, 0 }; +static u16 ft2232_pid[MAX_USB_IDS+1] = { 0x6010, 0 }; + +typedef struct ft2232_layout_s +{ + char* name; + int(*init)(void); + void(*reset)(int trst, int srst); + void(*blink)(void); +} ft2232_layout_t; + +/* init procedures for supported layouts */ +int usbjtag_init(void); +int jtagkey_init(void); +int olimex_jtag_init(void); +int flyswatter_init(void); +int turtle_init(void); +int comstick_init(void); +int stm32stick_init(void); + +/* reset procedures for supported layouts */ +void usbjtag_reset(int trst, int srst); +void jtagkey_reset(int trst, int srst); +void olimex_jtag_reset(int trst, int srst); +void flyswatter_reset(int trst, int srst); +void turtle_reset(int trst, int srst); +void comstick_reset(int trst, int srst); +void stm32stick_reset(int trst, int srst); + +/* blink procedures for layouts that support a blinking led */ +void olimex_jtag_blink(void); +void turtle_jtag_blink(void); + +ft2232_layout_t ft2232_layouts[] = +{ + {"usbjtag", usbjtag_init, usbjtag_reset, NULL}, + {"jtagkey", jtagkey_init, jtagkey_reset, NULL}, + {"jtagkey_prototype_v1", jtagkey_init, jtagkey_reset, NULL}, + {"oocdlink", jtagkey_init, jtagkey_reset, NULL}, + {"signalyzer", usbjtag_init, usbjtag_reset, NULL}, + {"evb_lm3s811", usbjtag_init, usbjtag_reset, NULL}, + {"olimex-jtag", olimex_jtag_init, olimex_jtag_reset, olimex_jtag_blink}, + {"flyswatter", flyswatter_init, flyswatter_reset, NULL}, + {"turtelizer2", turtle_init, turtle_reset, turtle_jtag_blink}, + {"comstick", comstick_init, comstick_reset, NULL}, + {"stm32stick", stm32stick_init, stm32stick_reset, NULL}, + {NULL, NULL, NULL}, +}; + +static u8 nTRST, nTRSTnOE, nSRST, nSRSTnOE; + +static ft2232_layout_t *layout; +static u8 low_output = 0x0; +static u8 low_direction = 0x0; +static u8 high_output = 0x0; +static u8 high_direction = 0x0; + +#if BUILD_FT2232_FTD2XX == 1 +static FT_HANDLE ftdih = NULL; +#elif BUILD_FT2232_LIBFTDI == 1 +static struct ftdi_context ftdic; +#endif + +static u8 *ft2232_buffer = NULL; +static int ft2232_buffer_size = 0; +static int ft2232_read_pointer = 0; +static int ft2232_expect_read = 0; +#define FT2232_BUFFER_SIZE 131072 +#define BUFFER_ADD ft2232_buffer[ft2232_buffer_size++] +#define BUFFER_READ ft2232_buffer[ft2232_read_pointer++] + +jtag_interface_t ft2232_interface = +{ + + .name = "ft2232", + + .execute_queue = ft2232_execute_queue, + + .speed = ft2232_speed, + .register_commands = ft2232_register_commands, + .init = ft2232_init, + .quit = ft2232_quit, +}; + +int ft2232_write(u8 *buf, int size, u32* bytes_written) +{ +#if BUILD_FT2232_FTD2XX == 1 + FT_STATUS status; + DWORD dw_bytes_written; + if ((status = FT_Write(ftdih, buf, size, &dw_bytes_written)) != FT_OK) + { + *bytes_written = dw_bytes_written; + ERROR("FT_Write returned: %lu", status); + return ERROR_JTAG_DEVICE_ERROR; + } + else + { + *bytes_written = dw_bytes_written; + return ERROR_OK; + } +#elif BUILD_FT2232_LIBFTDI == 1 + int retval; + if ((retval = ftdi_write_data(&ftdic, buf, size)) < 0) + { + *bytes_written = 0; + ERROR("ftdi_write_data: %s", ftdi_get_error_string(&ftdic)); + return ERROR_JTAG_DEVICE_ERROR; + } + else + { + *bytes_written = retval; + return ERROR_OK; + } +#endif +} + +int ft2232_read(u8* buf, int size, u32* bytes_read) +{ +#if BUILD_FT2232_FTD2XX == 1 + DWORD dw_bytes_read; + FT_STATUS status; + int timeout = 5; + *bytes_read = 0; + + while ((*bytes_read < size) && timeout--) + { + if ((status = FT_Read(ftdih, buf + *bytes_read, size - + *bytes_read, &dw_bytes_read)) != FT_OK) + { + *bytes_read = 0; + ERROR("FT_Read returned: %lu", status); + return ERROR_JTAG_DEVICE_ERROR; + } + *bytes_read += dw_bytes_read; + } +#elif BUILD_FT2232_LIBFTDI == 1 + int retval; + int timeout = 100; + *bytes_read = 0; + + while ((*bytes_read < size) && timeout--) + { + if ((retval = ftdi_read_data(&ftdic, buf + *bytes_read, size - *bytes_read)) < 0) + { + *bytes_read = 0; + ERROR("ftdi_read_data: %s", ftdi_get_error_string(&ftdic)); + return ERROR_JTAG_DEVICE_ERROR; + } + *bytes_read += retval; + } +#endif + + if (*bytes_read < size) + { + ERROR("couldn't read the requested number of bytes from FT2232 device (%i < %i)", *bytes_read, size); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +int ft2232_speed(int speed) +{ + u8 buf[3]; + int retval; + u32 bytes_written; + + buf[0] = 0x86; /* command "set divisor" */ + buf[1] = speed & 0xff; /* valueL (0=6MHz, 1=3MHz, 2=2.0MHz, ...*/ + buf[2] = (speed >> 8) & 0xff; /* valueH */ + + DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + if (((retval = ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + ERROR("couldn't set FT2232 TCK speed"); + return retval; + } + + jtag_speed = speed; + + return ERROR_OK; +} + +int ft2232_register_commands(struct command_context_s *cmd_ctx) +{ + register_command(cmd_ctx, NULL, "ft2232_device_desc", ft2232_handle_device_desc_command, + COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "ft2232_serial", ft2232_handle_serial_command, + COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "ft2232_layout", ft2232_handle_layout_command, + COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "ft2232_vid_pid", ft2232_handle_vid_pid_command, + COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "ft2232_latency", ft2232_handle_latency_command, + COMMAND_CONFIG, NULL); + return ERROR_OK; +} + +void ft2232_end_state(enum tap_state state) +{ + if (tap_move_map[state] != -1) + end_state = state; + else + { + ERROR("BUG: %i is not a valid end state", state); + exit(-1); + } +} + +void ft2232_read_scan(enum scan_type type, u8* buffer, int scan_size) +{ + int num_bytes = ((scan_size + 7) / 8); + int bits_left = scan_size; + int cur_byte = 0; + + while(num_bytes-- > 1) + { + buffer[cur_byte] = BUFFER_READ; + cur_byte++; + bits_left -= 8; + } + + buffer[cur_byte] = 0x0; + + if (bits_left > 1) + { + buffer[cur_byte] = BUFFER_READ >> 1; + } + + buffer[cur_byte] = (buffer[cur_byte] | ((BUFFER_READ & 0x02) << 6)) >> (8 - bits_left); + +} + +void ft2232_debug_dump_buffer(void) +{ + int i; + char line[256]; + char *line_p = line; + + for (i = 0; i < ft2232_buffer_size; i++) + { + line_p += snprintf(line_p, 256 - (line_p - line), "%2.2x ", ft2232_buffer[i]); + if (i % 16 == 15) + { + DEBUG("%s", line); + line_p = line; + } + } + + if (line_p != line) + DEBUG("%s", line); +} + +int ft2232_send_and_recv(jtag_command_t *first, jtag_command_t *last) +{ + jtag_command_t *cmd; + u8 *buffer; + int scan_size; + enum scan_type type; + int retval; + u32 bytes_written; + u32 bytes_read; + +#ifdef _DEBUG_USB_IO_ + struct timeval start, inter, inter2, end; + struct timeval d_inter, d_inter2, d_end; +#endif + +#ifdef _DEBUG_USB_COMMS_ + DEBUG("write buffer (size %i):", ft2232_buffer_size); + ft2232_debug_dump_buffer(); +#endif + +#ifdef _DEBUG_USB_IO_ + gettimeofday(&start, NULL); +#endif + + if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK) + { + ERROR("couldn't write MPSSE commands to FT2232"); + exit(-1); + } + +#ifdef _DEBUG_USB_IO_ + gettimeofday(&inter, NULL); +#endif + + if (ft2232_expect_read) + { + int timeout = 100; + ft2232_buffer_size = 0; + +#ifdef _DEBUG_USB_IO_ + gettimeofday(&inter2, NULL); +#endif + + if ((retval = ft2232_read(ft2232_buffer, ft2232_expect_read, &bytes_read)) != ERROR_OK) + { + ERROR("couldn't read from FT2232"); + exit(-1); + } + +#ifdef _DEBUG_USB_IO_ + gettimeofday(&end, NULL); + + timeval_subtract(&d_inter, &inter, &start); + timeval_subtract(&d_inter2, &inter2, &start); + timeval_subtract(&d_end, &end, &start); + + INFO("inter: %i.%i, inter2: %i.%i end: %i.%i", d_inter.tv_sec, d_inter.tv_usec, d_inter2.tv_sec, d_inter2.tv_usec, d_end.tv_sec, d_end.tv_usec); +#endif + + + ft2232_buffer_size = bytes_read; + + if (ft2232_expect_read != ft2232_buffer_size) + { + ERROR("ft2232_expect_read (%i) != ft2232_buffer_size (%i) (%i retries)", ft2232_expect_read, ft2232_buffer_size, 100 - timeout); + ft2232_debug_dump_buffer(); + + exit(-1); + } + +#ifdef _DEBUG_USB_COMMS_ + DEBUG("read buffer (%i retries): %i bytes", 100 - timeout, ft2232_buffer_size); + ft2232_debug_dump_buffer(); +#endif + } + + ft2232_expect_read = 0; + ft2232_read_pointer = 0; + + /* return ERROR_OK, unless a jtag_read_buffer returns a failed check + * that wasn't handled by a caller-provided error handler + */ + retval = ERROR_OK; + + cmd = first; + while (cmd != last) + { + switch (cmd->type) + { + case JTAG_SCAN: + type = jtag_scan_type(cmd->cmd.scan); + if (type != SCAN_OUT) + { + scan_size = jtag_scan_size(cmd->cmd.scan); + buffer = calloc(CEIL(scan_size, 8), 1); + ft2232_read_scan(type, buffer, scan_size); + if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + free(buffer); + } + break; + default: + break; + } + cmd = cmd->next; + } + + ft2232_buffer_size = 0; + + return retval; +} + +void ft2232_add_pathmove(pathmove_command_t *cmd) +{ + int num_states = cmd->num_states; + u8 tms_byte; + int state_count; + + state_count = 0; + while (num_states) + { + tms_byte = 0x0; + int bit_count = 0; + + /* command "Clock Data to TMS/CS Pin (no Read)" */ + BUFFER_ADD = 0x4b; + /* number of states remaining */ + BUFFER_ADD = (num_states % 7) - 1; + + while (num_states % 7) + { + if (tap_transitions[cur_state].low == cmd->path[state_count]) + buf_set_u32(&tms_byte, bit_count++, 1, 0x0); + else if (tap_transitions[cur_state].high == cmd->path[state_count]) + buf_set_u32(&tms_byte, bit_count++, 1, 0x1); + else + { + ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_strings[cur_state], tap_state_strings[cmd->path[state_count]]); + exit(-1); + } + + cur_state = cmd->path[state_count]; + state_count++; + num_states--; + } + + BUFFER_ADD = tms_byte; + } + + end_state = cur_state; +} + +void ft2232_add_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size) +{ + int num_bytes = (scan_size + 7) / 8; + int bits_left = scan_size; + int cur_byte = 0; + int last_bit; + + if (!((!ir_scan && (cur_state == TAP_SD)) || (ir_scan && (cur_state == TAP_SI)))) + { + /* command "Clock Data to TMS/CS Pin (no Read)" */ + BUFFER_ADD = 0x4b; + /* scan 7 bit */ + BUFFER_ADD = 0x6; + /* TMS data bits */ + if (ir_scan) + { + BUFFER_ADD = TAP_MOVE(cur_state, TAP_SI); + cur_state = TAP_SI; + } + else + { + BUFFER_ADD = TAP_MOVE(cur_state, TAP_SD); + cur_state = TAP_SD; + } + //DEBUG("added TMS scan (no read)"); + } + + /* add command for complete bytes */ + while (num_bytes > 1) + { + int thisrun_bytes; + if (type == SCAN_IO) + { + /* Clock Data Bytes In and Out LSB First */ + BUFFER_ADD = 0x39; + //DEBUG("added TDI bytes (io %i)", num_bytes); + } + else if (type == SCAN_OUT) + { + /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */ + BUFFER_ADD = 0x19; + //DEBUG("added TDI bytes (o)"); + } + else if (type == SCAN_IN) + { + /* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */ + BUFFER_ADD = 0x28; + //DEBUG("added TDI bytes (i %i)", num_bytes); + } + thisrun_bytes = (num_bytes > 65537) ? 65536 : (num_bytes - 1); + num_bytes -= thisrun_bytes; + BUFFER_ADD = (thisrun_bytes - 1) & 0xff; + BUFFER_ADD = ((thisrun_bytes - 1) >> 8) & 0xff; + if (type != SCAN_IN) + { + /* add complete bytes */ + while(thisrun_bytes-- > 0) + { + BUFFER_ADD = buffer[cur_byte]; + cur_byte++; + bits_left -= 8; + } + } + else /* (type == SCAN_IN) */ + { + bits_left -= 8 * (thisrun_bytes); + } + } + + /* the most signifcant bit is scanned during TAP movement */ + if (type != SCAN_IN) + last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1; + else + last_bit = 0; + + /* process remaining bits but the last one */ + if (bits_left > 1) + { + if (type == SCAN_IO) + { + /* Clock Data Bits In and Out LSB First */ + BUFFER_ADD = 0x3b; + //DEBUG("added TDI bits (io) %i", bits_left - 1); + } + else if (type == SCAN_OUT) + { + /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ + BUFFER_ADD = 0x1b; + //DEBUG("added TDI bits (o)"); + } + else if (type == SCAN_IN) + { + /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ + BUFFER_ADD = 0x2a; + //DEBUG("added TDI bits (i %i)", bits_left - 1); + } + BUFFER_ADD = bits_left - 2; + if (type != SCAN_IN) + BUFFER_ADD = buffer[cur_byte]; + } + + if ((ir_scan && (end_state == TAP_SI)) || + (!ir_scan && (end_state == TAP_SD))) + { + if (type == SCAN_IO) + { + /* Clock Data Bits In and Out LSB First */ + BUFFER_ADD = 0x3b; + //DEBUG("added TDI bits (io) %i", bits_left - 1); + } + else if (type == SCAN_OUT) + { + /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ + BUFFER_ADD = 0x1b; + //DEBUG("added TDI bits (o)"); + } + else if (type == SCAN_IN) + { + /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ + BUFFER_ADD = 0x2a; + //DEBUG("added TDI bits (i %i)", bits_left - 1); + } + BUFFER_ADD = 0x0; + BUFFER_ADD = last_bit; + } + else + { + /* move from Shift-IR/DR to end state */ + if (type != SCAN_OUT) + { + /* Clock Data to TMS/CS Pin with Read */ + BUFFER_ADD = 0x6b; + //DEBUG("added TMS scan (read)"); + } + else + { + /* Clock Data to TMS/CS Pin (no Read) */ + BUFFER_ADD = 0x4b; + //DEBUG("added TMS scan (no read)"); + } + BUFFER_ADD = 0x6; + BUFFER_ADD = TAP_MOVE(cur_state, end_state) | (last_bit << 7); + cur_state = end_state; + } +} + +int ft2232_large_scan(scan_command_t *cmd, enum scan_type type, u8 *buffer, int scan_size) +{ + int num_bytes = (scan_size + 7) / 8; + int bits_left = scan_size; + int cur_byte = 0; + int last_bit; + u8 *receive_buffer = malloc(CEIL(scan_size, 8)); + u8 *receive_pointer = receive_buffer; + u32 bytes_written; + u32 bytes_read; + int retval; + int thisrun_read = 0; + + if (cmd->ir_scan) + { + ERROR("BUG: large IR scans are not supported"); + exit(-1); + } + + if (cur_state != TAP_SD) + { + /* command "Clock Data to TMS/CS Pin (no Read)" */ + BUFFER_ADD = 0x4b; + /* scan 7 bit */ + BUFFER_ADD = 0x6; + /* TMS data bits */ + BUFFER_ADD = TAP_MOVE(cur_state, TAP_SD); + cur_state = TAP_SD; + } + + if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK) + { + ERROR("couldn't write MPSSE commands to FT2232"); + exit(-1); + } + DEBUG("ft2232_buffer_size: %i, bytes_written: %i", ft2232_buffer_size, bytes_written); + ft2232_buffer_size = 0; + + /* add command for complete bytes */ + while (num_bytes > 1) + { + int thisrun_bytes; + + if (type == SCAN_IO) + { + /* Clock Data Bytes In and Out LSB First */ + BUFFER_ADD = 0x39; + //DEBUG("added TDI bytes (io %i)", num_bytes); + } + else if (type == SCAN_OUT) + { + /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */ + BUFFER_ADD = 0x19; + //DEBUG("added TDI bytes (o)"); + } + else if (type == SCAN_IN) + { + /* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */ + BUFFER_ADD = 0x28; + //DEBUG("added TDI bytes (i %i)", num_bytes); + } + thisrun_bytes = (num_bytes > 65537) ? 65536 : (num_bytes - 1); + thisrun_read = thisrun_bytes; + num_bytes -= thisrun_bytes; + BUFFER_ADD = (thisrun_bytes - 1) & 0xff; + BUFFER_ADD = ((thisrun_bytes - 1) >> 8) & 0xff; + if (type != SCAN_IN) + { + /* add complete bytes */ + while(thisrun_bytes-- > 0) + { + BUFFER_ADD = buffer[cur_byte]; + cur_byte++; + bits_left -= 8; + } + } + else /* (type == SCAN_IN) */ + { + bits_left -= 8 * (thisrun_bytes); + } + + if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK) + { + ERROR("couldn't write MPSSE commands to FT2232"); + exit(-1); + } + DEBUG("ft2232_buffer_size: %i, bytes_written: %i", ft2232_buffer_size, bytes_written); + ft2232_buffer_size = 0; + + if (type != SCAN_OUT) + { + if ((retval = ft2232_read(receive_pointer, thisrun_read, &bytes_read)) != ERROR_OK) + { + ERROR("couldn't read from FT2232"); + exit(-1); + } + DEBUG("thisrun_read: %i, bytes_read: %i", thisrun_read, bytes_read); + receive_pointer += bytes_read; + } + } + + thisrun_read = 0; + + /* the most signifcant bit is scanned during TAP movement */ + if (type != SCAN_IN) + last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1; + else + last_bit = 0; + + /* process remaining bits but the last one */ + if (bits_left > 1) + { + if (type == SCAN_IO) + { + /* Clock Data Bits In and Out LSB First */ + BUFFER_ADD = 0x3b; + //DEBUG("added TDI bits (io) %i", bits_left - 1); + } + else if (type == SCAN_OUT) + { + /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ + BUFFER_ADD = 0x1b; + //DEBUG("added TDI bits (o)"); + } + else if (type == SCAN_IN) + { + /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ + BUFFER_ADD = 0x2a; + //DEBUG("added TDI bits (i %i)", bits_left - 1); + } + BUFFER_ADD = bits_left - 2; + if (type != SCAN_IN) + BUFFER_ADD = buffer[cur_byte]; + + if (type != SCAN_OUT) + thisrun_read += 2; + } + + if (end_state == TAP_SD) + { + if (type == SCAN_IO) + { + /* Clock Data Bits In and Out LSB First */ + BUFFER_ADD = 0x3b; + //DEBUG("added TDI bits (io) %i", bits_left - 1); + } + else if (type == SCAN_OUT) + { + /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ + BUFFER_ADD = 0x1b; + //DEBUG("added TDI bits (o)"); + } + else if (type == SCAN_IN) + { + /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ + BUFFER_ADD = 0x2a; + //DEBUG("added TDI bits (i %i)", bits_left - 1); + } + BUFFER_ADD = 0x0; + BUFFER_ADD = last_bit; + } + else + { + /* move from Shift-IR/DR to end state */ + if (type != SCAN_OUT) + { + /* Clock Data to TMS/CS Pin with Read */ + BUFFER_ADD = 0x6b; + //DEBUG("added TMS scan (read)"); + } + else + { + /* Clock Data to TMS/CS Pin (no Read) */ + BUFFER_ADD = 0x4b; + //DEBUG("added TMS scan (no read)"); + } + BUFFER_ADD = 0x6; + BUFFER_ADD = TAP_MOVE(cur_state, end_state) | (last_bit << 7); + cur_state = end_state; + } + + if (type != SCAN_OUT) + thisrun_read += 1; + + if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK) + { + ERROR("couldn't write MPSSE commands to FT2232"); + exit(-1); + } + DEBUG("ft2232_buffer_size: %i, bytes_written: %i", ft2232_buffer_size, bytes_written); + ft2232_buffer_size = 0; + + if (type != SCAN_OUT) + { + if ((retval = ft2232_read(receive_pointer, thisrun_read, &bytes_read)) != ERROR_OK) + { + ERROR("couldn't read from FT2232"); + exit(-1); + } + DEBUG("thisrun_read: %i, bytes_read: %i", thisrun_read, bytes_read); + receive_pointer += bytes_read; + } + + return ERROR_OK; +} + +int ft2232_predict_scan_out(int scan_size, enum scan_type type) +{ + int predicted_size = 3; + int num_bytes = (scan_size - 1) / 8; + + if (cur_state != TAP_SD) + predicted_size += 3; + + if (type == SCAN_IN) /* only from device to host */ + { + /* complete bytes */ + predicted_size += (CEIL(num_bytes, 65536)) * 3; + /* remaining bits - 1 (up to 7) */ + predicted_size += ((scan_size - 1) % 8) ? 2 : 0; + } + else /* host to device, or bidirectional */ + { + /* complete bytes */ + predicted_size += num_bytes + (CEIL(num_bytes, 65536)) * 3; + /* remaining bits -1 (up to 7) */ + predicted_size += ((scan_size - 1) % 8) ? 3 : 0; + } + + return predicted_size; +} + +int ft2232_predict_scan_in(int scan_size, enum scan_type type) +{ + int predicted_size = 0; + + if (type != SCAN_OUT) + { + /* complete bytes */ + predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) - 1) : 0; + /* remaining bits - 1 */ + predicted_size += ((scan_size - 1) % 8) ? 1 : 0; + /* last bit (from TMS scan) */ + predicted_size += 1; + } + + //DEBUG("scan_size: %i, predicted_size: %i", scan_size, predicted_size); + + return predicted_size; +} + +void usbjtag_reset(int trst, int srst) +{ + if (trst == 1) + { + cur_state = TAP_TLR; + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + low_direction |= nTRSTnOE; /* switch to output pin (output is low) */ + else + low_output &= ~nTRST; /* switch output low */ + } + else if (trst == 0) + { + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + low_direction &= ~nTRSTnOE; /* switch to input pin (high-Z + internal and external pullup) */ + else + low_output |= nTRST; /* switch output high */ + } + + if (srst == 1) + { + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + low_output &= ~nSRST; /* switch output low */ + else + low_direction |= nSRSTnOE; /* switch to output pin (output is low) */ + } + else if (srst == 0) + { + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + low_output |= nSRST; /* switch output high */ + else + low_direction &= ~nSRSTnOE; /* switch to input pin (high-Z) */ + } + + /* command "set data bits low byte" */ + BUFFER_ADD = 0x80; + BUFFER_ADD = low_output; + BUFFER_ADD = low_direction; + +} + +void jtagkey_reset(int trst, int srst) +{ + if (trst == 1) + { + cur_state = TAP_TLR; + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + high_output &= ~nTRSTnOE; + else + high_output &= ~nTRST; + } + else if (trst == 0) + { + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + high_output |= nTRSTnOE; + else + high_output |= nTRST; + } + + if (srst == 1) + { + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + high_output &= ~nSRST; + else + high_output &= ~nSRSTnOE; + } + else if (srst == 0) + { + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + high_output |= nSRST; + else + high_output |= nSRSTnOE; + } + + /* command "set data bits high byte" */ + BUFFER_ADD = 0x82; + BUFFER_ADD = high_output; + BUFFER_ADD = high_direction; + DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction); +} + +void olimex_jtag_reset(int trst, int srst) +{ + if (trst == 1) + { + cur_state = TAP_TLR; + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + high_output &= ~nTRSTnOE; + else + high_output &= ~nTRST; + } + else if (trst == 0) + { + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + high_output |= nTRSTnOE; + else + high_output |= nTRST; + } + + if (srst == 1) + { + high_output |= nSRST; + } + else if (srst == 0) + { + high_output &= ~nSRST; + } + + /* command "set data bits high byte" */ + BUFFER_ADD = 0x82; + BUFFER_ADD = high_output; + BUFFER_ADD = high_direction; + DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction); +} + +void flyswatter_reset(int trst, int srst) +{ + if (trst == 1) + { + cur_state = TAP_TLR; + low_output &= ~nTRST; + } + else if (trst == 0) + { + low_output |= nTRST; + } + + if (srst == 1) + { + low_output |= nSRST; + } + else if (srst == 0) + { + low_output &= ~nSRST; + } + + /* command "set data bits low byte" */ + BUFFER_ADD = 0x80; + BUFFER_ADD = low_output; + BUFFER_ADD = low_direction; + DEBUG("trst: %i, srst: %i, low_output: 0x%2.2x, low_direction: 0x%2.2x", trst, srst, low_output, low_direction); +} + +void turtle_reset(int trst, int srst) +{ + trst = trst; + + if (srst == 1) + { + low_output |= nSRST; + } + else if (srst == 0) + { + low_output &= ~nSRST; + } + + /* command "set data bits low byte" */ + BUFFER_ADD = 0x80; + BUFFER_ADD = low_output; + BUFFER_ADD = low_direction; + DEBUG("srst: %i, low_output: 0x%2.2x, low_direction: 0x%2.2x", srst, low_output, low_direction); +} + +void comstick_reset(int trst, int srst) +{ + if (trst == 1) + { + cur_state = TAP_TLR; + high_output &= ~nTRST; + } + else if (trst == 0) + { + high_output |= nTRST; + } + + if (srst == 1) + { + high_output &= ~nSRST; + } + else if (srst == 0) + { + high_output |= nSRST; + } + + /* command "set data bits high byte" */ + BUFFER_ADD = 0x82; + BUFFER_ADD = high_output; + BUFFER_ADD = high_direction; + DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction); +} + +void stm32stick_reset(int trst, int srst) +{ + if (trst == 1) + { + cur_state = TAP_TLR; + high_output &= ~nTRST; + } + else if (trst == 0) + { + high_output |= nTRST; + } + + if (srst == 1) + { + low_output &= ~nSRST; + } + else if (srst == 0) + { + low_output |= nSRST; + } + + /* command "set data bits low byte" */ + BUFFER_ADD = 0x80; + BUFFER_ADD = low_output; + BUFFER_ADD = low_direction; + + /* command "set data bits high byte" */ + BUFFER_ADD = 0x82; + BUFFER_ADD = high_output; + BUFFER_ADD = high_direction; + DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction); +} + +int ft2232_execute_queue() +{ + jtag_command_t *cmd = jtag_command_queue; /* currently processed command */ + jtag_command_t *first_unsent = cmd; /* next command that has to be sent */ + u8 *buffer; + int scan_size; /* size of IR or DR scan */ + enum scan_type type; + int i; + int predicted_size = 0; + int require_send = 0; + int retval; + + /* return ERROR_OK, unless ft2232_send_and_recv reports a failed check + * that wasn't handled by a caller-provided error handler + */ + retval = ERROR_OK; + + ft2232_buffer_size = 0; + ft2232_expect_read = 0; + + /* blink, if the current layout has that feature */ + if (layout->blink) + layout->blink(); + + while (cmd) + { + switch(cmd->type) + { + case JTAG_END_STATE: + if (cmd->cmd.end_state->end_state != -1) + ft2232_end_state(cmd->cmd.end_state->end_state); + break; + case JTAG_RESET: + /* only send the maximum buffer size that FT2232C can handle */ + predicted_size = 3; + if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) + { + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + require_send = 0; + first_unsent = cmd; + } + + layout->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + require_send = 1; + +#ifdef _DEBUG_JTAG_IO_ + DEBUG("trst: %i, srst: %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); +#endif + break; + case JTAG_RUNTEST: + /* only send the maximum buffer size that FT2232C can handle */ + predicted_size = 0; + if (cur_state != TAP_RTI) + predicted_size += 3; + predicted_size += 3 * CEIL(cmd->cmd.runtest->num_cycles, 7); + if ((cmd->cmd.runtest->end_state != -1) && (cmd->cmd.runtest->end_state != TAP_RTI)) + predicted_size += 3; + if ((cmd->cmd.runtest->end_state == -1) && (end_state != TAP_RTI)) + predicted_size += 3; + if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) + { + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + require_send = 0; + first_unsent = cmd; + } + if (cur_state != TAP_RTI) + { + /* command "Clock Data to TMS/CS Pin (no Read)" */ + BUFFER_ADD = 0x4b; + /* scan 7 bit */ + BUFFER_ADD = 0x6; + /* TMS data bits */ + BUFFER_ADD = TAP_MOVE(cur_state, TAP_RTI); + cur_state = TAP_RTI; + require_send = 1; + } + i = cmd->cmd.runtest->num_cycles; + while (i > 0) + { + /* command "Clock Data to TMS/CS Pin (no Read)" */ + BUFFER_ADD = 0x4b; + /* scan 7 bit */ + BUFFER_ADD = (i > 7) ? 6 : (i - 1); + /* TMS data bits */ + BUFFER_ADD = 0x0; + cur_state = TAP_RTI; + i -= (i > 7) ? 7 : i; + //DEBUG("added TMS scan (no read)"); + } + if (cmd->cmd.runtest->end_state != -1) + ft2232_end_state(cmd->cmd.runtest->end_state); + if (cur_state != end_state) + { + /* command "Clock Data to TMS/CS Pin (no Read)" */ + BUFFER_ADD = 0x4b; + /* scan 7 bit */ + BUFFER_ADD = 0x6; + /* TMS data bits */ + BUFFER_ADD = TAP_MOVE(cur_state, end_state); + cur_state = end_state; + //DEBUG("added TMS scan (no read)"); + } + require_send = 1; +#ifdef _DEBUG_JTAG_IO_ + DEBUG("runtest: %i, end in %i", cmd->cmd.runtest->num_cycles, end_state); +#endif + break; + case JTAG_STATEMOVE: + /* only send the maximum buffer size that FT2232C can handle */ + predicted_size = 3; + if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) + { + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + require_send = 0; + first_unsent = cmd; + } + if (cmd->cmd.statemove->end_state != -1) + ft2232_end_state(cmd->cmd.statemove->end_state); + /* command "Clock Data to TMS/CS Pin (no Read)" */ + BUFFER_ADD = 0x4b; + /* scan 7 bit */ + BUFFER_ADD = 0x6; + /* TMS data bits */ + BUFFER_ADD = TAP_MOVE(cur_state, end_state); + //DEBUG("added TMS scan (no read)"); + cur_state = end_state; + require_send = 1; +#ifdef _DEBUG_JTAG_IO_ + DEBUG("statemove: %i", end_state); +#endif + break; + case JTAG_PATHMOVE: + /* only send the maximum buffer size that FT2232C can handle */ + predicted_size = 3 * CEIL(cmd->cmd.pathmove->num_states, 7); + if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) + { + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + require_send = 0; + first_unsent = cmd; + } + ft2232_add_pathmove(cmd->cmd.pathmove); + require_send = 1; +#ifdef _DEBUG_JTAG_IO_ + DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); +#endif + break; + case JTAG_SCAN: + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + type = jtag_scan_type(cmd->cmd.scan); + predicted_size = ft2232_predict_scan_out(scan_size, type); + if ((predicted_size + 1) > FT2232_BUFFER_SIZE) + { + DEBUG("oversized ft2232 scan (predicted_size > FT2232_BUFFER_SIZE)"); + /* unsent commands before this */ + if (first_unsent != cmd) + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + + /* current command */ + if (cmd->cmd.scan->end_state != -1) + ft2232_end_state(cmd->cmd.scan->end_state); + ft2232_large_scan(cmd->cmd.scan, type, buffer, scan_size); + require_send = 0; + first_unsent = cmd->next; + if (buffer) + free(buffer); + break; + } + else if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) + { + DEBUG("ft2232 buffer size reached, sending queued commands (first_unsent: %p, cmd: %p)", first_unsent, cmd); + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + require_send = 0; + first_unsent = cmd; + } + ft2232_expect_read += ft2232_predict_scan_in(scan_size, type); + //DEBUG("new read size: %i", ft2232_expect_read); + if (cmd->cmd.scan->end_state != -1) + ft2232_end_state(cmd->cmd.scan->end_state); + ft2232_add_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); + require_send = 1; + if (buffer) + free(buffer); +#ifdef _DEBUG_JTAG_IO_ + DEBUG("%s scan, %i bit, end in %i", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size, end_state); +#endif + break; + case JTAG_SLEEP: + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + first_unsent = cmd->next; + jtag_sleep(cmd->cmd.sleep->us); +#ifdef _DEBUG_JTAG_IO_ + DEBUG("sleep %i usec", cmd->cmd.sleep->us); +#endif + break; + default: + ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); + } + cmd = cmd->next; + } + + if (require_send > 0) + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + + return retval; +} + +#if BUILD_FT2232_FTD2XX == 1 +static int ft2232_init_ftd2xx(u16 vid, u16 pid, int more, int *try_more) +{ + FT_STATUS status; + DWORD openex_flags = 0; + char *openex_string = NULL; + u8 latency_timer; + + DEBUG("'ft2232' interface using FTD2XX with '%s' layout (%4.4x:%4.4x)", + ft2232_layout, vid, pid); + +#if IS_WIN32 == 0 + /* Add non-standard Vid/Pid to the linux driver */ + if ((status = FT_SetVIDPID(vid, pid)) != FT_OK) + { + WARNING("couldn't add %4.4x:%4.4x", + vid, pid); + } +#endif + + if (ft2232_device_desc && ft2232_serial) + { + WARNING("can't open by device description and serial number, giving precedence to serial"); + ft2232_device_desc = NULL; + } + + if (ft2232_device_desc) + { + openex_string = ft2232_device_desc; + openex_flags = FT_OPEN_BY_DESCRIPTION; + } + else if (ft2232_serial) + { + openex_string = ft2232_serial; + openex_flags = FT_OPEN_BY_SERIAL_NUMBER; + } + else + { + ERROR("neither device description nor serial number specified"); + ERROR("please add \"ft2232_device_desc <string>\" or \"ft2232_serial <string>\" to your .cfg file"); + + return ERROR_JTAG_INIT_FAILED; + } + + if ((status = FT_OpenEx(openex_string, openex_flags, &ftdih)) != FT_OK) + { + DWORD num_devices; + + if (more) { + WARNING("unable to open ftdi device (trying more): %lu", + status); + *try_more = 1; + return ERROR_JTAG_INIT_FAILED; + } + ERROR("unable to open ftdi device: %lu", status); + status = FT_ListDevices(&num_devices, NULL, FT_LIST_NUMBER_ONLY); + if (status == FT_OK) + { + char **desc_array = malloc(sizeof(char*) * (num_devices + 1)); + int i; + + for (i = 0; i < num_devices; i++) + desc_array[i] = malloc(64); + desc_array[num_devices] = NULL; + + status = FT_ListDevices(desc_array, &num_devices, FT_LIST_ALL | openex_flags); + + if (status == FT_OK) + { + ERROR("ListDevices: %lu\n", num_devices); + for (i = 0; i < num_devices; i++) + ERROR("%i: %s", i, desc_array[i]); + } + + for (i = 0; i < num_devices; i++) + free(desc_array[i]); + free(desc_array); + } + else + { + ERROR("ListDevices: NONE\n"); + } + return ERROR_JTAG_INIT_FAILED; + } + + if ((status = FT_SetLatencyTimer(ftdih, ft2232_latency)) != FT_OK) + { + ERROR("unable to set latency timer: %lu", status); + return ERROR_JTAG_INIT_FAILED; + } + + if ((status = FT_GetLatencyTimer(ftdih, &latency_timer)) != FT_OK) + { + ERROR("unable to get latency timer: %lu", status); + return ERROR_JTAG_INIT_FAILED; + } + else + { + DEBUG("current latency timer: %i", latency_timer); + } + + if ((status = FT_SetTimeouts(ftdih, 5000, 5000)) != FT_OK) + { + ERROR("unable to set timeouts: %lu", status); + return ERROR_JTAG_INIT_FAILED; + } + + if ((status = FT_SetBitMode(ftdih, 0x0b, 2)) != FT_OK) + { + ERROR("unable to enable bit i/o mode: %lu", status); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +static int ft2232_purge_ftd2xx(void) +{ + FT_STATUS status; + + if ((status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX)) != FT_OK) + { + ERROR("error purging ftd2xx device: %lu", status); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} +#endif /* BUILD_FT2232_FTD2XX == 1 */ + +#if BUILD_FT2232_LIBFTDI == 1 +static int ft2232_init_libftdi(u16 vid, u16 pid, int more, int *try_more) +{ + u8 latency_timer; + + DEBUG("'ft2232' interface using libftdi with '%s' layout (%4.4x:%4.4x)", + ft2232_layout, vid, pid); + + if (ftdi_init(&ftdic) < 0) + return ERROR_JTAG_INIT_FAILED; + + /* context, vendor id, product id */ + if (ftdi_usb_open_desc(&ftdic, vid, pid, ft2232_device_desc, + ft2232_serial) < 0) { + if (more) + WARNING("unable to open ftdi device (trying more): %s", + ftdic.error_str); + else + ERROR("unable to open ftdi device: %s", ftdic.error_str); + *try_more = 1; + return ERROR_JTAG_INIT_FAILED; + } + + if (ftdi_set_interface(&ftdic, INTERFACE_A) < 0) + { + ERROR("unable to select FT2232 channel A: %s", ftdic.error_str); + return ERROR_JTAG_INIT_FAILED; + } + + if (ftdi_usb_reset(&ftdic) < 0) + { + ERROR("unable to reset ftdi device"); + return ERROR_JTAG_INIT_FAILED; + } + + if (ftdi_set_latency_timer(&ftdic, ft2232_latency) < 0) + { + ERROR("unable to set latency timer"); + return ERROR_JTAG_INIT_FAILED; + } + + if (ftdi_get_latency_timer(&ftdic, &latency_timer) < 0) + { + ERROR("unable to get latency timer"); + return ERROR_JTAG_INIT_FAILED; + } + else + { + DEBUG("current latency timer: %i", latency_timer); + } + + ftdi_set_bitmode(&ftdic, 0x0b, 2); /* ctx, JTAG I/O mask */ + + return ERROR_OK; +} + +static int ft2232_purge_libftdi(void) +{ + if (ftdi_usb_purge_buffers(&ftdic) < 0) + { + ERROR("ftdi_purge_buffers: %s", ftdic.error_str); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} +#endif /* BUILD_FT2232_LIBFTDI == 1 */ + +int ft2232_init(void) +{ + u8 buf[1]; + int retval; + u32 bytes_written; + ft2232_layout_t *cur_layout = ft2232_layouts; + int i; + + if ((ft2232_layout == NULL) || (ft2232_layout[0] == 0)) + { + ft2232_layout = "usbjtag"; + WARNING("No ft2232 layout specified, using default 'usbjtag'"); + } + + while (cur_layout->name) + { + if (strcmp(cur_layout->name, ft2232_layout) == 0) + { + layout = cur_layout; + break; + } + cur_layout++; + } + + if (!layout) + { + ERROR("No matching layout found for %s", ft2232_layout); + return ERROR_JTAG_INIT_FAILED; + } + + for (i = 0; 1; i++) { + /* + * "more indicates that there are more IDs to try, so we should + * not print an error for an ID mismatch (but for anything + * else, we should). + * + * try_more indicates that the error code returned indicates an + * ID mismatch (and nothing else) and that we should proceeed + * with the next ID pair. + */ + int more = ft2232_vid[i+1] || ft2232_pid[i+1]; + int try_more = 0; + +#if BUILD_FT2232_FTD2XX == 1 + retval = ft2232_init_ftd2xx(ft2232_vid[i], ft2232_pid[i], + more, &try_more); +#elif BUILD_FT2232_LIBFTDI == 1 + retval = ft2232_init_libftdi(ft2232_vid[i], ft2232_pid[i], + more, &try_more); +#endif + if (retval >= 0) + break; + if (!more || !try_more) + return retval; + } + + ft2232_buffer_size = 0; + ft2232_buffer = malloc(FT2232_BUFFER_SIZE); + + if (layout->init() != ERROR_OK) + return ERROR_JTAG_INIT_FAILED; + + ft2232_speed(jtag_speed); + + buf[0] = 0x85; /* Disconnect TDI/DO to TDO/DI for Loopback */ + if (((retval = ft2232_write(buf, 1, &bytes_written)) != ERROR_OK) || (bytes_written != 1)) + { + ERROR("couldn't write to FT2232 to disable loopback"); + return ERROR_JTAG_INIT_FAILED; + } + +#if BUILD_FT2232_FTD2XX == 1 + return ft2232_purge_ftd2xx(); +#elif BUILD_FT2232_LIBFTDI == 1 + return ft2232_purge_libftdi(); +#endif + + return ERROR_OK; +} + +int usbjtag_init(void) +{ + u8 buf[3]; + u32 bytes_written; + + low_output = 0x08; + low_direction = 0x0b; + + if (strcmp(ft2232_layout, "usbjtag") == 0) + { + nTRST = 0x10; + nTRSTnOE = 0x10; + nSRST = 0x40; + nSRSTnOE = 0x40; + } + else if (strcmp(ft2232_layout, "signalyzer") == 0) + { + nTRST = 0x10; + nTRSTnOE = 0x10; + nSRST = 0x20; + nSRSTnOE = 0x20; + } + else if (strcmp(ft2232_layout, "evb_lm3s811") == 0) + { + nTRST = 0x0; + nTRSTnOE = 0x00; + nSRST = 0x20; + nSRSTnOE = 0x20; + low_output = 0x88; + low_direction = 0x8b; + } + else + { + ERROR("BUG: usbjtag_init called for unknown layout '%s'", ft2232_layout); + return ERROR_JTAG_INIT_FAILED; + } + + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + { + low_direction &= ~nTRSTnOE; /* nTRST input */ + low_output &= ~nTRST; /* nTRST = 0 */ + } + else + { + low_direction |= nTRSTnOE; /* nTRST output */ + low_output |= nTRST; /* nTRST = 1 */ + } + + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + { + low_direction |= nSRSTnOE; /* nSRST output */ + low_output |= nSRST; /* nSRST = 1 */ + } + else + { + low_direction &= ~nSRSTnOE; /* nSRST input */ + low_output &= ~nSRST; /* nSRST = 0 */ + } + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, xRST high) */ + buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in */ + DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + ERROR("couldn't initialize FT2232 with 'USBJTAG' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +int jtagkey_init(void) +{ + u8 buf[3]; + u32 bytes_written; + + low_output = 0x08; + low_direction = 0x1b; + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */ + buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */ + DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + ERROR("couldn't initialize FT2232 with 'JTAGkey' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + if (strcmp(layout->name, "jtagkey") == 0) + { + nTRST = 0x01; + nTRSTnOE = 0x4; + nSRST = 0x02; + nSRSTnOE = 0x08; + } + else if ((strcmp(layout->name, "jtagkey_prototype_v1") == 0) || + (strcmp(layout->name, "oocdlink") == 0)) + { + nTRST = 0x02; + nTRSTnOE = 0x1; + nSRST = 0x08; + nSRSTnOE = 0x04; + } + else + { + ERROR("BUG: jtagkey_init called for non jtagkey layout"); + exit(-1); + } + + high_output = 0x0; + high_direction = 0x0f; + + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + { + high_output |= nTRSTnOE; + high_output &= ~nTRST; + } + else + { + high_output &= ~nTRSTnOE; + high_output |= nTRST; + } + + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + { + high_output &= ~nSRSTnOE; + high_output |= nSRST; + } + else + { + high_output |= nSRSTnOE; + high_output &= ~nSRST; + } + + /* initialize high port */ + buf[0] = 0x82; /* command "set data bits high byte" */ + buf[1] = high_output; /* value */ + buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */ + DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + ERROR("couldn't initialize FT2232 with 'JTAGkey' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +int olimex_jtag_init(void) +{ + u8 buf[3]; + u32 bytes_written; + + low_output = 0x08; + low_direction = 0x1b; + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */ + buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */ + DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + ERROR("couldn't initialize FT2232 with 'JTAGkey' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + nTRST = 0x01; + nTRSTnOE = 0x4; + nSRST = 0x02; + nSRSTnOE = 0x00; /* no output enable for nSRST */ + + high_output = 0x0; + high_direction = 0x0f; + + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + { + high_output |= nTRSTnOE; + high_output &= ~nTRST; + } + else + { + high_output &= ~nTRSTnOE; + high_output |= nTRST; + } + + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + { + ERROR("can't set nSRST to push-pull on the Olimex ARM-USB-OCD"); + } + else + { + high_output &= ~nSRST; + } + + /* turn red LED on */ + high_output |= 0x08; + + /* initialize high port */ + buf[0] = 0x82; /* command "set data bits high byte" */ + buf[1] = high_output; /* value */ + buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */ + DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + ERROR("couldn't initialize FT2232 with 'JTAGkey' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +int flyswatter_init(void) +{ + u8 buf[3]; + u32 bytes_written; + + low_output = 0x18; + low_direction = 0xfb; + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */ + buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE[12]=out, n[ST]srst=out */ + DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + ERROR("couldn't initialize FT2232 with 'flyswatter' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + nTRST = 0x10; + nTRSTnOE = 0x0; /* not output enable for nTRST */ + nSRST = 0x20; + nSRSTnOE = 0x00; /* no output enable for nSRST */ + + high_output = 0x00; + high_direction = 0x0c; + + /* turn red LED1 on, LED2 off */ + high_output |= 0x08; + + /* initialize high port */ + buf[0] = 0x82; /* command "set data bits high byte" */ + buf[1] = high_output; /* value */ + buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */ + DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + ERROR("couldn't initialize FT2232 with 'flyswatter' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +int turtle_init(void) +{ + u8 buf[3]; + u32 bytes_written; + + low_output = 0x08; + low_direction = 0x5b; + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */ + buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */ + DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + ERROR("couldn't initialize FT2232 with 'turtelizer2' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + nSRST = 0x40; + + high_output = 0x00; + high_direction = 0x0C; + + /* initialize high port */ + buf[0] = 0x82; /* command "set data bits high byte" */ + buf[1] = high_output; + buf[2] = high_direction; + DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + ERROR("couldn't initialize FT2232 with 'turtelizer2' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +int comstick_init(void) +{ + u8 buf[3]; + u32 bytes_written; + + low_output = 0x08; + low_direction = 0x0b; + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */ + buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */ + DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + ERROR("couldn't initialize FT2232 with 'comstick' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + nTRST = 0x01; + nTRSTnOE = 0x00; /* no output enable for nTRST */ + nSRST = 0x02; + nSRSTnOE = 0x00; /* no output enable for nSRST */ + + high_output = 0x03; + high_direction = 0x03; + + /* initialize high port */ + buf[0] = 0x82; /* command "set data bits high byte" */ + buf[1] = high_output; + buf[2] = high_direction; + DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + ERROR("couldn't initialize FT2232 with 'comstick' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +int stm32stick_init(void) +{ + u8 buf[3]; + u32 bytes_written; + + low_output = 0x88; + low_direction = 0x8b; + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; /* value (TMS=1,TCK=0, TDI=0, nOE=0) */ + buf[2] = low_direction; /* dir (output=1), TCK/TDI/TMS=out, TDO=in, nOE=out */ + DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + ERROR("couldn't initialize FT2232 with 'stm32stick' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + nTRST = 0x01; + nTRSTnOE = 0x00; /* no output enable for nTRST */ + nSRST = 0x80; + nSRSTnOE = 0x00; /* no output enable for nSRST */ + + high_output = 0x01; + high_direction = 0x03; + + /* initialize high port */ + buf[0] = 0x82; /* command "set data bits high byte" */ + buf[1] = high_output; + buf[2] = high_direction; + DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + ERROR("couldn't initialize FT2232 with 'stm32stick' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +void olimex_jtag_blink(void) +{ + /* Olimex ARM-USB-OCD has a LED connected to ACBUS3 + * ACBUS3 is bit 3 of the GPIOH port + */ + if (high_output & 0x08) + { + /* set port pin high */ + high_output &= 0x07; + } + else + { + /* set port pin low */ + high_output |= 0x08; + } + + BUFFER_ADD = 0x82; + BUFFER_ADD = high_output; + BUFFER_ADD = high_direction; +} + +void turtle_jtag_blink(void) +{ + /* + * Turtelizer2 has two LEDs connected to ACBUS2 and ACBUS3 + */ + if (high_output & 0x08) + { + high_output = 0x04; + } + else + { + high_output = 0x08; + } + + BUFFER_ADD = 0x82; + BUFFER_ADD = high_output; + BUFFER_ADD = high_direction; +} + + +int ft2232_quit(void) +{ +#if BUILD_FT2232_FTD2XX == 1 + FT_STATUS status; + + status = FT_Close(ftdih); +#elif BUILD_FT2232_LIBFTDI == 1 + ftdi_disable_bitbang(&ftdic); + + ftdi_usb_close(&ftdic); + + ftdi_deinit(&ftdic); +#endif + + free(ft2232_buffer); + ft2232_buffer = NULL; + + return ERROR_OK; +} + +int ft2232_handle_device_desc_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 1) + { + ft2232_device_desc = strdup(args[0]); + } + else + { + ERROR("expected exactly one argument to ft2232_device_desc <description>"); + } + + return ERROR_OK; +} + +int ft2232_handle_serial_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 1) + { + ft2232_serial = strdup(args[0]); + } + else + { + ERROR("expected exactly one argument to ft2232_serial <serial-number>"); + } + + return ERROR_OK; +} + +int ft2232_handle_layout_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 0) + return ERROR_OK; + + ft2232_layout = malloc(strlen(args[0]) + 1); + strcpy(ft2232_layout, args[0]); + + return ERROR_OK; +} + +int ft2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int i; + + if (argc > MAX_USB_IDS*2) { + WARNING("ignoring extra IDs in ft2232_vid_pid " + "(maximum is %d pairs)", MAX_USB_IDS); + argc = MAX_USB_IDS*2; + } + if (argc < 2 || (argc & 1)) + { + WARNING("incomplete ft2232_vid_pid configuration directive"); + if (argc < 2) + return ERROR_OK; + } + + for (i = 0; i+1 < argc; i += 2) { + ft2232_vid[i >> 1] = strtol(args[i], NULL, 0); + ft2232_pid[i >> 1] = strtol(args[i+1], NULL, 0); + } + /* + * Explicitly terminate, in case there are multiples instances of + * ft2232_vid_pid. + */ + ft2232_vid[i >> 1] = ft2232_pid[i >> 1] = 0; + + return ERROR_OK; +} + +int ft2232_handle_latency_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 1) + { + ft2232_latency = atoi(args[0]); + } + else + { + ERROR("expected exactly one argument to ft2232_latency <ms>"); + } + + return ERROR_OK; +} + + diff --git a/src/jtag/jtag.c b/src/jtag/jtag.c index 77c4b3f..600fe19 100644 --- a/src/jtag/jtag.c +++ b/src/jtag/jtag.c @@ -1,1841 +1,1841 @@ -/***************************************************************************
- * 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 "jtag.h"
-
-#include "command.h"
-#include "log.h"
-#include "interpreter.h"
-
-#include "stdlib.h"
-#include "string.h"
-#include <unistd.h>
-
-char* tap_state_strings[16] =
-{
- "tlr",
- "sds", "cd", "sd", "e1d", "pd", "e2d", "ud",
- "rti",
- "sis", "ci", "si", "e1i", "pi", "e2i", "ui"
-};
-
-typedef struct cmd_queue_page_s
-{
- void *address;
- size_t used;
- struct cmd_queue_page_s *next;
-} cmd_queue_page_t;
-
-#define CMD_QUEUE_PAGE_SIZE (1024 * 1024)
-static cmd_queue_page_t *cmd_queue_pages = NULL;
-
-/* tap_move[i][j]: tap movement command to go from state i to state j
- * 0: Test-Logic-Reset
- * 1: Run-Test/Idle
- * 2: Shift-DR
- * 3: Pause-DR
- * 4: Shift-IR
- * 5: Pause-IR
- *
- * SD->SD and SI->SI have to be caught in interface specific code
- */
-u8 tap_move[6][6] =
-{
-/* TLR RTI SD PD SI PI */
- {0x7f, 0x00, 0x17, 0x0a, 0x1b, 0x16}, /* TLR */
- {0x7f, 0x00, 0x25, 0x05, 0x2b, 0x0b}, /* RTI */
- {0x7f, 0x31, 0x00, 0x01, 0x0f, 0x2f}, /* SD */
- {0x7f, 0x30, 0x20, 0x17, 0x1e, 0x2f}, /* PD */
- {0x7f, 0x31, 0x07, 0x17, 0x00, 0x01}, /* SI */
- {0x7f, 0x30, 0x1c, 0x17, 0x20, 0x2f} /* PI */
-};
-
-int tap_move_map[16] = {
- 0, -1, -1, 2, -1, 3, -1, -1,
- 1, -1, -1, 4, -1, 5, -1, -1
-};
-
-tap_transition_t tap_transitions[16] =
-{
- {TAP_TLR, TAP_RTI}, /* TLR */
- {TAP_SIS, TAP_CD}, /* SDS */
- {TAP_E1D, TAP_SD}, /* CD */
- {TAP_E1D, TAP_SD}, /* SD */
- {TAP_UD, TAP_PD}, /* E1D */
- {TAP_E2D, TAP_PD}, /* PD */
- {TAP_UD, TAP_SD}, /* E2D */
- {TAP_SDS, TAP_RTI}, /* UD */
- {TAP_SDS, TAP_RTI}, /* RTI */
- {TAP_TLR, TAP_CI}, /* SIS */
- {TAP_E1I, TAP_SI}, /* CI */
- {TAP_E1I, TAP_SI}, /* SI */
- {TAP_UI, TAP_PI}, /* E1I */
- {TAP_E2I, TAP_PI}, /* PI */
- {TAP_UI, TAP_SI}, /* E2I */
- {TAP_SDS, TAP_RTI} /* UI */
-};
-
-char* jtag_event_strings[] =
-{
- "SRST asserted",
- "TRST asserted",
- "SRST released",
- "TRST released"
-};
-
-enum tap_state end_state = TAP_TLR;
-enum tap_state cur_state = TAP_TLR;
-int jtag_trst = 0;
-int jtag_srst = 0;
-
-jtag_command_t *jtag_command_queue = NULL;
-jtag_command_t **last_comand_pointer = &jtag_command_queue;
-jtag_device_t *jtag_devices = NULL;
-int jtag_num_devices = 0;
-int jtag_ir_scan_size = 0;
-enum reset_types jtag_reset_config = RESET_NONE;
-enum tap_state cmd_queue_end_state = TAP_TLR;
-enum tap_state cmd_queue_cur_state = TAP_TLR;
-
-int jtag_verify_capture_ir = 1;
-
-/* how long the OpenOCD should wait before attempting JTAG communication after reset lines deasserted (in ms) */
-int jtag_nsrst_delay = 0; /* default to no nSRST delay */
-int jtag_ntrst_delay = 0; /* default to no nTRST delay */
-
-/* maximum number of JTAG devices expected in the chain
- */
-#define JTAG_MAX_CHAIN_SIZE 20
-
-/* callbacks to inform high-level handlers about JTAG state changes */
-jtag_event_callback_t *jtag_event_callbacks;
-
-/* jtag interfaces (parport, FTDI-USB, TI-USB, ...)
- */
-#if BUILD_PARPORT == 1
- extern jtag_interface_t parport_interface;
-#endif
-
-#if BUILD_FT2232_FTD2XX == 1
- extern jtag_interface_t ft2232_interface;
-#endif
-
-#if BUILD_FT2232_LIBFTDI == 1
- extern jtag_interface_t ft2232_interface;
-#endif
-
-#if BUILD_AMTJTAGACCEL == 1
- extern jtag_interface_t amt_jtagaccel_interface;
-#endif
-
-#if BUILD_EP93XX == 1
- extern jtag_interface_t ep93xx_interface;
-#endif
-
-#if BUILD_AT91RM9200 == 1
- extern jtag_interface_t at91rm9200_interface;
-#endif
-
-#if BUILD_GW16012 == 1
- extern jtag_interface_t gw16012_interface;
-#endif
-
-#if BUILD_PRESTO_LIBFTDI == 1 || BUILD_PRESTO_FTD2XX == 1
- extern jtag_interface_t presto_interface;
-#endif
-
-#if BUILD_USBPROG == 1
- extern jtag_interface_t usbprog_interface;
-#endif
-
-jtag_interface_t *jtag_interfaces[] = {
-#if BUILD_PARPORT == 1
- &parport_interface,
-#endif
-#if BUILD_FT2232_FTD2XX == 1
- &ft2232_interface,
-#endif
-#if BUILD_FT2232_LIBFTDI == 1
- &ft2232_interface,
-#endif
-#if BUILD_AMTJTAGACCEL == 1
- &amt_jtagaccel_interface,
-#endif
-#if BUILD_EP93XX == 1
- &ep93xx_interface,
-#endif
-#if BUILD_AT91RM9200 == 1
- &at91rm9200_interface,
-#endif
-#if BUILD_GW16012 == 1
- &gw16012_interface,
-#endif
-#if BUILD_PRESTO_LIBFTDI == 1 || BUILD_PRESTO_FTD2XX == 1
- &presto_interface,
-#endif
-#if BUILD_USBPROG == 1
- &usbprog_interface,
-#endif
- NULL,
-};
-
-jtag_interface_t *jtag = NULL;
-
-/* configuration */
-jtag_interface_t *jtag_interface = NULL;
-int jtag_speed = 0;
-
-
-/* forward declarations */
-int jtag_add_statemove(enum tap_state endstate);
-int jtag_add_pathmove(int num_states, enum tap_state *path);
-int jtag_add_runtest(int num_cycles, enum tap_state endstate);
-int jtag_add_reset(int trst, int srst);
-int jtag_add_end_state(enum tap_state endstate);
-int jtag_add_sleep(u32 us);
-int jtag_execute_queue(void);
-int jtag_cancel_queue(void);
-
-/* jtag commands */
-int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_jtag_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_jtag_nsrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_jtag_ntrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-int handle_scan_chain_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-int handle_endstate_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_jtag_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_runtest_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_statemove_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_irscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_drscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-int handle_verify_ircapture_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-int jtag_register_event_callback(int (*callback)(enum jtag_event event, void *priv), void *priv)
-{
- jtag_event_callback_t **callbacks_p = &jtag_event_callbacks;
-
- if (callback == NULL)
- {
- return ERROR_INVALID_ARGUMENTS;
- }
-
- if (*callbacks_p)
- {
- while ((*callbacks_p)->next)
- callbacks_p = &((*callbacks_p)->next);
- callbacks_p = &((*callbacks_p)->next);
- }
-
- (*callbacks_p) = malloc(sizeof(jtag_event_callback_t));
- (*callbacks_p)->callback = callback;
- (*callbacks_p)->priv = priv;
- (*callbacks_p)->next = NULL;
-
- return ERROR_OK;
-}
-
-int jtag_unregister_event_callback(int (*callback)(enum jtag_event event, void *priv))
-{
- jtag_event_callback_t **callbacks_p = &jtag_event_callbacks;
-
- if (callback == NULL)
- {
- return ERROR_INVALID_ARGUMENTS;
- }
-
- while (*callbacks_p)
- {
- jtag_event_callback_t **next = &((*callbacks_p)->next);
- if ((*callbacks_p)->callback == callback)
- {
- free(*callbacks_p);
- *callbacks_p = *next;
- }
- callbacks_p = next;
- }
-
- return ERROR_OK;
-}
-
-int jtag_call_event_callbacks(enum jtag_event event)
-{
- jtag_event_callback_t *callback = jtag_event_callbacks;
-
- DEBUG("jtag event: %s", jtag_event_strings[event]);
-
- while (callback)
- {
- callback->callback(event, callback->priv);
- callback = callback->next;
- }
-
- return ERROR_OK;
-}
-
-/* returns a pointer to the pointer of the last command in queue
- * this may be a pointer to the root pointer (jtag_command_queue)
- * or to the next member of the last but one command
- */
-jtag_command_t** jtag_get_last_command_p(void)
-{
-/* jtag_command_t *cmd = jtag_command_queue;
-
- if (cmd)
- while (cmd->next)
- cmd = cmd->next;
- else
- return &jtag_command_queue;
-
- return &cmd->next;*/
-
- return last_comand_pointer;
-}
-
-/* returns a pointer to the n-th device in the scan chain */
-jtag_device_t* jtag_get_device(int num)
-{
- jtag_device_t *device = jtag_devices;
- int i = 0;
-
- while (device)
- {
- if (num == i)
- return device;
- device = device->next;
- i++;
- }
-
- ERROR("jtag device number %d not defined", num);
- exit(-1);
-}
-
-void* cmd_queue_alloc(size_t size)
-{
- cmd_queue_page_t **p_page = &cmd_queue_pages;
- int offset;
-
- if (*p_page)
- {
- while ((*p_page)->next)
- p_page = &((*p_page)->next);
- if (CMD_QUEUE_PAGE_SIZE - (*p_page)->used < size)
- p_page = &((*p_page)->next);
- }
-
- if (!*p_page)
- {
- *p_page = malloc(sizeof(cmd_queue_page_t));
- (*p_page)->used = 0;
- (*p_page)->address = malloc(CMD_QUEUE_PAGE_SIZE);
- (*p_page)->next = NULL;
- }
-
- offset = (*p_page)->used;
- (*p_page)->used += size;
-
- u8 *t=(u8 *)((*p_page)->address);
- return t + offset;
-}
-
-void cmd_queue_free()
-{
- cmd_queue_page_t *page = cmd_queue_pages;
-
- while (page)
- {
- cmd_queue_page_t *last = page;
- free(page->address);
- page = page->next;
- free(last);
- }
-
- cmd_queue_pages = NULL;
-}
-
-int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state)
-{
- jtag_command_t **last_cmd;
- jtag_device_t *device;
- int i, j;
- int scan_size = 0;
-
- if (jtag_trst == 1)
- {
- WARNING("JTAG command queued, while TRST is low (TAP in reset)");
- return ERROR_JTAG_TRST_ASSERTED;
- }
-
- last_cmd = jtag_get_last_command_p();
-
- /* allocate memory for a new list member */
- *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
- (*last_cmd)->next = NULL;
- last_comand_pointer = &((*last_cmd)->next);
- (*last_cmd)->type = JTAG_SCAN;
-
- /* allocate memory for ir scan command */
- (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t));
- (*last_cmd)->cmd.scan->ir_scan = 1;
- (*last_cmd)->cmd.scan->num_fields = jtag_num_devices; /* one field per device */
- (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(jtag_num_devices * sizeof(scan_field_t));
- (*last_cmd)->cmd.scan->end_state = state;
-
- if (state != -1)
- cmd_queue_end_state = state;
-
- if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR)
- jtag_call_event_callbacks(JTAG_TRST_RELEASED);
-
- if (cmd_queue_end_state == TAP_TLR)
- jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
-
- cmd_queue_cur_state = cmd_queue_end_state;
-
- for (i = 0; i < jtag_num_devices; i++)
- {
- int found = 0;
- device = jtag_get_device(i);
- scan_size = device->ir_length;
- (*last_cmd)->cmd.scan->fields[i].device = i;
- (*last_cmd)->cmd.scan->fields[i].num_bits = scan_size;
- (*last_cmd)->cmd.scan->fields[i].in_value = NULL;
- (*last_cmd)->cmd.scan->fields[i].in_handler = NULL; /* disable verification by default */
-
- /* search the list */
- for (j = 0; j < num_fields; j++)
- {
- if (i == fields[j].device)
- {
- found = 1;
- (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(fields[j].out_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
- (*last_cmd)->cmd.scan->fields[i].out_mask = buf_cpy(fields[j].out_mask, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
-
- if (jtag_verify_capture_ir)
- {
- if (fields[j].in_handler==NULL)
- {
- jtag_set_check_value((*last_cmd)->cmd.scan->fields+i, device->expected, device->expected_mask, NULL);
- } else
- {
- (*last_cmd)->cmd.scan->fields[i].in_handler = fields[j].in_handler;
- (*last_cmd)->cmd.scan->fields[i].in_handler_priv = fields[j].in_handler_priv;
- (*last_cmd)->cmd.scan->fields[i].in_check_value = device->expected;
- (*last_cmd)->cmd.scan->fields[i].in_check_mask = device->expected_mask;
- }
- }
-
- device->bypass = 0;
- break;
- }
- }
-
- if (!found)
- {
- /* if a device isn't listed, set it to BYPASS */
- (*last_cmd)->cmd.scan->fields[i].out_value = buf_set_ones(cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
- (*last_cmd)->cmd.scan->fields[i].out_mask = NULL;
- device->bypass = 1;
-
- }
-
- /* update device information */
- buf_cpy((*last_cmd)->cmd.scan->fields[i].out_value, jtag_get_device(i)->cur_instr, scan_size);
- }
-
- return ERROR_OK;
-}
-
-int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state)
-{
- jtag_command_t **last_cmd;
- int i;
-
- if (jtag_trst == 1)
- {
- WARNING("JTAG command queued, while TRST is low (TAP in reset)");
- return ERROR_JTAG_TRST_ASSERTED;
- }
-
- last_cmd = jtag_get_last_command_p();
-
- /* allocate memory for a new list member */
- *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
- (*last_cmd)->next = NULL;
- last_comand_pointer = &((*last_cmd)->next);
- (*last_cmd)->type = JTAG_SCAN;
-
- /* allocate memory for ir scan command */
- (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t));
- (*last_cmd)->cmd.scan->ir_scan = 1;
- (*last_cmd)->cmd.scan->num_fields = num_fields;
- (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(num_fields * sizeof(scan_field_t));
- (*last_cmd)->cmd.scan->end_state = state;
-
- if (state != -1)
- cmd_queue_end_state = state;
-
- if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR)
- jtag_call_event_callbacks(JTAG_TRST_RELEASED);
-
- if (cmd_queue_end_state == TAP_TLR)
- jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
-
- cmd_queue_cur_state = cmd_queue_end_state;
-
- for (i = 0; i < num_fields; i++)
- {
- int num_bits = fields[i].num_bits;
- int num_bytes = CEIL(fields[i].num_bits, 8);
- (*last_cmd)->cmd.scan->fields[i].device = fields[i].device;
- (*last_cmd)->cmd.scan->fields[i].num_bits = num_bits;
- (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(fields[i].out_value, cmd_queue_alloc(num_bytes), num_bits);
- (*last_cmd)->cmd.scan->fields[i].out_mask = buf_cpy(fields[i].out_mask, cmd_queue_alloc(num_bytes), num_bits);
- (*last_cmd)->cmd.scan->fields[i].in_value = fields[i].in_value;
- (*last_cmd)->cmd.scan->fields[i].in_check_value = fields[i].in_check_value;
- (*last_cmd)->cmd.scan->fields[i].in_check_mask = fields[i].in_check_mask;
- (*last_cmd)->cmd.scan->fields[i].in_handler = NULL;
- (*last_cmd)->cmd.scan->fields[i].in_handler_priv = NULL;
- }
- return ERROR_OK;
-}
-
-int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state)
-{
- int i, j;
- int bypass_devices = 0;
- int field_count = 0;
- jtag_command_t **last_cmd = jtag_get_last_command_p();
- jtag_device_t *device = jtag_devices;
- int scan_size;
-
- if (jtag_trst == 1)
- {
- WARNING("JTAG command queued, while TRST is low (TAP in reset)");
- return ERROR_JTAG_TRST_ASSERTED;
- }
-
- /* count devices in bypass */
- while (device)
- {
- if (device->bypass)
- bypass_devices++;
- device = device->next;
- }
-
- /* allocate memory for a new list member */
- *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
- last_comand_pointer = &((*last_cmd)->next);
- (*last_cmd)->next = NULL;
- (*last_cmd)->type = JTAG_SCAN;
-
- /* allocate memory for dr scan command */
- (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t));
- (*last_cmd)->cmd.scan->ir_scan = 0;
- (*last_cmd)->cmd.scan->num_fields = num_fields + bypass_devices;
- (*last_cmd)->cmd.scan->fields = cmd_queue_alloc((num_fields + bypass_devices) * sizeof(scan_field_t));
- (*last_cmd)->cmd.scan->end_state = state;
-
- if (state != -1)
- cmd_queue_end_state = state;
-
- if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR)
- jtag_call_event_callbacks(JTAG_TRST_RELEASED);
-
- if (cmd_queue_end_state == TAP_TLR)
- jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
-
- cmd_queue_cur_state = cmd_queue_end_state;
-
- for (i = 0; i < jtag_num_devices; i++)
- {
- int found = 0;
- (*last_cmd)->cmd.scan->fields[field_count].device = i;
-
- for (j = 0; j < num_fields; j++)
- {
- if (i == fields[j].device)
- {
- found = 1;
- scan_size = fields[j].num_bits;
- (*last_cmd)->cmd.scan->fields[field_count].num_bits = scan_size;
- (*last_cmd)->cmd.scan->fields[field_count].out_value = buf_cpy(fields[j].out_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
- (*last_cmd)->cmd.scan->fields[field_count].out_mask = buf_cpy(fields[j].out_mask, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
- (*last_cmd)->cmd.scan->fields[field_count].in_value = fields[j].in_value;
- (*last_cmd)->cmd.scan->fields[field_count].in_check_value = fields[j].in_check_value;
- (*last_cmd)->cmd.scan->fields[field_count].in_check_mask = fields[j].in_check_mask;
- (*last_cmd)->cmd.scan->fields[field_count].in_handler = fields[j].in_handler;
- (*last_cmd)->cmd.scan->fields[field_count++].in_handler_priv = fields[j].in_handler_priv;
- }
- }
- if (!found)
- {
- /* if a device isn't listed, the BYPASS register should be selected */
- if (!jtag_get_device(i)->bypass)
- {
- ERROR("BUG: no scan data for a device not in BYPASS");
- exit(-1);
- }
-
- /* program the scan field to 1 bit length, and ignore it's value */
- (*last_cmd)->cmd.scan->fields[field_count].num_bits = 1;
- (*last_cmd)->cmd.scan->fields[field_count].out_value = NULL;
- (*last_cmd)->cmd.scan->fields[field_count].out_mask = NULL;
- (*last_cmd)->cmd.scan->fields[field_count].in_value = NULL;
- (*last_cmd)->cmd.scan->fields[field_count].in_check_value = NULL;
- (*last_cmd)->cmd.scan->fields[field_count].in_check_mask = NULL;
- (*last_cmd)->cmd.scan->fields[field_count].in_handler = NULL;
- (*last_cmd)->cmd.scan->fields[field_count++].in_handler_priv = NULL;
- }
- else
- {
- /* if a device is listed, the BYPASS register must not be selected */
- if (jtag_get_device(i)->bypass)
- {
- WARNING("scan data for a device in BYPASS");
- }
- }
- }
- return ERROR_OK;
-}
-
-
-int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state)
-{
- int i;
- jtag_command_t **last_cmd = jtag_get_last_command_p();
-
- if (jtag_trst == 1)
- {
- WARNING("JTAG command queued, while TRST is low (TAP in reset)");
- return ERROR_JTAG_TRST_ASSERTED;
- }
-
- /* allocate memory for a new list member */
- *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
- last_comand_pointer = &((*last_cmd)->next);
- (*last_cmd)->next = NULL;
- (*last_cmd)->type = JTAG_SCAN;
-
- /* allocate memory for scan command */
- (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t));
- (*last_cmd)->cmd.scan->ir_scan = 0;
- (*last_cmd)->cmd.scan->num_fields = num_fields;
- (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(num_fields * sizeof(scan_field_t));
- (*last_cmd)->cmd.scan->end_state = state;
-
- if (state != -1)
- cmd_queue_end_state = state;
-
- if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR)
- jtag_call_event_callbacks(JTAG_TRST_RELEASED);
-
- if (cmd_queue_end_state == TAP_TLR)
- jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
-
- cmd_queue_cur_state = cmd_queue_end_state;
-
- for (i = 0; i < num_fields; i++)
- {
- int num_bits = fields[i].num_bits;
- int num_bytes = CEIL(fields[i].num_bits, 8);
- (*last_cmd)->cmd.scan->fields[i].device = fields[i].device;
- (*last_cmd)->cmd.scan->fields[i].num_bits = num_bits;
- (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(fields[i].out_value, cmd_queue_alloc(num_bytes), num_bits);
- (*last_cmd)->cmd.scan->fields[i].out_mask = buf_cpy(fields[i].out_mask, cmd_queue_alloc(num_bytes), num_bits);
- (*last_cmd)->cmd.scan->fields[i].in_value = fields[i].in_value;
- (*last_cmd)->cmd.scan->fields[i].in_check_value = fields[i].in_check_value;
- (*last_cmd)->cmd.scan->fields[i].in_check_mask = fields[i].in_check_mask;
- (*last_cmd)->cmd.scan->fields[i].in_handler = fields[i].in_handler;
- (*last_cmd)->cmd.scan->fields[i].in_handler_priv = fields[i].in_handler_priv;
- }
-
- return ERROR_OK;
-}
-int jtag_add_statemove(enum tap_state state)
-{
- jtag_command_t **last_cmd = jtag_get_last_command_p();
-
- if (jtag_trst == 1)
- {
- WARNING("JTAG command queued, while TRST is low (TAP in reset)");
- return ERROR_JTAG_TRST_ASSERTED;
- }
-
- /* allocate memory for a new list member */
- *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
- last_comand_pointer = &((*last_cmd)->next);
- (*last_cmd)->next = NULL;
- (*last_cmd)->type = JTAG_STATEMOVE;
-
- (*last_cmd)->cmd.statemove = cmd_queue_alloc(sizeof(statemove_command_t));
- (*last_cmd)->cmd.statemove->end_state = state;
-
- if (state != -1)
- cmd_queue_end_state = state;
-
- if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR)
- jtag_call_event_callbacks(JTAG_TRST_RELEASED);
-
- if (cmd_queue_end_state == TAP_TLR)
- jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
-
- cmd_queue_cur_state = cmd_queue_end_state;
-
- return ERROR_OK;
-}
-
-int jtag_add_pathmove(int num_states, enum tap_state *path)
-{
- jtag_command_t **last_cmd = jtag_get_last_command_p();
- int i;
-
- if (jtag_trst == 1)
- {
- WARNING("JTAG command queued, while TRST is low (TAP in reset)");
- return ERROR_JTAG_TRST_ASSERTED;
- }
-
- /* the last state has to be a stable state */
- if (tap_move_map[path[num_states - 1]] == -1)
- {
- ERROR("TAP path doesn't finish in a stable state");
- return ERROR_JTAG_NOT_IMPLEMENTED;
- }
-
- /* allocate memory for a new list member */
- *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
- last_comand_pointer = &((*last_cmd)->next);
- (*last_cmd)->next = NULL;
- (*last_cmd)->type = JTAG_PATHMOVE;
-
- (*last_cmd)->cmd.pathmove = cmd_queue_alloc(sizeof(pathmove_command_t));
- (*last_cmd)->cmd.pathmove->num_states = num_states;
- (*last_cmd)->cmd.pathmove->path = cmd_queue_alloc(sizeof(enum tap_state) * num_states);
-
- for (i = 0; i < num_states; i++)
- (*last_cmd)->cmd.pathmove->path[i] = path[i];
-
- if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR)
- jtag_call_event_callbacks(JTAG_TRST_RELEASED);
-
- if (cmd_queue_end_state == TAP_TLR)
- jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
-
- cmd_queue_cur_state = path[num_states - 1];
-
- return ERROR_OK;
-}
-
-int jtag_add_runtest(int num_cycles, enum tap_state state)
-{
- jtag_command_t **last_cmd = jtag_get_last_command_p();
-
- if (jtag_trst == 1)
- {
- WARNING("JTAG command queued, while TRST is low (TAP in reset)");
- return ERROR_JTAG_TRST_ASSERTED;
- }
-
- /* allocate memory for a new list member */
- *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
- (*last_cmd)->next = NULL;
- last_comand_pointer = &((*last_cmd)->next);
- (*last_cmd)->type = JTAG_RUNTEST;
-
- (*last_cmd)->cmd.runtest = cmd_queue_alloc(sizeof(runtest_command_t));
- (*last_cmd)->cmd.runtest->num_cycles = num_cycles;
- (*last_cmd)->cmd.runtest->end_state = state;
-
- if (state != -1)
- cmd_queue_end_state = state;
-
- if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR)
- jtag_call_event_callbacks(JTAG_TRST_RELEASED);
-
- if (cmd_queue_end_state == TAP_TLR)
- jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
-
- cmd_queue_cur_state = cmd_queue_end_state;
-
- return ERROR_OK;
-}
-
-int jtag_add_reset(int req_trst, int req_srst)
-{
- int trst_with_tms = 0;
-
- jtag_command_t **last_cmd = jtag_get_last_command_p();
-
- if (req_trst == -1)
- req_trst = jtag_trst;
-
- if (req_srst == -1)
- req_srst = jtag_srst;
-
- /* Make sure that jtag_reset_config allows the requested reset */
- /* if SRST pulls TRST, we can't fulfill srst == 1 with trst == 0 */
- if (((jtag_reset_config & RESET_SRST_PULLS_TRST) && (req_srst == 1)) && (req_trst == 0))
- return ERROR_JTAG_RESET_WOULD_ASSERT_TRST;
-
- /* if TRST pulls SRST, we reset with TAP T-L-R */
- if (((jtag_reset_config & RESET_TRST_PULLS_SRST) && (req_trst == 1)) && (req_srst == 0))
- {
- req_trst = 0;
- trst_with_tms = 1;
- }
-
- if (req_srst && !(jtag_reset_config & RESET_HAS_SRST))
- {
- ERROR("requested nSRST assertion, but the current configuration doesn't support this");
- return ERROR_JTAG_RESET_CANT_SRST;
- }
-
- if (req_trst && !(jtag_reset_config & RESET_HAS_TRST))
- {
- req_trst = 0;
- trst_with_tms = 1;
- }
-
- /* allocate memory for a new list member */
- *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
- (*last_cmd)->next = NULL;
- last_comand_pointer = &((*last_cmd)->next);
- (*last_cmd)->type = JTAG_RESET;
-
- (*last_cmd)->cmd.reset = cmd_queue_alloc(sizeof(reset_command_t));
- (*last_cmd)->cmd.reset->trst = req_trst;
- (*last_cmd)->cmd.reset->srst = req_srst;
-
- jtag_trst = req_trst;
- jtag_srst = req_srst;
-
- if (jtag_srst)
- {
- jtag_call_event_callbacks(JTAG_SRST_ASSERTED);
- }
- else
- {
- jtag_call_event_callbacks(JTAG_SRST_RELEASED);
- if (jtag_nsrst_delay)
- jtag_add_sleep(jtag_nsrst_delay * 1000);
- }
-
- if (trst_with_tms)
- {
- last_cmd = &((*last_cmd)->next);
-
- /* allocate memory for a new list member */
- *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
- (*last_cmd)->next = NULL;
- last_comand_pointer = &((*last_cmd)->next);
- (*last_cmd)->type = JTAG_STATEMOVE;
-
- (*last_cmd)->cmd.statemove = cmd_queue_alloc(sizeof(statemove_command_t));
- (*last_cmd)->cmd.statemove->end_state = TAP_TLR;
-
- jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
- cmd_queue_cur_state = TAP_TLR;
- cmd_queue_end_state = TAP_TLR;
-
- return ERROR_OK;
- }
- else
- {
- if (jtag_trst)
- {
- /* we just asserted nTRST, so we're now in Test-Logic-Reset,
- * and inform possible listeners about this
- */
- cmd_queue_cur_state = TAP_TLR;
- jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
- }
- else
- {
- /* the nTRST line got deasserted, so we're still in Test-Logic-Reset,
- * but we might want to add a delay to give the TAP time to settle
- */
- if (jtag_ntrst_delay)
- jtag_add_sleep(jtag_ntrst_delay * 1000);
- }
- }
-
- return ERROR_OK;
-}
-
-int jtag_add_end_state(enum tap_state state)
-{
- jtag_command_t **last_cmd = jtag_get_last_command_p();
-
- /* allocate memory for a new list member */
- *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
- (*last_cmd)->next = NULL;
- last_comand_pointer = &((*last_cmd)->next);
- (*last_cmd)->type = JTAG_END_STATE;
-
- (*last_cmd)->cmd.end_state = cmd_queue_alloc(sizeof(end_state_command_t));
- (*last_cmd)->cmd.end_state->end_state = state;
-
- if (state != -1)
- cmd_queue_end_state = state;
-
- return ERROR_OK;
-}
-
-int jtag_add_sleep(u32 us)
-{
- jtag_command_t **last_cmd = jtag_get_last_command_p();
-
- /* allocate memory for a new list member */
- *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
- (*last_cmd)->next = NULL;
- last_comand_pointer = &((*last_cmd)->next);
- (*last_cmd)->type = JTAG_SLEEP;
-
- (*last_cmd)->cmd.sleep = cmd_queue_alloc(sizeof(sleep_command_t));
- (*last_cmd)->cmd.sleep->us = us;
-
- return ERROR_OK;
-}
-
-int jtag_scan_size(scan_command_t *cmd)
-{
- int bit_count = 0;
- int i;
-
- /* count bits in scan command */
- for (i = 0; i < cmd->num_fields; i++)
- {
- bit_count += cmd->fields[i].num_bits;
- }
-
- return bit_count;
-}
-
-int jtag_build_buffer(scan_command_t *cmd, u8 **buffer)
-{
- int bit_count = 0;
- int i;
-
- bit_count = jtag_scan_size(cmd);
- *buffer = malloc(CEIL(bit_count, 8));
-
- bit_count = 0;
-
- for (i = 0; i < cmd->num_fields; i++)
- {
- if (cmd->fields[i].out_value)
- {
-#ifdef _DEBUG_JTAG_IO_
- char* char_buf = buf_to_str(cmd->fields[i].out_value, (cmd->fields[i].num_bits > 64) ? 64 : 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;
- }
-
- return bit_count;
-
-}
-
-int jtag_read_buffer(u8 *buffer, scan_command_t *cmd)
-{
- int i;
- int bit_count = 0;
- int retval;
-
- /* we return ERROR_OK, unless a check fails, or a handler reports a problem */
- retval = ERROR_OK;
-
- for (i = 0; i < cmd->num_fields; i++)
- {
- /* if neither in_value nor in_handler
- * are specified we don't have to examine this field
- */
- if (cmd->fields[i].in_value || cmd->fields[i].in_handler)
- {
- int num_bits = cmd->fields[i].num_bits;
- u8 *captured = buf_set_buf(buffer, bit_count, malloc(CEIL(num_bits, 8)), 0, num_bits);
-
-#ifdef _DEBUG_JTAG_IO_
- char *char_buf;
-
- char_buf = buf_to_str(captured, (num_bits > 64) ? 64 : num_bits, 16);
- DEBUG("fields[%i].in_value: 0x%s", i, char_buf);
- free(char_buf);
-#endif
-
- if (cmd->fields[i].in_value)
- {
- buf_cpy(captured, cmd->fields[i].in_value, num_bits);
-
- if (cmd->fields[i].in_handler)
- {
- if (cmd->fields[i].in_handler(cmd->fields[i].in_value, cmd->fields[i].in_handler_priv, cmd->fields+i) != ERROR_OK)
- {
- WARNING("in_handler reported a failed check");
- retval = ERROR_JTAG_QUEUE_FAILED;
- }
- }
- }
-
- /* no in_value specified, but a handler takes care of the scanned data */
- if (cmd->fields[i].in_handler && (!cmd->fields[i].in_value))
- {
- if (cmd->fields[i].in_handler(captured, cmd->fields[i].in_handler_priv, cmd->fields+i) != ERROR_OK)
- {
- /* We're going to call the error:handler later, but if the in_handler
- * reported an error we report this failure upstream
- */
- WARNING("in_handler reported a failed check");
- retval = ERROR_JTAG_QUEUE_FAILED;
- }
- }
-
- free(captured);
- }
- bit_count += cmd->fields[i].num_bits;
- }
-
- return retval;
-}
-
-int jtag_check_value(u8 *captured, void *priv, scan_field_t *field)
-{
- int retval = ERROR_OK;
- int num_bits = field->num_bits;
-
- int compare_failed = 0;
-
- if (field->in_check_mask)
- compare_failed = buf_cmp_mask(captured, field->in_check_value, field->in_check_mask, num_bits);
- else
- compare_failed = buf_cmp(captured, field->in_check_value, num_bits);
-
- if (compare_failed)
- {
- /* An error handler could have caught the failing check
- * only report a problem when there wasn't a handler, or if the handler
- * acknowledged the error
- */
- if (compare_failed)
- {
- char *captured_char = buf_to_str(captured, (num_bits > 64) ? 64 : num_bits, 16);
- char *in_check_value_char = buf_to_str(field->in_check_value, (num_bits > 64) ? 64 : num_bits, 16);
-
- if (field->in_check_mask)
- {
- char *in_check_mask_char;
- in_check_mask_char = buf_to_str(field->in_check_mask, (num_bits > 64) ? 64 : num_bits, 16);
- 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);
- free(in_check_mask_char);
- }
- else
- {
- WARNING("value captured during scan didn't pass the requested check: captured: 0x%s check_value: 0x%s", captured_char, in_check_value_char);
- }
-
- free(captured_char);
- free(in_check_value_char);
-
- retval = ERROR_JTAG_QUEUE_FAILED;
- }
-
- }
- return retval;
-}
-
-/*
- set up checking of this field using the in_handler. The values passed in must be valid until
- after jtag_execute() has completed.
- */
-void jtag_set_check_value(scan_field_t *field, u8 *value, u8 *mask, error_handler_t *in_error_handler)
-{
- if (value)
- field->in_handler = jtag_check_value;
- else
- field->in_handler = NULL; /* No check, e.g. embeddedice uses value==NULL to indicate no check */
- field->in_handler_priv = NULL; /* this will be filled in at the invocation site to point to the field duplicate */
- field->in_check_value = value;
- field->in_check_mask = mask;
-}
-
-enum scan_type jtag_scan_type(scan_command_t *cmd)
-{
- int i;
- int type = 0;
-
- for (i = 0; i < cmd->num_fields; i++)
- {
- if (cmd->fields[i].in_value || cmd->fields[i].in_handler)
- type |= SCAN_IN;
- if (cmd->fields[i].out_value)
- type |= SCAN_OUT;
- }
-
- return type;
-}
-
-int jtag_execute_queue(void)
-{
- int retval;
-
- retval = jtag->execute_queue();
-
- cmd_queue_free();
-
- jtag_command_queue = NULL;
- last_comand_pointer = &jtag_command_queue;
-
- return retval;
-}
-
-int jtag_reset_callback(enum jtag_event event, void *priv)
-{
- jtag_device_t *device = priv;
-
- DEBUG("-");
-
- if (event == JTAG_TRST_ASSERTED)
- {
- buf_set_ones(device->cur_instr, device->ir_length);
- device->bypass = 1;
- }
-
- return ERROR_OK;
-}
-
-void jtag_sleep(u32 us)
-{
- usleep(us);
-}
-
-/* Try to examine chain layout according to IEEE 1149.1 §12
- */
-int jtag_examine_chain()
-{
- jtag_device_t *device = jtag_devices;
- scan_field_t field;
- u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
- int i;
- int bit_count;
- int device_count = 0;
- u8 zero_check = 0x0;
- u8 one_check = 0xff;
-
- field.device = 0;
- field.num_bits = sizeof(idcode_buffer) * 8;
- field.out_value = idcode_buffer;
- field.out_mask = NULL;
- field.in_value = idcode_buffer;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- for (i = 0; i < JTAG_MAX_CHAIN_SIZE; i++)
- {
- buf_set_u32(idcode_buffer, i * 32, 32, 0x000000FF);
- }
-
- jtag_add_plain_dr_scan(1, &field, TAP_TLR);
- jtag_execute_queue();
-
- for (i = 0; i < JTAG_MAX_CHAIN_SIZE * 4; i++)
- {
- zero_check |= idcode_buffer[i];
- one_check &= idcode_buffer[i];
- }
-
- /* if there wasn't a single non-zero bit or if all bits were one, the scan isn't valid */
- if ((zero_check == 0x00) || (one_check == 0xff))
- {
- ERROR("JTAG communication failure, check connection, JTAG interface, target power etc.");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- for (bit_count = 0; bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;)
- {
- u32 idcode = buf_get_u32(idcode_buffer, bit_count, 32);
- if ((idcode & 1) == 0)
- {
- /* LSB must not be 0, this indicates a device in bypass */
- device_count++;
-
- bit_count += 1;
- }
- else
- {
- u32 manufacturer;
- u32 part;
- u32 version;
-
- if (idcode == 0x000000FF)
- {
- /* End of chain (invalid manufacturer ID) */
- break;
- }
-
- if (device)
- {
- device->idcode = idcode;
- device = device->next;
- }
- device_count++;
-
- manufacturer = (idcode & 0xffe) >> 1;
- part = (idcode & 0xffff000) >> 12;
- version = (idcode & 0xf0000000) >> 28;
-
- INFO("JTAG device found: 0x%8.8x (Manufacturer: 0x%3.3x, Part: 0x%4.4x, Version: 0x%1.1x)",
- idcode, manufacturer, part, version);
-
- bit_count += 32;
- }
- }
-
- /* see if number of discovered devices matches configuration */
- if (device_count != jtag_num_devices)
- {
- ERROR("number of discovered devices in JTAG chain (%i) doesn't match configuration (%i)",
- device_count, jtag_num_devices);
- ERROR("check the config file and ensure proper JTAG communication (connections, speed, ...)");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- return ERROR_OK;
-}
-
-int jtag_validate_chain()
-{
- jtag_device_t *device = jtag_devices;
- int total_ir_length = 0;
- u8 *ir_test = NULL;
- scan_field_t field;
- int chain_pos = 0;
-
- while (device)
- {
- total_ir_length += device->ir_length;
- device = device->next;
- }
-
- total_ir_length += 2;
- ir_test = malloc(CEIL(total_ir_length, 8));
- buf_set_ones(ir_test, total_ir_length);
-
- field.device = 0;
- field.num_bits = total_ir_length;
- field.out_value = ir_test;
- field.out_mask = NULL;
- field.in_value = ir_test;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_plain_ir_scan(1, &field, TAP_TLR);
- jtag_execute_queue();
-
- device = jtag_devices;
- while (device)
- {
- if (buf_get_u32(ir_test, chain_pos, 2) != 0x1)
- {
- 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);
- free(ir_test);
- return ERROR_JTAG_INIT_FAILED;
- }
- chain_pos += device->ir_length;
- device = device->next;
- }
-
- if (buf_get_u32(ir_test, chain_pos, 2) != 0x3)
- {
- 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);
- free(ir_test);
- return ERROR_JTAG_INIT_FAILED;
- }
-
- free(ir_test);
-
- return ERROR_OK;
-}
-
-int jtag_register_commands(struct command_context_s *cmd_ctx)
-{
- register_command(cmd_ctx, NULL, "interface", handle_interface_command,
- COMMAND_CONFIG, NULL);
- register_command(cmd_ctx, NULL, "jtag_speed", handle_jtag_speed_command,
- COMMAND_ANY, "set jtag speed (if supported) <speed>");
- register_command(cmd_ctx, NULL, "jtag_device", handle_jtag_device_command,
- COMMAND_CONFIG, "jtag_device <ir_length> <ir_expected> <ir_mask>");
- register_command(cmd_ctx, NULL, "reset_config", handle_reset_config_command,
- COMMAND_CONFIG, NULL);
- register_command(cmd_ctx, NULL, "jtag_nsrst_delay", handle_jtag_nsrst_delay_command,
- COMMAND_CONFIG, NULL);
- register_command(cmd_ctx, NULL, "jtag_ntrst_delay", handle_jtag_ntrst_delay_command,
- COMMAND_CONFIG, NULL);
-
- register_command(cmd_ctx, NULL, "scan_chain", handle_scan_chain_command,
- COMMAND_EXEC, "print current scan chain configuration");
-
- register_command(cmd_ctx, NULL, "endstate", handle_endstate_command,
- COMMAND_EXEC, "finish JTAG operations in <tap_state>");
- register_command(cmd_ctx, NULL, "jtag_reset", handle_jtag_reset_command,
- COMMAND_EXEC, "toggle reset lines <trst> <srst>");
- register_command(cmd_ctx, NULL, "runtest", handle_runtest_command,
- COMMAND_EXEC, "move to Run-Test/Idle, and execute <num_cycles>");
- register_command(cmd_ctx, NULL, "statemove", handle_statemove_command,
- COMMAND_EXEC, "move to current endstate or [tap_state]");
- register_command(cmd_ctx, NULL, "irscan", handle_irscan_command,
- COMMAND_EXEC, "execute IR scan <device> <instr> [dev2] [instr2] ...");
- register_command(cmd_ctx, NULL, "drscan", handle_drscan_command,
- COMMAND_EXEC, "execute DR scan <device> <var> [dev2] [var2] ...");
-
- register_command(cmd_ctx, NULL, "verify_ircapture", handle_verify_ircapture_command,
- COMMAND_ANY, "verify value captured during Capture-IR <enable|disable>");
- return ERROR_OK;
-}
-
-int jtag_interface_init(struct command_context_s *cmd_ctx)
-{
- if (!jtag_interface)
- {
- /* nothing was previously specified by "interface" command */
- ERROR("JTAG interface has to be specified, see \"interface\" command");
- return ERROR_JTAG_INVALID_INTERFACE;
- }
-
- if (jtag_interface->init() != ERROR_OK)
- return ERROR_JTAG_INIT_FAILED;
-
- jtag = jtag_interface;
- return ERROR_OK;
-}
-
-int jtag_init(struct command_context_s *cmd_ctx)
-{
- int i, validate_tries = 0;
- jtag_device_t *device;
-
- DEBUG("-");
-
- if (!jtag && jtag_interface_init(cmd_ctx) != ERROR_OK)
- return ERROR_JTAG_INIT_FAILED;
-
- device = jtag_devices;
- jtag_ir_scan_size = 0;
- jtag_num_devices = 0;
- while (device != NULL)
- {
- jtag_ir_scan_size += device->ir_length;
- jtag_num_devices++;
- device = device->next;
- }
-
- jtag_add_statemove(TAP_TLR);
- jtag_execute_queue();
-
- /* examine chain first, as this could discover the real chain layout */
- if (jtag_examine_chain() != ERROR_OK)
- {
- ERROR("trying to validate configured JTAG chain anyway...");
- }
-
- while (jtag_validate_chain() != ERROR_OK)
- {
- validate_tries++;
- if (validate_tries > 5)
- {
- ERROR("Could not validate JTAG chain, exit");
- jtag = NULL;
- return ERROR_JTAG_INVALID_INTERFACE;
- }
- usleep(10000);
- }
-
- return ERROR_OK;
-}
-
-int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- int i;
-
- /* check whether the interface is already configured */
- if (jtag_interface)
- {
- WARNING("Interface already configured, ignoring");
- return ERROR_OK;
- }
-
- /* interface name is a mandatory argument */
- if (argc < 1 || args[0][0] == '\0')
- {
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- for (i=0; jtag_interfaces[i]; i++)
- {
- if (strcmp(args[0], jtag_interfaces[i]->name) == 0)
- {
- if (jtag_interfaces[i]->register_commands(cmd_ctx) != ERROR_OK)
- exit(-1);
-
- jtag_interface = jtag_interfaces[i];
- return ERROR_OK;
- }
- }
-
- /* no valid interface was found (i.e. the configuration option,
- * didn't match one of the compiled-in interfaces
- */
- ERROR("No valid jtag interface found (%s)", args[0]);
- ERROR("compiled-in jtag interfaces:");
- for (i = 0; jtag_interfaces[i]; i++)
- {
- ERROR("%i: %s", i, jtag_interfaces[i]->name);
- }
-
- return ERROR_JTAG_INVALID_INTERFACE;
-}
-
-int handle_jtag_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- jtag_device_t **last_device_p = &jtag_devices;
-
- if (*last_device_p)
- {
- while ((*last_device_p)->next)
- last_device_p = &((*last_device_p)->next);
- last_device_p = &((*last_device_p)->next);
- }
-
- if (argc < 3)
- return ERROR_OK;
-
- *last_device_p = malloc(sizeof(jtag_device_t));
- (*last_device_p)->ir_length = strtoul(args[0], NULL, 0);
-
- (*last_device_p)->expected = malloc((*last_device_p)->ir_length);
- buf_set_u32((*last_device_p)->expected, 0, (*last_device_p)->ir_length, strtoul(args[1], NULL, 0));
- (*last_device_p)->expected_mask = malloc((*last_device_p)->ir_length);
- buf_set_u32((*last_device_p)->expected_mask, 0, (*last_device_p)->ir_length, strtoul(args[2], NULL, 0));
-
- (*last_device_p)->cur_instr = malloc((*last_device_p)->ir_length);
- (*last_device_p)->bypass = 1;
- buf_set_ones((*last_device_p)->cur_instr, (*last_device_p)->ir_length);
-
- (*last_device_p)->next = NULL;
-
- jtag_register_event_callback(jtag_reset_callback, (*last_device_p));
-
- jtag_num_devices++;
-
- return ERROR_OK;
-}
-
-int handle_scan_chain_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- jtag_device_t *device = jtag_devices;
- int device_count = 0;
-
- while (device)
- {
- u32 expected, expected_mask, cur_instr;
- expected = buf_get_u32(device->expected, 0, device->ir_length);
- expected_mask = buf_get_u32(device->expected_mask, 0, device->ir_length);
- cur_instr = buf_get_u32(device->cur_instr, 0, device->ir_length);
- command_print(cmd_ctx, "%i: idcode: 0x%8.8x ir length %i, ir capture 0x%x, ir mask 0x%x, current instruction 0x%x", device_count, device->idcode, device->ir_length, expected, expected_mask, cur_instr);
- device = device->next;
- device_count++;
- }
-
- return ERROR_OK;
-}
-
-int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc >= 1)
- {
- if (strcmp(args[0], "none") == 0)
- jtag_reset_config = RESET_NONE;
- else if (strcmp(args[0], "trst_only") == 0)
- jtag_reset_config = RESET_HAS_TRST;
- else if (strcmp(args[0], "srst_only") == 0)
- jtag_reset_config = RESET_HAS_SRST;
- else if (strcmp(args[0], "trst_and_srst") == 0)
- jtag_reset_config = RESET_TRST_AND_SRST;
- else
- {
- ERROR("invalid reset_config argument, defaulting to none");
- jtag_reset_config = RESET_NONE;
- return ERROR_INVALID_ARGUMENTS;
- }
- }
-
- if (argc >= 2)
- {
- if (strcmp(args[1], "srst_pulls_trst") == 0)
- jtag_reset_config |= RESET_SRST_PULLS_TRST;
- else if (strcmp(args[1], "trst_pulls_srst") == 0)
- jtag_reset_config |= RESET_TRST_PULLS_SRST;
- else if (strcmp(args[1], "combined") == 0)
- jtag_reset_config |= RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST;
- else if (strcmp(args[1], "separate") == 0)
- jtag_reset_config &= ~(RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST);
- else
- {
- ERROR("invalid reset_config argument, defaulting to none");
- jtag_reset_config = RESET_NONE;
- return ERROR_INVALID_ARGUMENTS;
- }
- }
-
- if (argc >= 3)
- {
- if (strcmp(args[2], "trst_open_drain") == 0)
- jtag_reset_config |= RESET_TRST_OPEN_DRAIN;
- else if (strcmp(args[2], "trst_push_pull") == 0)
- jtag_reset_config &= ~RESET_TRST_OPEN_DRAIN;
- else
- {
- ERROR("invalid reset_config argument, defaulting to none");
- jtag_reset_config = RESET_NONE;
- return ERROR_INVALID_ARGUMENTS;
- }
- }
-
- if (argc >= 4)
- {
- if (strcmp(args[3], "srst_push_pull") == 0)
- jtag_reset_config |= RESET_SRST_PUSH_PULL;
- else if (strcmp(args[3], "srst_open_drain") == 0)
- jtag_reset_config &= ~RESET_SRST_PUSH_PULL;
- else
- {
- ERROR("invalid reset_config argument, defaulting to none");
- jtag_reset_config = RESET_NONE;
- return ERROR_INVALID_ARGUMENTS;
- }
- }
-
- return ERROR_OK;
-}
-
-int handle_jtag_nsrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc < 1)
- {
- ERROR("jtag_nsrst_delay <ms> command takes one required argument");
- exit(-1);
- }
- else
- {
- jtag_nsrst_delay = strtoul(args[0], NULL, 0);
- }
-
- return ERROR_OK;
-}
-
-int handle_jtag_ntrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc < 1)
- {
- ERROR("jtag_ntrst_delay <ms> command takes one required argument");
- exit(-1);
- }
- else
- {
- jtag_ntrst_delay = strtoul(args[0], NULL, 0);
- }
-
- return ERROR_OK;
-}
-
-int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 0)
- command_print(cmd_ctx, "jtag_speed: %i", jtag_speed);
-
- if (argc > 0)
- {
- /* this command can be called during CONFIG,
- * in which case jtag isn't initialized */
- if (jtag)
- jtag->speed(strtoul(args[0], NULL, 0));
- else
- jtag_speed = strtoul(args[0], NULL, 0);
- }
-
- return ERROR_OK;
-}
-
-int handle_endstate_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- enum tap_state state;
-
- if (argc < 1)
- {
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
- else
- {
- for (state = 0; state < 16; state++)
- {
- if (strcmp(args[0], tap_state_strings[state]) == 0)
- {
- jtag_add_end_state(state);
- jtag_execute_queue();
- }
- }
- }
- command_print(cmd_ctx, "current endstate: %s", tap_state_strings[end_state]);
-
- return ERROR_OK;
-}
-
-int handle_jtag_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- int trst = -1;
- int srst = -1;
- int retval;
-
- if (argc < 2)
- {
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- }
-
- if (args[0][0] == '1')
- trst = 1;
- else if (args[0][0] == '0')
- trst = 0;
- else
- {
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- if (args[1][0] == '1')
- srst = 1;
- else if (args[1][0] == '0')
- srst = 0;
- else
- {
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- if (!jtag && jtag_interface_init(cmd_ctx) != ERROR_OK)
- return ERROR_JTAG_INIT_FAILED;
-
- if ((retval = jtag_add_reset(trst, srst)) != ERROR_OK)
- {
- switch (retval)
- {
- case ERROR_JTAG_RESET_WOULD_ASSERT_TRST:
- command_print(cmd_ctx, "requested reset would assert trst\nif this is acceptable, use jtag_reset 1 %c", args[1][0]);
- break;
- case ERROR_JTAG_RESET_CANT_SRST:
- command_print(cmd_ctx, "can't assert srst because the current reset_config doesn't support it");
- break;
- default:
- command_print(cmd_ctx, "unknown error");
- }
- }
- jtag_execute_queue();
-
- return ERROR_OK;
-}
-
-int handle_runtest_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc < 1)
- {
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- jtag_add_runtest(strtol(args[0], NULL, 0), -1);
- jtag_execute_queue();
-
- return ERROR_OK;
-
-}
-
-int handle_statemove_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- enum tap_state state;
-
- state = -1;
- if (argc == 1)
- {
- for (state = 0; state < 16; state++)
- {
- if (strcmp(args[0], tap_state_strings[state]) == 0)
- {
- break;
- }
- }
- }
-
- jtag_add_statemove(state);
- jtag_execute_queue();
-
- return ERROR_OK;
-
-}
-
-int handle_irscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- int i;
- scan_field_t *fields;
-
- if ((argc < 2) || (argc % 2))
- {
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- fields = malloc(sizeof(scan_field_t) * argc / 2);
-
- for (i = 0; i < argc / 2; i++)
- {
- int device = strtoul(args[i*2], NULL, 0);
- int field_size = jtag_get_device(device)->ir_length;
- fields[i].device = device;
- fields[i].out_value = malloc(CEIL(field_size, 8));
- buf_set_u32(fields[i].out_value, 0, field_size, strtoul(args[i*2+1], NULL, 0));
- fields[i].out_mask = NULL;
- fields[i].in_value = NULL;
- fields[i].in_check_mask = NULL;
- fields[i].in_handler = NULL;
- fields[i].in_handler_priv = NULL;
- }
-
- jtag_add_ir_scan(argc / 2, fields, -1);
- jtag_execute_queue();
-
- for (i = 0; i < argc / 2; i++)
- free(fields[i].out_value);
-
- free (fields);
-
- return ERROR_OK;
-}
-
-int handle_drscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- scan_field_t *fields;
- int num_fields = 0;
- int field_count = 0;
- var_t *var;
- int i, j;
-
- if ((argc < 2) || (argc % 2))
- {
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- for (i = 0; i < argc; i+=2)
- {
- var = get_var_by_namenum(args[i+1]);
- if (var)
- {
- num_fields += var->num_fields;
- }
- else
- {
- command_print(cmd_ctx, "variable %s doesn't exist", args[i+1]);
- return ERROR_OK;
- }
- }
-
- fields = malloc(sizeof(scan_field_t) * num_fields);
-
- for (i = 0; i < argc; i+=2)
- {
- var = get_var_by_namenum(args[i+1]);
-
- for (j = 0; j < var->num_fields; j++)
- {
- fields[field_count].device = strtol(args[i], NULL, 0);
- fields[field_count].num_bits = var->fields[j].num_bits;
- fields[field_count].out_value = malloc(CEIL(var->fields[j].num_bits, 8));
- buf_set_u32(fields[field_count].out_value, 0, var->fields[j].num_bits, var->fields[j].value);
- fields[field_count].out_mask = NULL;
- fields[field_count].in_value = fields[field_count].out_value;
- fields[field_count].in_check_mask = NULL;
- fields[field_count].in_check_value = NULL;
- fields[field_count].in_handler = field_le_to_host;
- fields[field_count++].in_handler_priv = &(var->fields[j]);
- }
- }
-
- jtag_add_dr_scan(num_fields, fields, -1);
- jtag_execute_queue();
-
- for (i = 0; i < argc / 2; i++)
- free(fields[i].out_value);
-
- free(fields);
-
- return ERROR_OK;
-}
-
-int handle_verify_ircapture_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 1)
- {
- if (strcmp(args[0], "enable") == 0)
- {
- jtag_verify_capture_ir = 1;
- }
- else if (strcmp(args[0], "disable") == 0)
- {
- jtag_verify_capture_ir = 0;
- } else
- {
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
- } else if (argc != 0)
- {
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- command_print(cmd_ctx, "verify Capture-IR is %s", (jtag_verify_capture_ir) ? "enabled": "disabled");
-
- return ERROR_OK;
-}
+/*************************************************************************** + * 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 "jtag.h" + +#include "command.h" +#include "log.h" +#include "interpreter.h" + +#include "stdlib.h" +#include "string.h" +#include <unistd.h> + +char* tap_state_strings[16] = +{ + "tlr", + "sds", "cd", "sd", "e1d", "pd", "e2d", "ud", + "rti", + "sis", "ci", "si", "e1i", "pi", "e2i", "ui" +}; + +typedef struct cmd_queue_page_s +{ + void *address; + size_t used; + struct cmd_queue_page_s *next; +} cmd_queue_page_t; + +#define CMD_QUEUE_PAGE_SIZE (1024 * 1024) +static cmd_queue_page_t *cmd_queue_pages = NULL; + +/* tap_move[i][j]: tap movement command to go from state i to state j + * 0: Test-Logic-Reset + * 1: Run-Test/Idle + * 2: Shift-DR + * 3: Pause-DR + * 4: Shift-IR + * 5: Pause-IR + * + * SD->SD and SI->SI have to be caught in interface specific code + */ +u8 tap_move[6][6] = +{ +/* TLR RTI SD PD SI PI */ + {0x7f, 0x00, 0x17, 0x0a, 0x1b, 0x16}, /* TLR */ + {0x7f, 0x00, 0x25, 0x05, 0x2b, 0x0b}, /* RTI */ + {0x7f, 0x31, 0x00, 0x01, 0x0f, 0x2f}, /* SD */ + {0x7f, 0x30, 0x20, 0x17, 0x1e, 0x2f}, /* PD */ + {0x7f, 0x31, 0x07, 0x17, 0x00, 0x01}, /* SI */ + {0x7f, 0x30, 0x1c, 0x17, 0x20, 0x2f} /* PI */ +}; + +int tap_move_map[16] = { + 0, -1, -1, 2, -1, 3, -1, -1, + 1, -1, -1, 4, -1, 5, -1, -1 +}; + +tap_transition_t tap_transitions[16] = +{ + {TAP_TLR, TAP_RTI}, /* TLR */ + {TAP_SIS, TAP_CD}, /* SDS */ + {TAP_E1D, TAP_SD}, /* CD */ + {TAP_E1D, TAP_SD}, /* SD */ + {TAP_UD, TAP_PD}, /* E1D */ + {TAP_E2D, TAP_PD}, /* PD */ + {TAP_UD, TAP_SD}, /* E2D */ + {TAP_SDS, TAP_RTI}, /* UD */ + {TAP_SDS, TAP_RTI}, /* RTI */ + {TAP_TLR, TAP_CI}, /* SIS */ + {TAP_E1I, TAP_SI}, /* CI */ + {TAP_E1I, TAP_SI}, /* SI */ + {TAP_UI, TAP_PI}, /* E1I */ + {TAP_E2I, TAP_PI}, /* PI */ + {TAP_UI, TAP_SI}, /* E2I */ + {TAP_SDS, TAP_RTI} /* UI */ +}; + +char* jtag_event_strings[] = +{ + "SRST asserted", + "TRST asserted", + "SRST released", + "TRST released" +}; + +enum tap_state end_state = TAP_TLR; +enum tap_state cur_state = TAP_TLR; +int jtag_trst = 0; +int jtag_srst = 0; + +jtag_command_t *jtag_command_queue = NULL; +jtag_command_t **last_comand_pointer = &jtag_command_queue; +jtag_device_t *jtag_devices = NULL; +int jtag_num_devices = 0; +int jtag_ir_scan_size = 0; +enum reset_types jtag_reset_config = RESET_NONE; +enum tap_state cmd_queue_end_state = TAP_TLR; +enum tap_state cmd_queue_cur_state = TAP_TLR; + +int jtag_verify_capture_ir = 1; + +/* how long the OpenOCD should wait before attempting JTAG communication after reset lines deasserted (in ms) */ +int jtag_nsrst_delay = 0; /* default to no nSRST delay */ +int jtag_ntrst_delay = 0; /* default to no nTRST delay */ + +/* maximum number of JTAG devices expected in the chain + */ +#define JTAG_MAX_CHAIN_SIZE 20 + +/* callbacks to inform high-level handlers about JTAG state changes */ +jtag_event_callback_t *jtag_event_callbacks; + +/* jtag interfaces (parport, FTDI-USB, TI-USB, ...) + */ +#if BUILD_PARPORT == 1 + extern jtag_interface_t parport_interface; +#endif + +#if BUILD_FT2232_FTD2XX == 1 + extern jtag_interface_t ft2232_interface; +#endif + +#if BUILD_FT2232_LIBFTDI == 1 + extern jtag_interface_t ft2232_interface; +#endif + +#if BUILD_AMTJTAGACCEL == 1 + extern jtag_interface_t amt_jtagaccel_interface; +#endif + +#if BUILD_EP93XX == 1 + extern jtag_interface_t ep93xx_interface; +#endif + +#if BUILD_AT91RM9200 == 1 + extern jtag_interface_t at91rm9200_interface; +#endif + +#if BUILD_GW16012 == 1 + extern jtag_interface_t gw16012_interface; +#endif + +#if BUILD_PRESTO_LIBFTDI == 1 || BUILD_PRESTO_FTD2XX == 1 + extern jtag_interface_t presto_interface; +#endif + +#if BUILD_USBPROG == 1 + extern jtag_interface_t usbprog_interface; +#endif + +jtag_interface_t *jtag_interfaces[] = { +#if BUILD_PARPORT == 1 + &parport_interface, +#endif +#if BUILD_FT2232_FTD2XX == 1 + &ft2232_interface, +#endif +#if BUILD_FT2232_LIBFTDI == 1 + &ft2232_interface, +#endif +#if BUILD_AMTJTAGACCEL == 1 + &amt_jtagaccel_interface, +#endif +#if BUILD_EP93XX == 1 + &ep93xx_interface, +#endif +#if BUILD_AT91RM9200 == 1 + &at91rm9200_interface, +#endif +#if BUILD_GW16012 == 1 + &gw16012_interface, +#endif +#if BUILD_PRESTO_LIBFTDI == 1 || BUILD_PRESTO_FTD2XX == 1 + &presto_interface, +#endif +#if BUILD_USBPROG == 1 + &usbprog_interface, +#endif + NULL, +}; + +jtag_interface_t *jtag = NULL; + +/* configuration */ +jtag_interface_t *jtag_interface = NULL; +int jtag_speed = 0; + + +/* forward declarations */ +int jtag_add_statemove(enum tap_state endstate); +int jtag_add_pathmove(int num_states, enum tap_state *path); +int jtag_add_runtest(int num_cycles, enum tap_state endstate); +int jtag_add_reset(int trst, int srst); +int jtag_add_end_state(enum tap_state endstate); +int jtag_add_sleep(u32 us); +int jtag_execute_queue(void); +int jtag_cancel_queue(void); + +/* jtag commands */ +int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_jtag_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_jtag_nsrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_jtag_ntrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int handle_scan_chain_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int handle_endstate_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_jtag_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_runtest_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_statemove_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_irscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_drscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int handle_verify_ircapture_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int jtag_register_event_callback(int (*callback)(enum jtag_event event, void *priv), void *priv) +{ + jtag_event_callback_t **callbacks_p = &jtag_event_callbacks; + + if (callback == NULL) + { + return ERROR_INVALID_ARGUMENTS; + } + + if (*callbacks_p) + { + while ((*callbacks_p)->next) + callbacks_p = &((*callbacks_p)->next); + callbacks_p = &((*callbacks_p)->next); + } + + (*callbacks_p) = malloc(sizeof(jtag_event_callback_t)); + (*callbacks_p)->callback = callback; + (*callbacks_p)->priv = priv; + (*callbacks_p)->next = NULL; + + return ERROR_OK; +} + +int jtag_unregister_event_callback(int (*callback)(enum jtag_event event, void *priv)) +{ + jtag_event_callback_t **callbacks_p = &jtag_event_callbacks; + + if (callback == NULL) + { + return ERROR_INVALID_ARGUMENTS; + } + + while (*callbacks_p) + { + jtag_event_callback_t **next = &((*callbacks_p)->next); + if ((*callbacks_p)->callback == callback) + { + free(*callbacks_p); + *callbacks_p = *next; + } + callbacks_p = next; + } + + return ERROR_OK; +} + +int jtag_call_event_callbacks(enum jtag_event event) +{ + jtag_event_callback_t *callback = jtag_event_callbacks; + + DEBUG("jtag event: %s", jtag_event_strings[event]); + + while (callback) + { + callback->callback(event, callback->priv); + callback = callback->next; + } + + return ERROR_OK; +} + +/* returns a pointer to the pointer of the last command in queue + * this may be a pointer to the root pointer (jtag_command_queue) + * or to the next member of the last but one command + */ +jtag_command_t** jtag_get_last_command_p(void) +{ +/* jtag_command_t *cmd = jtag_command_queue; + + if (cmd) + while (cmd->next) + cmd = cmd->next; + else + return &jtag_command_queue; + + return &cmd->next;*/ + + return last_comand_pointer; +} + +/* returns a pointer to the n-th device in the scan chain */ +jtag_device_t* jtag_get_device(int num) +{ + jtag_device_t *device = jtag_devices; + int i = 0; + + while (device) + { + if (num == i) + return device; + device = device->next; + i++; + } + + ERROR("jtag device number %d not defined", num); + exit(-1); +} + +void* cmd_queue_alloc(size_t size) +{ + cmd_queue_page_t **p_page = &cmd_queue_pages; + int offset; + + if (*p_page) + { + while ((*p_page)->next) + p_page = &((*p_page)->next); + if (CMD_QUEUE_PAGE_SIZE - (*p_page)->used < size) + p_page = &((*p_page)->next); + } + + if (!*p_page) + { + *p_page = malloc(sizeof(cmd_queue_page_t)); + (*p_page)->used = 0; + (*p_page)->address = malloc(CMD_QUEUE_PAGE_SIZE); + (*p_page)->next = NULL; + } + + offset = (*p_page)->used; + (*p_page)->used += size; + + u8 *t=(u8 *)((*p_page)->address); + return t + offset; +} + +void cmd_queue_free() +{ + cmd_queue_page_t *page = cmd_queue_pages; + + while (page) + { + cmd_queue_page_t *last = page; + free(page->address); + page = page->next; + free(last); + } + + cmd_queue_pages = NULL; +} + +int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state) +{ + jtag_command_t **last_cmd; + jtag_device_t *device; + int i, j; + int scan_size = 0; + + if (jtag_trst == 1) + { + WARNING("JTAG command queued, while TRST is low (TAP in reset)"); + return ERROR_JTAG_TRST_ASSERTED; + } + + last_cmd = jtag_get_last_command_p(); + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + (*last_cmd)->next = NULL; + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->type = JTAG_SCAN; + + /* allocate memory for ir scan command */ + (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t)); + (*last_cmd)->cmd.scan->ir_scan = 1; + (*last_cmd)->cmd.scan->num_fields = jtag_num_devices; /* one field per device */ + (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(jtag_num_devices * sizeof(scan_field_t)); + (*last_cmd)->cmd.scan->end_state = state; + + if (state != -1) + cmd_queue_end_state = state; + + if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_RELEASED); + + if (cmd_queue_end_state == TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + + cmd_queue_cur_state = cmd_queue_end_state; + + for (i = 0; i < jtag_num_devices; i++) + { + int found = 0; + device = jtag_get_device(i); + scan_size = device->ir_length; + (*last_cmd)->cmd.scan->fields[i].device = i; + (*last_cmd)->cmd.scan->fields[i].num_bits = scan_size; + (*last_cmd)->cmd.scan->fields[i].in_value = NULL; + (*last_cmd)->cmd.scan->fields[i].in_handler = NULL; /* disable verification by default */ + + /* search the list */ + for (j = 0; j < num_fields; j++) + { + if (i == fields[j].device) + { + found = 1; + (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(fields[j].out_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); + (*last_cmd)->cmd.scan->fields[i].out_mask = buf_cpy(fields[j].out_mask, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); + + if (jtag_verify_capture_ir) + { + if (fields[j].in_handler==NULL) + { + jtag_set_check_value((*last_cmd)->cmd.scan->fields+i, device->expected, device->expected_mask, NULL); + } else + { + (*last_cmd)->cmd.scan->fields[i].in_handler = fields[j].in_handler; + (*last_cmd)->cmd.scan->fields[i].in_handler_priv = fields[j].in_handler_priv; + (*last_cmd)->cmd.scan->fields[i].in_check_value = device->expected; + (*last_cmd)->cmd.scan->fields[i].in_check_mask = device->expected_mask; + } + } + + device->bypass = 0; + break; + } + } + + if (!found) + { + /* if a device isn't listed, set it to BYPASS */ + (*last_cmd)->cmd.scan->fields[i].out_value = buf_set_ones(cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); + (*last_cmd)->cmd.scan->fields[i].out_mask = NULL; + device->bypass = 1; + + } + + /* update device information */ + buf_cpy((*last_cmd)->cmd.scan->fields[i].out_value, jtag_get_device(i)->cur_instr, scan_size); + } + + return ERROR_OK; +} + +int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state) +{ + jtag_command_t **last_cmd; + int i; + + if (jtag_trst == 1) + { + WARNING("JTAG command queued, while TRST is low (TAP in reset)"); + return ERROR_JTAG_TRST_ASSERTED; + } + + last_cmd = jtag_get_last_command_p(); + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + (*last_cmd)->next = NULL; + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->type = JTAG_SCAN; + + /* allocate memory for ir scan command */ + (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t)); + (*last_cmd)->cmd.scan->ir_scan = 1; + (*last_cmd)->cmd.scan->num_fields = num_fields; + (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(num_fields * sizeof(scan_field_t)); + (*last_cmd)->cmd.scan->end_state = state; + + if (state != -1) + cmd_queue_end_state = state; + + if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_RELEASED); + + if (cmd_queue_end_state == TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + + cmd_queue_cur_state = cmd_queue_end_state; + + for (i = 0; i < num_fields; i++) + { + int num_bits = fields[i].num_bits; + int num_bytes = CEIL(fields[i].num_bits, 8); + (*last_cmd)->cmd.scan->fields[i].device = fields[i].device; + (*last_cmd)->cmd.scan->fields[i].num_bits = num_bits; + (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(fields[i].out_value, cmd_queue_alloc(num_bytes), num_bits); + (*last_cmd)->cmd.scan->fields[i].out_mask = buf_cpy(fields[i].out_mask, cmd_queue_alloc(num_bytes), num_bits); + (*last_cmd)->cmd.scan->fields[i].in_value = fields[i].in_value; + (*last_cmd)->cmd.scan->fields[i].in_check_value = fields[i].in_check_value; + (*last_cmd)->cmd.scan->fields[i].in_check_mask = fields[i].in_check_mask; + (*last_cmd)->cmd.scan->fields[i].in_handler = NULL; + (*last_cmd)->cmd.scan->fields[i].in_handler_priv = NULL; + } + return ERROR_OK; +} + +int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state) +{ + int i, j; + int bypass_devices = 0; + int field_count = 0; + jtag_command_t **last_cmd = jtag_get_last_command_p(); + jtag_device_t *device = jtag_devices; + int scan_size; + + if (jtag_trst == 1) + { + WARNING("JTAG command queued, while TRST is low (TAP in reset)"); + return ERROR_JTAG_TRST_ASSERTED; + } + + /* count devices in bypass */ + while (device) + { + if (device->bypass) + bypass_devices++; + device = device->next; + } + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->next = NULL; + (*last_cmd)->type = JTAG_SCAN; + + /* allocate memory for dr scan command */ + (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t)); + (*last_cmd)->cmd.scan->ir_scan = 0; + (*last_cmd)->cmd.scan->num_fields = num_fields + bypass_devices; + (*last_cmd)->cmd.scan->fields = cmd_queue_alloc((num_fields + bypass_devices) * sizeof(scan_field_t)); + (*last_cmd)->cmd.scan->end_state = state; + + if (state != -1) + cmd_queue_end_state = state; + + if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_RELEASED); + + if (cmd_queue_end_state == TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + + cmd_queue_cur_state = cmd_queue_end_state; + + for (i = 0; i < jtag_num_devices; i++) + { + int found = 0; + (*last_cmd)->cmd.scan->fields[field_count].device = i; + + for (j = 0; j < num_fields; j++) + { + if (i == fields[j].device) + { + found = 1; + scan_size = fields[j].num_bits; + (*last_cmd)->cmd.scan->fields[field_count].num_bits = scan_size; + (*last_cmd)->cmd.scan->fields[field_count].out_value = buf_cpy(fields[j].out_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); + (*last_cmd)->cmd.scan->fields[field_count].out_mask = buf_cpy(fields[j].out_mask, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); + (*last_cmd)->cmd.scan->fields[field_count].in_value = fields[j].in_value; + (*last_cmd)->cmd.scan->fields[field_count].in_check_value = fields[j].in_check_value; + (*last_cmd)->cmd.scan->fields[field_count].in_check_mask = fields[j].in_check_mask; + (*last_cmd)->cmd.scan->fields[field_count].in_handler = fields[j].in_handler; + (*last_cmd)->cmd.scan->fields[field_count++].in_handler_priv = fields[j].in_handler_priv; + } + } + if (!found) + { + /* if a device isn't listed, the BYPASS register should be selected */ + if (!jtag_get_device(i)->bypass) + { + ERROR("BUG: no scan data for a device not in BYPASS"); + exit(-1); + } + + /* program the scan field to 1 bit length, and ignore it's value */ + (*last_cmd)->cmd.scan->fields[field_count].num_bits = 1; + (*last_cmd)->cmd.scan->fields[field_count].out_value = NULL; + (*last_cmd)->cmd.scan->fields[field_count].out_mask = NULL; + (*last_cmd)->cmd.scan->fields[field_count].in_value = NULL; + (*last_cmd)->cmd.scan->fields[field_count].in_check_value = NULL; + (*last_cmd)->cmd.scan->fields[field_count].in_check_mask = NULL; + (*last_cmd)->cmd.scan->fields[field_count].in_handler = NULL; + (*last_cmd)->cmd.scan->fields[field_count++].in_handler_priv = NULL; + } + else + { + /* if a device is listed, the BYPASS register must not be selected */ + if (jtag_get_device(i)->bypass) + { + WARNING("scan data for a device in BYPASS"); + } + } + } + return ERROR_OK; +} + + +int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state) +{ + int i; + jtag_command_t **last_cmd = jtag_get_last_command_p(); + + if (jtag_trst == 1) + { + WARNING("JTAG command queued, while TRST is low (TAP in reset)"); + return ERROR_JTAG_TRST_ASSERTED; + } + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->next = NULL; + (*last_cmd)->type = JTAG_SCAN; + + /* allocate memory for scan command */ + (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t)); + (*last_cmd)->cmd.scan->ir_scan = 0; + (*last_cmd)->cmd.scan->num_fields = num_fields; + (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(num_fields * sizeof(scan_field_t)); + (*last_cmd)->cmd.scan->end_state = state; + + if (state != -1) + cmd_queue_end_state = state; + + if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_RELEASED); + + if (cmd_queue_end_state == TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + + cmd_queue_cur_state = cmd_queue_end_state; + + for (i = 0; i < num_fields; i++) + { + int num_bits = fields[i].num_bits; + int num_bytes = CEIL(fields[i].num_bits, 8); + (*last_cmd)->cmd.scan->fields[i].device = fields[i].device; + (*last_cmd)->cmd.scan->fields[i].num_bits = num_bits; + (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(fields[i].out_value, cmd_queue_alloc(num_bytes), num_bits); + (*last_cmd)->cmd.scan->fields[i].out_mask = buf_cpy(fields[i].out_mask, cmd_queue_alloc(num_bytes), num_bits); + (*last_cmd)->cmd.scan->fields[i].in_value = fields[i].in_value; + (*last_cmd)->cmd.scan->fields[i].in_check_value = fields[i].in_check_value; + (*last_cmd)->cmd.scan->fields[i].in_check_mask = fields[i].in_check_mask; + (*last_cmd)->cmd.scan->fields[i].in_handler = fields[i].in_handler; + (*last_cmd)->cmd.scan->fields[i].in_handler_priv = fields[i].in_handler_priv; + } + + return ERROR_OK; +} +int jtag_add_statemove(enum tap_state state) +{ + jtag_command_t **last_cmd = jtag_get_last_command_p(); + + if (jtag_trst == 1) + { + WARNING("JTAG command queued, while TRST is low (TAP in reset)"); + return ERROR_JTAG_TRST_ASSERTED; + } + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->next = NULL; + (*last_cmd)->type = JTAG_STATEMOVE; + + (*last_cmd)->cmd.statemove = cmd_queue_alloc(sizeof(statemove_command_t)); + (*last_cmd)->cmd.statemove->end_state = state; + + if (state != -1) + cmd_queue_end_state = state; + + if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_RELEASED); + + if (cmd_queue_end_state == TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + + cmd_queue_cur_state = cmd_queue_end_state; + + return ERROR_OK; +} + +int jtag_add_pathmove(int num_states, enum tap_state *path) +{ + jtag_command_t **last_cmd = jtag_get_last_command_p(); + int i; + + if (jtag_trst == 1) + { + WARNING("JTAG command queued, while TRST is low (TAP in reset)"); + return ERROR_JTAG_TRST_ASSERTED; + } + + /* the last state has to be a stable state */ + if (tap_move_map[path[num_states - 1]] == -1) + { + ERROR("TAP path doesn't finish in a stable state"); + return ERROR_JTAG_NOT_IMPLEMENTED; + } + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->next = NULL; + (*last_cmd)->type = JTAG_PATHMOVE; + + (*last_cmd)->cmd.pathmove = cmd_queue_alloc(sizeof(pathmove_command_t)); + (*last_cmd)->cmd.pathmove->num_states = num_states; + (*last_cmd)->cmd.pathmove->path = cmd_queue_alloc(sizeof(enum tap_state) * num_states); + + for (i = 0; i < num_states; i++) + (*last_cmd)->cmd.pathmove->path[i] = path[i]; + + if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_RELEASED); + + if (cmd_queue_end_state == TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + + cmd_queue_cur_state = path[num_states - 1]; + + return ERROR_OK; +} + +int jtag_add_runtest(int num_cycles, enum tap_state state) +{ + jtag_command_t **last_cmd = jtag_get_last_command_p(); + + if (jtag_trst == 1) + { + WARNING("JTAG command queued, while TRST is low (TAP in reset)"); + return ERROR_JTAG_TRST_ASSERTED; + } + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + (*last_cmd)->next = NULL; + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->type = JTAG_RUNTEST; + + (*last_cmd)->cmd.runtest = cmd_queue_alloc(sizeof(runtest_command_t)); + (*last_cmd)->cmd.runtest->num_cycles = num_cycles; + (*last_cmd)->cmd.runtest->end_state = state; + + if (state != -1) + cmd_queue_end_state = state; + + if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_RELEASED); + + if (cmd_queue_end_state == TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + + cmd_queue_cur_state = cmd_queue_end_state; + + return ERROR_OK; +} + +int jtag_add_reset(int req_trst, int req_srst) +{ + int trst_with_tms = 0; + + jtag_command_t **last_cmd = jtag_get_last_command_p(); + + if (req_trst == -1) + req_trst = jtag_trst; + + if (req_srst == -1) + req_srst = jtag_srst; + + /* Make sure that jtag_reset_config allows the requested reset */ + /* if SRST pulls TRST, we can't fulfill srst == 1 with trst == 0 */ + if (((jtag_reset_config & RESET_SRST_PULLS_TRST) && (req_srst == 1)) && (req_trst == 0)) + return ERROR_JTAG_RESET_WOULD_ASSERT_TRST; + + /* if TRST pulls SRST, we reset with TAP T-L-R */ + if (((jtag_reset_config & RESET_TRST_PULLS_SRST) && (req_trst == 1)) && (req_srst == 0)) + { + req_trst = 0; + trst_with_tms = 1; + } + + if (req_srst && !(jtag_reset_config & RESET_HAS_SRST)) + { + ERROR("requested nSRST assertion, but the current configuration doesn't support this"); + return ERROR_JTAG_RESET_CANT_SRST; + } + + if (req_trst && !(jtag_reset_config & RESET_HAS_TRST)) + { + req_trst = 0; + trst_with_tms = 1; + } + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + (*last_cmd)->next = NULL; + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->type = JTAG_RESET; + + (*last_cmd)->cmd.reset = cmd_queue_alloc(sizeof(reset_command_t)); + (*last_cmd)->cmd.reset->trst = req_trst; + (*last_cmd)->cmd.reset->srst = req_srst; + + jtag_trst = req_trst; + jtag_srst = req_srst; + + if (jtag_srst) + { + jtag_call_event_callbacks(JTAG_SRST_ASSERTED); + } + else + { + jtag_call_event_callbacks(JTAG_SRST_RELEASED); + if (jtag_nsrst_delay) + jtag_add_sleep(jtag_nsrst_delay * 1000); + } + + if (trst_with_tms) + { + last_cmd = &((*last_cmd)->next); + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + (*last_cmd)->next = NULL; + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->type = JTAG_STATEMOVE; + + (*last_cmd)->cmd.statemove = cmd_queue_alloc(sizeof(statemove_command_t)); + (*last_cmd)->cmd.statemove->end_state = TAP_TLR; + + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + cmd_queue_cur_state = TAP_TLR; + cmd_queue_end_state = TAP_TLR; + + return ERROR_OK; + } + else + { + if (jtag_trst) + { + /* we just asserted nTRST, so we're now in Test-Logic-Reset, + * and inform possible listeners about this + */ + cmd_queue_cur_state = TAP_TLR; + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + } + else + { + /* the nTRST line got deasserted, so we're still in Test-Logic-Reset, + * but we might want to add a delay to give the TAP time to settle + */ + if (jtag_ntrst_delay) + jtag_add_sleep(jtag_ntrst_delay * 1000); + } + } + + return ERROR_OK; +} + +int jtag_add_end_state(enum tap_state state) +{ + jtag_command_t **last_cmd = jtag_get_last_command_p(); + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + (*last_cmd)->next = NULL; + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->type = JTAG_END_STATE; + + (*last_cmd)->cmd.end_state = cmd_queue_alloc(sizeof(end_state_command_t)); + (*last_cmd)->cmd.end_state->end_state = state; + + if (state != -1) + cmd_queue_end_state = state; + + return ERROR_OK; +} + +int jtag_add_sleep(u32 us) +{ + jtag_command_t **last_cmd = jtag_get_last_command_p(); + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + (*last_cmd)->next = NULL; + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->type = JTAG_SLEEP; + + (*last_cmd)->cmd.sleep = cmd_queue_alloc(sizeof(sleep_command_t)); + (*last_cmd)->cmd.sleep->us = us; + + return ERROR_OK; +} + +int jtag_scan_size(scan_command_t *cmd) +{ + int bit_count = 0; + int i; + + /* count bits in scan command */ + for (i = 0; i < cmd->num_fields; i++) + { + bit_count += cmd->fields[i].num_bits; + } + + return bit_count; +} + +int jtag_build_buffer(scan_command_t *cmd, u8 **buffer) +{ + int bit_count = 0; + int i; + + bit_count = jtag_scan_size(cmd); + *buffer = malloc(CEIL(bit_count, 8)); + + bit_count = 0; + + for (i = 0; i < cmd->num_fields; i++) + { + if (cmd->fields[i].out_value) + { +#ifdef _DEBUG_JTAG_IO_ + char* char_buf = buf_to_str(cmd->fields[i].out_value, (cmd->fields[i].num_bits > 64) ? 64 : 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; + } + + return bit_count; + +} + +int jtag_read_buffer(u8 *buffer, scan_command_t *cmd) +{ + int i; + int bit_count = 0; + int retval; + + /* we return ERROR_OK, unless a check fails, or a handler reports a problem */ + retval = ERROR_OK; + + for (i = 0; i < cmd->num_fields; i++) + { + /* if neither in_value nor in_handler + * are specified we don't have to examine this field + */ + if (cmd->fields[i].in_value || cmd->fields[i].in_handler) + { + int num_bits = cmd->fields[i].num_bits; + u8 *captured = buf_set_buf(buffer, bit_count, malloc(CEIL(num_bits, 8)), 0, num_bits); + +#ifdef _DEBUG_JTAG_IO_ + char *char_buf; + + char_buf = buf_to_str(captured, (num_bits > 64) ? 64 : num_bits, 16); + DEBUG("fields[%i].in_value: 0x%s", i, char_buf); + free(char_buf); +#endif + + if (cmd->fields[i].in_value) + { + buf_cpy(captured, cmd->fields[i].in_value, num_bits); + + if (cmd->fields[i].in_handler) + { + if (cmd->fields[i].in_handler(cmd->fields[i].in_value, cmd->fields[i].in_handler_priv, cmd->fields+i) != ERROR_OK) + { + WARNING("in_handler reported a failed check"); + retval = ERROR_JTAG_QUEUE_FAILED; + } + } + } + + /* no in_value specified, but a handler takes care of the scanned data */ + if (cmd->fields[i].in_handler && (!cmd->fields[i].in_value)) + { + if (cmd->fields[i].in_handler(captured, cmd->fields[i].in_handler_priv, cmd->fields+i) != ERROR_OK) + { + /* We're going to call the error:handler later, but if the in_handler + * reported an error we report this failure upstream + */ + WARNING("in_handler reported a failed check"); + retval = ERROR_JTAG_QUEUE_FAILED; + } + } + + free(captured); + } + bit_count += cmd->fields[i].num_bits; + } + + return retval; +} + +int jtag_check_value(u8 *captured, void *priv, scan_field_t *field) +{ + int retval = ERROR_OK; + int num_bits = field->num_bits; + + int compare_failed = 0; + + if (field->in_check_mask) + compare_failed = buf_cmp_mask(captured, field->in_check_value, field->in_check_mask, num_bits); + else + compare_failed = buf_cmp(captured, field->in_check_value, num_bits); + + if (compare_failed) + { + /* An error handler could have caught the failing check + * only report a problem when there wasn't a handler, or if the handler + * acknowledged the error + */ + if (compare_failed) + { + char *captured_char = buf_to_str(captured, (num_bits > 64) ? 64 : num_bits, 16); + char *in_check_value_char = buf_to_str(field->in_check_value, (num_bits > 64) ? 64 : num_bits, 16); + + if (field->in_check_mask) + { + char *in_check_mask_char; + in_check_mask_char = buf_to_str(field->in_check_mask, (num_bits > 64) ? 64 : num_bits, 16); + 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); + free(in_check_mask_char); + } + else + { + WARNING("value captured during scan didn't pass the requested check: captured: 0x%s check_value: 0x%s", captured_char, in_check_value_char); + } + + free(captured_char); + free(in_check_value_char); + + retval = ERROR_JTAG_QUEUE_FAILED; + } + + } + return retval; +} + +/* + set up checking of this field using the in_handler. The values passed in must be valid until + after jtag_execute() has completed. + */ +void jtag_set_check_value(scan_field_t *field, u8 *value, u8 *mask, error_handler_t *in_error_handler) +{ + if (value) + field->in_handler = jtag_check_value; + else + field->in_handler = NULL; /* No check, e.g. embeddedice uses value==NULL to indicate no check */ + field->in_handler_priv = NULL; /* this will be filled in at the invocation site to point to the field duplicate */ + field->in_check_value = value; + field->in_check_mask = mask; +} + +enum scan_type jtag_scan_type(scan_command_t *cmd) +{ + int i; + int type = 0; + + for (i = 0; i < cmd->num_fields; i++) + { + if (cmd->fields[i].in_value || cmd->fields[i].in_handler) + type |= SCAN_IN; + if (cmd->fields[i].out_value) + type |= SCAN_OUT; + } + + return type; +} + +int jtag_execute_queue(void) +{ + int retval; + + retval = jtag->execute_queue(); + + cmd_queue_free(); + + jtag_command_queue = NULL; + last_comand_pointer = &jtag_command_queue; + + return retval; +} + +int jtag_reset_callback(enum jtag_event event, void *priv) +{ + jtag_device_t *device = priv; + + DEBUG("-"); + + if (event == JTAG_TRST_ASSERTED) + { + buf_set_ones(device->cur_instr, device->ir_length); + device->bypass = 1; + } + + return ERROR_OK; +} + +void jtag_sleep(u32 us) +{ + usleep(us); +} + +/* Try to examine chain layout according to IEEE 1149.1 §12 + */ +int jtag_examine_chain() +{ + jtag_device_t *device = jtag_devices; + scan_field_t field; + u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4]; + int i; + int bit_count; + int device_count = 0; + u8 zero_check = 0x0; + u8 one_check = 0xff; + + field.device = 0; + field.num_bits = sizeof(idcode_buffer) * 8; + field.out_value = idcode_buffer; + field.out_mask = NULL; + field.in_value = idcode_buffer; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + for (i = 0; i < JTAG_MAX_CHAIN_SIZE; i++) + { + buf_set_u32(idcode_buffer, i * 32, 32, 0x000000FF); + } + + jtag_add_plain_dr_scan(1, &field, TAP_TLR); + jtag_execute_queue(); + + for (i = 0; i < JTAG_MAX_CHAIN_SIZE * 4; i++) + { + zero_check |= idcode_buffer[i]; + one_check &= idcode_buffer[i]; + } + + /* if there wasn't a single non-zero bit or if all bits were one, the scan isn't valid */ + if ((zero_check == 0x00) || (one_check == 0xff)) + { + ERROR("JTAG communication failure, check connection, JTAG interface, target power etc."); + return ERROR_JTAG_INIT_FAILED; + } + + for (bit_count = 0; bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;) + { + u32 idcode = buf_get_u32(idcode_buffer, bit_count, 32); + if ((idcode & 1) == 0) + { + /* LSB must not be 0, this indicates a device in bypass */ + device_count++; + + bit_count += 1; + } + else + { + u32 manufacturer; + u32 part; + u32 version; + + if (idcode == 0x000000FF) + { + /* End of chain (invalid manufacturer ID) */ + break; + } + + if (device) + { + device->idcode = idcode; + device = device->next; + } + device_count++; + + manufacturer = (idcode & 0xffe) >> 1; + part = (idcode & 0xffff000) >> 12; + version = (idcode & 0xf0000000) >> 28; + + INFO("JTAG device found: 0x%8.8x (Manufacturer: 0x%3.3x, Part: 0x%4.4x, Version: 0x%1.1x)", + idcode, manufacturer, part, version); + + bit_count += 32; + } + } + + /* see if number of discovered devices matches configuration */ + if (device_count != jtag_num_devices) + { + ERROR("number of discovered devices in JTAG chain (%i) doesn't match configuration (%i)", + device_count, jtag_num_devices); + ERROR("check the config file and ensure proper JTAG communication (connections, speed, ...)"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +int jtag_validate_chain() +{ + jtag_device_t *device = jtag_devices; + int total_ir_length = 0; + u8 *ir_test = NULL; + scan_field_t field; + int chain_pos = 0; + + while (device) + { + total_ir_length += device->ir_length; + device = device->next; + } + + total_ir_length += 2; + ir_test = malloc(CEIL(total_ir_length, 8)); + buf_set_ones(ir_test, total_ir_length); + + field.device = 0; + field.num_bits = total_ir_length; + field.out_value = ir_test; + field.out_mask = NULL; + field.in_value = ir_test; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_plain_ir_scan(1, &field, TAP_TLR); + jtag_execute_queue(); + + device = jtag_devices; + while (device) + { + if (buf_get_u32(ir_test, chain_pos, 2) != 0x1) + { + 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); + free(ir_test); + return ERROR_JTAG_INIT_FAILED; + } + chain_pos += device->ir_length; + device = device->next; + } + + if (buf_get_u32(ir_test, chain_pos, 2) != 0x3) + { + 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); + free(ir_test); + return ERROR_JTAG_INIT_FAILED; + } + + free(ir_test); + + return ERROR_OK; +} + +int jtag_register_commands(struct command_context_s *cmd_ctx) +{ + register_command(cmd_ctx, NULL, "interface", handle_interface_command, + COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "jtag_speed", handle_jtag_speed_command, + COMMAND_ANY, "set jtag speed (if supported) <speed>"); + register_command(cmd_ctx, NULL, "jtag_device", handle_jtag_device_command, + COMMAND_CONFIG, "jtag_device <ir_length> <ir_expected> <ir_mask>"); + register_command(cmd_ctx, NULL, "reset_config", handle_reset_config_command, + COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "jtag_nsrst_delay", handle_jtag_nsrst_delay_command, + COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "jtag_ntrst_delay", handle_jtag_ntrst_delay_command, + COMMAND_CONFIG, NULL); + + register_command(cmd_ctx, NULL, "scan_chain", handle_scan_chain_command, + COMMAND_EXEC, "print current scan chain configuration"); + + register_command(cmd_ctx, NULL, "endstate", handle_endstate_command, + COMMAND_EXEC, "finish JTAG operations in <tap_state>"); + register_command(cmd_ctx, NULL, "jtag_reset", handle_jtag_reset_command, + COMMAND_EXEC, "toggle reset lines <trst> <srst>"); + register_command(cmd_ctx, NULL, "runtest", handle_runtest_command, + COMMAND_EXEC, "move to Run-Test/Idle, and execute <num_cycles>"); + register_command(cmd_ctx, NULL, "statemove", handle_statemove_command, + COMMAND_EXEC, "move to current endstate or [tap_state]"); + register_command(cmd_ctx, NULL, "irscan", handle_irscan_command, + COMMAND_EXEC, "execute IR scan <device> <instr> [dev2] [instr2] ..."); + register_command(cmd_ctx, NULL, "drscan", handle_drscan_command, + COMMAND_EXEC, "execute DR scan <device> <var> [dev2] [var2] ..."); + + register_command(cmd_ctx, NULL, "verify_ircapture", handle_verify_ircapture_command, + COMMAND_ANY, "verify value captured during Capture-IR <enable|disable>"); + return ERROR_OK; +} + +int jtag_interface_init(struct command_context_s *cmd_ctx) +{ + if (!jtag_interface) + { + /* nothing was previously specified by "interface" command */ + ERROR("JTAG interface has to be specified, see \"interface\" command"); + return ERROR_JTAG_INVALID_INTERFACE; + } + + if (jtag_interface->init() != ERROR_OK) + return ERROR_JTAG_INIT_FAILED; + + jtag = jtag_interface; + return ERROR_OK; +} + +int jtag_init(struct command_context_s *cmd_ctx) +{ + int i, validate_tries = 0; + jtag_device_t *device; + + DEBUG("-"); + + if (!jtag && jtag_interface_init(cmd_ctx) != ERROR_OK) + return ERROR_JTAG_INIT_FAILED; + + device = jtag_devices; + jtag_ir_scan_size = 0; + jtag_num_devices = 0; + while (device != NULL) + { + jtag_ir_scan_size += device->ir_length; + jtag_num_devices++; + device = device->next; + } + + jtag_add_statemove(TAP_TLR); + jtag_execute_queue(); + + /* examine chain first, as this could discover the real chain layout */ + if (jtag_examine_chain() != ERROR_OK) + { + ERROR("trying to validate configured JTAG chain anyway..."); + } + + while (jtag_validate_chain() != ERROR_OK) + { + validate_tries++; + if (validate_tries > 5) + { + ERROR("Could not validate JTAG chain, exit"); + jtag = NULL; + return ERROR_JTAG_INVALID_INTERFACE; + } + usleep(10000); + } + + return ERROR_OK; +} + +int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int i; + + /* check whether the interface is already configured */ + if (jtag_interface) + { + WARNING("Interface already configured, ignoring"); + return ERROR_OK; + } + + /* interface name is a mandatory argument */ + if (argc < 1 || args[0][0] == '\0') + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + for (i=0; jtag_interfaces[i]; i++) + { + if (strcmp(args[0], jtag_interfaces[i]->name) == 0) + { + if (jtag_interfaces[i]->register_commands(cmd_ctx) != ERROR_OK) + exit(-1); + + jtag_interface = jtag_interfaces[i]; + return ERROR_OK; + } + } + + /* no valid interface was found (i.e. the configuration option, + * didn't match one of the compiled-in interfaces + */ + ERROR("No valid jtag interface found (%s)", args[0]); + ERROR("compiled-in jtag interfaces:"); + for (i = 0; jtag_interfaces[i]; i++) + { + ERROR("%i: %s", i, jtag_interfaces[i]->name); + } + + return ERROR_JTAG_INVALID_INTERFACE; +} + +int handle_jtag_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + jtag_device_t **last_device_p = &jtag_devices; + + if (*last_device_p) + { + while ((*last_device_p)->next) + last_device_p = &((*last_device_p)->next); + last_device_p = &((*last_device_p)->next); + } + + if (argc < 3) + return ERROR_OK; + + *last_device_p = malloc(sizeof(jtag_device_t)); + (*last_device_p)->ir_length = strtoul(args[0], NULL, 0); + + (*last_device_p)->expected = malloc((*last_device_p)->ir_length); + buf_set_u32((*last_device_p)->expected, 0, (*last_device_p)->ir_length, strtoul(args[1], NULL, 0)); + (*last_device_p)->expected_mask = malloc((*last_device_p)->ir_length); + buf_set_u32((*last_device_p)->expected_mask, 0, (*last_device_p)->ir_length, strtoul(args[2], NULL, 0)); + + (*last_device_p)->cur_instr = malloc((*last_device_p)->ir_length); + (*last_device_p)->bypass = 1; + buf_set_ones((*last_device_p)->cur_instr, (*last_device_p)->ir_length); + + (*last_device_p)->next = NULL; + + jtag_register_event_callback(jtag_reset_callback, (*last_device_p)); + + jtag_num_devices++; + + return ERROR_OK; +} + +int handle_scan_chain_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + jtag_device_t *device = jtag_devices; + int device_count = 0; + + while (device) + { + u32 expected, expected_mask, cur_instr; + expected = buf_get_u32(device->expected, 0, device->ir_length); + expected_mask = buf_get_u32(device->expected_mask, 0, device->ir_length); + cur_instr = buf_get_u32(device->cur_instr, 0, device->ir_length); + command_print(cmd_ctx, "%i: idcode: 0x%8.8x ir length %i, ir capture 0x%x, ir mask 0x%x, current instruction 0x%x", device_count, device->idcode, device->ir_length, expected, expected_mask, cur_instr); + device = device->next; + device_count++; + } + + return ERROR_OK; +} + +int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc >= 1) + { + if (strcmp(args[0], "none") == 0) + jtag_reset_config = RESET_NONE; + else if (strcmp(args[0], "trst_only") == 0) + jtag_reset_config = RESET_HAS_TRST; + else if (strcmp(args[0], "srst_only") == 0) + jtag_reset_config = RESET_HAS_SRST; + else if (strcmp(args[0], "trst_and_srst") == 0) + jtag_reset_config = RESET_TRST_AND_SRST; + else + { + ERROR("invalid reset_config argument, defaulting to none"); + jtag_reset_config = RESET_NONE; + return ERROR_INVALID_ARGUMENTS; + } + } + + if (argc >= 2) + { + if (strcmp(args[1], "srst_pulls_trst") == 0) + jtag_reset_config |= RESET_SRST_PULLS_TRST; + else if (strcmp(args[1], "trst_pulls_srst") == 0) + jtag_reset_config |= RESET_TRST_PULLS_SRST; + else if (strcmp(args[1], "combined") == 0) + jtag_reset_config |= RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST; + else if (strcmp(args[1], "separate") == 0) + jtag_reset_config &= ~(RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST); + else + { + ERROR("invalid reset_config argument, defaulting to none"); + jtag_reset_config = RESET_NONE; + return ERROR_INVALID_ARGUMENTS; + } + } + + if (argc >= 3) + { + if (strcmp(args[2], "trst_open_drain") == 0) + jtag_reset_config |= RESET_TRST_OPEN_DRAIN; + else if (strcmp(args[2], "trst_push_pull") == 0) + jtag_reset_config &= ~RESET_TRST_OPEN_DRAIN; + else + { + ERROR("invalid reset_config argument, defaulting to none"); + jtag_reset_config = RESET_NONE; + return ERROR_INVALID_ARGUMENTS; + } + } + + if (argc >= 4) + { + if (strcmp(args[3], "srst_push_pull") == 0) + jtag_reset_config |= RESET_SRST_PUSH_PULL; + else if (strcmp(args[3], "srst_open_drain") == 0) + jtag_reset_config &= ~RESET_SRST_PUSH_PULL; + else + { + ERROR("invalid reset_config argument, defaulting to none"); + jtag_reset_config = RESET_NONE; + return ERROR_INVALID_ARGUMENTS; + } + } + + return ERROR_OK; +} + +int handle_jtag_nsrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc < 1) + { + ERROR("jtag_nsrst_delay <ms> command takes one required argument"); + exit(-1); + } + else + { + jtag_nsrst_delay = strtoul(args[0], NULL, 0); + } + + return ERROR_OK; +} + +int handle_jtag_ntrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc < 1) + { + ERROR("jtag_ntrst_delay <ms> command takes one required argument"); + exit(-1); + } + else + { + jtag_ntrst_delay = strtoul(args[0], NULL, 0); + } + + return ERROR_OK; +} + +int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 0) + command_print(cmd_ctx, "jtag_speed: %i", jtag_speed); + + if (argc > 0) + { + /* this command can be called during CONFIG, + * in which case jtag isn't initialized */ + if (jtag) + jtag->speed(strtoul(args[0], NULL, 0)); + else + jtag_speed = strtoul(args[0], NULL, 0); + } + + return ERROR_OK; +} + +int handle_endstate_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + enum tap_state state; + + if (argc < 1) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + else + { + for (state = 0; state < 16; state++) + { + if (strcmp(args[0], tap_state_strings[state]) == 0) + { + jtag_add_end_state(state); + jtag_execute_queue(); + } + } + } + command_print(cmd_ctx, "current endstate: %s", tap_state_strings[end_state]); + + return ERROR_OK; +} + +int handle_jtag_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int trst = -1; + int srst = -1; + int retval; + + if (argc < 2) + { + return ERROR_COMMAND_SYNTAX_ERROR; + + } + + if (args[0][0] == '1') + trst = 1; + else if (args[0][0] == '0') + trst = 0; + else + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (args[1][0] == '1') + srst = 1; + else if (args[1][0] == '0') + srst = 0; + else + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (!jtag && jtag_interface_init(cmd_ctx) != ERROR_OK) + return ERROR_JTAG_INIT_FAILED; + + if ((retval = jtag_add_reset(trst, srst)) != ERROR_OK) + { + switch (retval) + { + case ERROR_JTAG_RESET_WOULD_ASSERT_TRST: + command_print(cmd_ctx, "requested reset would assert trst\nif this is acceptable, use jtag_reset 1 %c", args[1][0]); + break; + case ERROR_JTAG_RESET_CANT_SRST: + command_print(cmd_ctx, "can't assert srst because the current reset_config doesn't support it"); + break; + default: + command_print(cmd_ctx, "unknown error"); + } + } + jtag_execute_queue(); + + return ERROR_OK; +} + +int handle_runtest_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc < 1) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + jtag_add_runtest(strtol(args[0], NULL, 0), -1); + jtag_execute_queue(); + + return ERROR_OK; + +} + +int handle_statemove_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + enum tap_state state; + + state = -1; + if (argc == 1) + { + for (state = 0; state < 16; state++) + { + if (strcmp(args[0], tap_state_strings[state]) == 0) + { + break; + } + } + } + + jtag_add_statemove(state); + jtag_execute_queue(); + + return ERROR_OK; + +} + +int handle_irscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int i; + scan_field_t *fields; + + if ((argc < 2) || (argc % 2)) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + fields = malloc(sizeof(scan_field_t) * argc / 2); + + for (i = 0; i < argc / 2; i++) + { + int device = strtoul(args[i*2], NULL, 0); + int field_size = jtag_get_device(device)->ir_length; + fields[i].device = device; + fields[i].out_value = malloc(CEIL(field_size, 8)); + buf_set_u32(fields[i].out_value, 0, field_size, strtoul(args[i*2+1], NULL, 0)); + fields[i].out_mask = NULL; + fields[i].in_value = NULL; + fields[i].in_check_mask = NULL; + fields[i].in_handler = NULL; + fields[i].in_handler_priv = NULL; + } + + jtag_add_ir_scan(argc / 2, fields, -1); + jtag_execute_queue(); + + for (i = 0; i < argc / 2; i++) + free(fields[i].out_value); + + free (fields); + + return ERROR_OK; +} + +int handle_drscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + scan_field_t *fields; + int num_fields = 0; + int field_count = 0; + var_t *var; + int i, j; + + if ((argc < 2) || (argc % 2)) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + for (i = 0; i < argc; i+=2) + { + var = get_var_by_namenum(args[i+1]); + if (var) + { + num_fields += var->num_fields; + } + else + { + command_print(cmd_ctx, "variable %s doesn't exist", args[i+1]); + return ERROR_OK; + } + } + + fields = malloc(sizeof(scan_field_t) * num_fields); + + for (i = 0; i < argc; i+=2) + { + var = get_var_by_namenum(args[i+1]); + + for (j = 0; j < var->num_fields; j++) + { + fields[field_count].device = strtol(args[i], NULL, 0); + fields[field_count].num_bits = var->fields[j].num_bits; + fields[field_count].out_value = malloc(CEIL(var->fields[j].num_bits, 8)); + buf_set_u32(fields[field_count].out_value, 0, var->fields[j].num_bits, var->fields[j].value); + fields[field_count].out_mask = NULL; + fields[field_count].in_value = fields[field_count].out_value; + fields[field_count].in_check_mask = NULL; + fields[field_count].in_check_value = NULL; + fields[field_count].in_handler = field_le_to_host; + fields[field_count++].in_handler_priv = &(var->fields[j]); + } + } + + jtag_add_dr_scan(num_fields, fields, -1); + jtag_execute_queue(); + + for (i = 0; i < argc / 2; i++) + free(fields[i].out_value); + + free(fields); + + return ERROR_OK; +} + +int handle_verify_ircapture_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 1) + { + if (strcmp(args[0], "enable") == 0) + { + jtag_verify_capture_ir = 1; + } + else if (strcmp(args[0], "disable") == 0) + { + jtag_verify_capture_ir = 0; + } else + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + } else if (argc != 0) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + command_print(cmd_ctx, "verify Capture-IR is %s", (jtag_verify_capture_ir) ? "enabled": "disabled"); + + return ERROR_OK; +} diff --git a/src/jtag/usbprog.c b/src/jtag/usbprog.c index 2ff785a..d0011f0 100644 --- a/src/jtag/usbprog.c +++ b/src/jtag/usbprog.c @@ -1,681 +1,681 @@ -/***************************************************************************
- * Copyright (C) 2007 by Benedikt Sauter sauter@ixbat.de *
- * based on Dominic Rath's amt_jtagaccel.c *
- * *
- * usbprog is a free programming adapter. You can easily install *
- * different firmware versions from an "online pool" over USB. *
- * The adapter can be used for programming and debugging AVR and ARM *
- * processors, as USB to RS232 converter, as JTAG interface or as *
- * simple I/O interface (5 lines). *
- * *
- * http://www.embedded-projects.net/usbprog *
- * *
- * 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 "jtag.h"
-#include <usb.h>
-
-/* system includes */
-
-#include "log.h"
-
-#define VID 0x1781
-#define PID 0x0c63
-
-/* Pins at usbprog */
-#define TDO_BIT 0
-#define TDI_BIT 3
-#define TCK_BIT 2
-#define TMS_BIT 1
-
-int usbprog_execute_queue(void);
-int usbprog_speed(int speed);
-int usbprog_register_commands(struct command_context_s *cmd_ctx);
-int usbprog_init(void);
-int usbprog_quit(void);
-
-void usbprog_end_state(enum tap_state state);
-void usbprog_state_move(void);
-void usbprog_path_move(pathmove_command_t *cmd);
-void usbprog_runtest(int num_cycles);
-void usbprog_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size);
-
-jtag_interface_t usbprog_interface =
-{
- .name = "usbprog",
- .execute_queue = usbprog_execute_queue,
- .speed = usbprog_speed,
- .register_commands = usbprog_register_commands,
- .init = usbprog_init,
- .quit = usbprog_quit
-};
-
-#define UNKOWN_COMMAND 0x00
-#define PORT_DIRECTION 0x01
-#define PORT_SET 0x02
-#define PORT_GET 0x03
-#define PORT_SETBIT 0x04
-#define PORT_GETBIT 0x05
-#define WRITE_TDI 0x06
-#define READ_TDO 0x07
-#define WRITE_AND_READ 0x08
-#define WRITE_TMS 0x09
-#define WRITE_TMS_CHAIN 0x0A
-
-struct usbprog_jtag
-{
- struct usb_dev_handle* usb_handle;
-};
-
-struct usbprog_jtag * usbprog_jtag_handle;
-
-struct usbprog_jtag* usbprog_jtag_open();
-void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag);
-void usbprog_jtag_init(struct usbprog_jtag *usbprog_jtag);
-unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen);
-
-void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char * buffer, int size);
-void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char * buffer, int size);
-void usbprog_jtag_write_and_read(struct usbprog_jtag *usbprog_jtag, char * buffer, int size);
-void usbprog_jtag_write_tms(struct usbprog_jtag *usbprog_jtag, char tms_scan);
-
-char tms_chain[64];
-int tms_chain_index;
-void usbprog_jtag_tms_collect(char tms_scan);
-void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag);
-
-void usbprog_write(int tck, int tms, int tdi);
-void usbprog_reset(int trst, int srst);
-
-void usbprog_jtag_set_direction(struct usbprog_jtag *usbprog_jtag, unsigned char direction);
-void usbprog_jtag_write_slice(struct usbprog_jtag *usbprog_jtag,unsigned char value);
-unsigned char usbprog_jtag_get_port(struct usbprog_jtag *usbprog_jtag);
-void usbprog_jtag_set_bit(struct usbprog_jtag *usbprog_jtag,int bit, int value);
-int usbprog_jtag_get_bit(struct usbprog_jtag *usbprog_jtag, int bit);
-
-int usbprog_speed(int speed)
-{
- return ERROR_OK;
-}
-
-int usbprog_register_commands(struct command_context_s *cmd_ctx)
-{
- return ERROR_OK;
-}
-
-int usbprog_execute_queue(void)
-{
- jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
- int scan_size;
- enum scan_type type;
- u8 *buffer;
-
- while (cmd)
- {
- switch (cmd->type)
- {
- case JTAG_END_STATE:
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("end_state: %i", cmd->cmd.end_state->end_state);
-#endif
- if (cmd->cmd.end_state->end_state != -1)
- usbprog_end_state(cmd->cmd.end_state->end_state);
- break;
- case JTAG_RESET:
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
-#endif
- if (cmd->cmd.reset->trst == 1)
- {
- cur_state = TAP_TLR;
- }
- usbprog_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
- break;
- case JTAG_RUNTEST:
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state);
-#endif
- if (cmd->cmd.runtest->end_state != -1)
- usbprog_end_state(cmd->cmd.runtest->end_state);
- usbprog_runtest(cmd->cmd.runtest->num_cycles);
- break;
- case JTAG_STATEMOVE:
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("statemove end in %i", cmd->cmd.statemove->end_state);
-#endif
- if (cmd->cmd.statemove->end_state != -1)
- usbprog_end_state(cmd->cmd.statemove->end_state);
- usbprog_state_move();
- break;
- case JTAG_PATHMOVE:
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states,
- cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
-#endif
- usbprog_path_move(cmd->cmd.pathmove);
- break;
- case JTAG_SCAN:
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("scan end in %i", cmd->cmd.scan->end_state);
-#endif
- if (cmd->cmd.scan->end_state != -1)
- usbprog_end_state(cmd->cmd.scan->end_state);
- scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
- type = jtag_scan_type(cmd->cmd.scan);
- usbprog_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
- if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
- return ERROR_JTAG_QUEUE_FAILED;
- if (buffer)
- free(buffer);
- break;
- case JTAG_SLEEP:
-#ifdef _DEBUG_JTAG_IO_
- DEBUG("sleep %i", cmd->cmd.sleep->us);
-#endif
- jtag_sleep(cmd->cmd.sleep->us);
- break;
- default:
- ERROR("BUG: unknown JTAG command type encountered");
- exit(-1);
- }
-
- cmd = cmd->next;
- }
-
- return ERROR_OK;
-}
-
-int usbprog_init(void)
-{
- usbprog_jtag_handle = usbprog_jtag_open();
-
- tms_chain_index = 0;
- if (usbprog_jtag_handle == 0)
- {
- ERROR("Can't find USB JTAG Interface! Please check connection and permissions.");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- INFO("USB JTAG Interface ready!");
-
- usbprog_jtag_init(usbprog_jtag_handle);
- usbprog_reset(0, 0);
- usbprog_write(0, 0, 0);
-
- return ERROR_OK;
-}
-
-int usbprog_quit(void)
-{
- return ERROR_OK;
-}
-
-/*************** jtag execute commands **********************/
-void usbprog_end_state(enum tap_state state)
-{
- if (tap_move_map[state] != -1)
- end_state = state;
- else
- {
- ERROR("BUG: %i is not a valid end state", state);
- exit(-1);
- }
-}
-
-void usbprog_state_move(void)
-{
- int i = 0, tms = 0;
- u8 tms_scan = TAP_MOVE(cur_state, end_state);
-
- usbprog_jtag_write_tms(usbprog_jtag_handle, (char)tms_scan);
- for (i = 0; i < 7; i++)
- {
- tms = (tms_scan >> i) & 1;
- }
-
- cur_state = end_state;
-}
-
-void usbprog_path_move(pathmove_command_t *cmd)
-{
- int num_states = cmd->num_states;
- int state_count;
-
- state_count = 0;
- while (num_states)
- {
- if (tap_transitions[cur_state].low == cmd->path[state_count])
- {
- //INFO("1");
- usbprog_write(0, 0, 0);
- usbprog_write(1, 0, 0);
- }
- else if (tap_transitions[cur_state].high == cmd->path[state_count])
- {
- //INFO("2");
- usbprog_write(0, 1, 0);
- usbprog_write(1, 1, 0);
- }
- else
- {
- ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_strings[cur_state], tap_state_strings[cmd->path[state_count]]);
- exit(-1);
- }
-
- cur_state = cmd->path[state_count];
- state_count++;
- num_states--;
- }
-
- end_state = cur_state;
-}
-
-void usbprog_runtest(int num_cycles)
-{
- int i;
-
- /* only do a state_move when we're not already in RTI */
- if (cur_state != TAP_RTI)
- {
- usbprog_end_state(TAP_RTI);
- usbprog_state_move();
- }
-
- /* execute num_cycles */
- if (num_cycles > 0)
- {
- usbprog_jtag_tms_send(usbprog_jtag_handle);
- usbprog_write(0, 0, 0);
- }
- else
- {
- usbprog_jtag_tms_send(usbprog_jtag_handle);
- //INFO("NUM CYCLES %i",num_cycles);
- }
-
- for (i = 0; i < num_cycles; i++)
- {
- usbprog_write(1, 0, 0);
- usbprog_write(0, 0, 0);
- }
-
- /* finish in end_state */
- /*
- usbprog_end_state(saved_end_state);
- if (cur_state != end_state)
- usbprog_state_move();
- */
-}
-
-void usbprog_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
-{
- enum tap_state saved_end_state = end_state;
-
- if (ir_scan)
- usbprog_end_state(TAP_SI);
- else
- usbprog_end_state(TAP_SD);
-
- //usbprog_jtag_tms_send(usbprog_jtag_handle);
-
- usbprog_state_move();
- usbprog_end_state(saved_end_state);
-
- usbprog_jtag_tms_send(usbprog_jtag_handle);
-
- if (type == SCAN_OUT)
- {
- usbprog_jtag_write_tdi(usbprog_jtag_handle,buffer, scan_size);
- }
- if (type == SCAN_IN)
- {
- usbprog_jtag_read_tdo(usbprog_jtag_handle,buffer, scan_size);
- }
- if (type == SCAN_IO)
- {
- usbprog_jtag_write_and_read(usbprog_jtag_handle,buffer, scan_size);
- }
-
- if (ir_scan)
- cur_state = TAP_PI;
- else
- cur_state = TAP_PD;
-
- if (cur_state != end_state)
- usbprog_state_move();
-}
-
-/*************** jtag wrapper functions *********************/
-
-void usbprog_write(int tck, int tms, int tdi)
-{
- unsigned char output_value=0x00;
-
- if (tms)
- output_value |= (1<<TMS_BIT);
- if (tdi)
- output_value |= (1<<TDI_BIT);
- if (tck)
- output_value |= (1<<TCK_BIT);
-
- usbprog_jtag_write_slice(usbprog_jtag_handle,output_value);
-}
-
-/* (1) assert or (0) deassert reset lines */
-void usbprog_reset(int trst, int srst)
-{
- DEBUG("trst: %i, srst: %i", trst, srst);
-
- if (trst)
- usbprog_jtag_set_bit(usbprog_jtag_handle, 5, 0);
- else
- usbprog_jtag_set_bit(usbprog_jtag_handle, 5, 1);
-
- if (srst)
- usbprog_jtag_set_bit(usbprog_jtag_handle, 4, 0);
- else
- usbprog_jtag_set_bit(usbprog_jtag_handle, 4, 1);
-}
-
-/*************** jtag lowlevel functions ********************/
-
-struct usb_bus *busses;
-
-struct usbprog_jtag* usbprog_jtag_open()
-{
- struct usb_bus *bus;
- struct usb_device *dev;
-
- struct usbprog_jtag *tmp;
-
- tmp = (struct usbprog_jtag*)malloc(sizeof(struct usbprog_jtag));
-
- usb_set_debug(10);
- usb_init();
- usb_find_busses();
- usb_find_devices();
-
- busses = usb_get_busses();
-
- /* find usbprog_jtag device in usb bus */
-
- for (bus = busses; bus; bus = bus->next)
- {
- for (dev = bus->devices; dev; dev = dev->next)
- {
- /* condition for sucessfully hit (too bad, I only check the vendor id)*/
- if (dev->descriptor.idVendor == VID && dev->descriptor.idProduct == PID)
- {
- tmp->usb_handle = usb_open(dev);
- usb_set_configuration(tmp->usb_handle, 1);
- usb_claim_interface(tmp->usb_handle, 0);
- usb_set_altinterface(tmp->usb_handle, 0);
- return tmp;
- }
- }
- }
- return 0;
-}
-
-void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag)
-{
- usb_close(usbprog_jtag->usb_handle);
- free(usbprog_jtag);
-}
-
-unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen)
-{
- int res = usb_bulk_write(usbprog_jtag->usb_handle, 3, msg,msglen, 100);
- if ((msg[0] == 2) || (msg[0] == 1) || (msg[0] == 4) || (msg[0] == 0) || \
- (msg[0] == 6) || (msg[0] == 0x0A) || (msg[0] == 9))
- return 1;
- if (res == msglen)
- {
- //INFO("HALLLLOOO %i",(int)msg[0]);
- res = usb_bulk_read(usbprog_jtag->usb_handle, 0x82, msg, 2, 100);
- if (res > 0)
- return (unsigned char)msg[1];
- else
- return -1;
- }
- else
- return -1;
- return 0;
-}
-
-void usbprog_jtag_init(struct usbprog_jtag *usbprog_jtag)
-{
- usbprog_jtag_set_direction(usbprog_jtag, 0xFE);
-}
-
-void usbprog_jtag_write_and_read(struct usbprog_jtag *usbprog_jtag, char * buffer, int size)
-{
- char tmp[64]; /* fastes packet size for usb controller */
- int send_bits, bufindex = 0, fillindex = 0, i, loops;
-
- char swap;
- /* 61 byte can be transfered (488 bit) */
-
- while (size > 0)
- {
- if (size > 488)
- {
- send_bits = 488;
- size = size - 488;
- loops = 61;
- }
- else
- {
- send_bits = size;
- loops = size / 8;
- loops++;
- size = 0;
- }
- tmp[0] = WRITE_AND_READ;
- tmp[1] = (char)(send_bits >> 8); /* high */
- tmp[2] = (char)(send_bits); /* low */
- i = 0;
-
- for (i = 0; i < loops; i++)
- {
- tmp[3 + i] = buffer[bufindex];
- bufindex++;
- }
-
- if (usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000) == 64)
- {
- //INFO("HALLLLOOO2 %i",(int)tmp[0]);
- usleep(1);
- int timeout = 0;
- while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 1000) < 1)
- {
- timeout++;
- if (timeout > 10)
- break;
- }
-
- for (i = 0; i < loops; i++)
- {
- swap = tmp[3 + i];
- buffer[fillindex++] = swap;
- }
- }
- }
-}
-
-void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char * buffer, int size)
-{
- char tmp[64]; /* fastes packet size for usb controller */
- int send_bits, fillindex = 0, i, loops;
-
- char swap;
- /* 61 byte can be transfered (488 bit) */
-
- while (size > 0)
- {
- if (size > 488)
- {
- send_bits = 488;
- size = size - 488;
- loops = 61;
- }
- else
- {
- send_bits = size;
- loops = size / 8;
- loops++;
- size = 0;
- }
- tmp[0] = WRITE_AND_READ;
- tmp[1] = (char)(send_bits >> 8); /* high */
- tmp[2] = (char)(send_bits); /* low */
-
- usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 3, 1000);
-
- //INFO("HALLLLOOO3 %i",(int)tmp[0]);
- int timeout = 0;
- usleep(1);
- while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 10) < 1)
- {
- timeout++;
- if (timeout > 10)
- break;
- }
-
- for (i = 0; i < loops; i++)
- {
- swap = tmp[3 + i];
- buffer[fillindex++] = swap;
- }
- }
-}
-
-void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char * buffer, int size)
-{
- char tmp[64]; /* fastes packet size for usb controller */
- int send_bits, bufindex = 0, i, loops;
-
- /* 61 byte can be transfered (488 bit) */
- while (size > 0)
- {
- if (size > 488)
- {
- send_bits = 488;
- size = size - 488;
- loops = 61;
- }
- else
- {
- send_bits = size;
- loops = size/8;
- //if(loops==0)
- loops++;
- size = 0;
- }
- tmp[0] = WRITE_TDI;
- tmp[1] = (char)(send_bits >> 8); /* high */
- tmp[2] = (char)(send_bits); /* low */
- i = 0;
-
- for (i = 0; i < loops; i++)
- {
- tmp[3 + i] = buffer[bufindex];
- bufindex++;
- }
- usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000);
- }
-}
-
-void usbprog_jtag_write_tms(struct usbprog_jtag *usbprog_jtag, char tms_scan)
-{
- usbprog_jtag_tms_collect(tms_scan);
-}
-
-void usbprog_jtag_set_direction(struct usbprog_jtag *usbprog_jtag, unsigned char direction)
-{
- char tmp[2];
- tmp[0] = PORT_DIRECTION;
- tmp[1] = (char)direction;
- usbprog_jtag_message(usbprog_jtag, tmp, 2);
-}
-
-void usbprog_jtag_write_slice(struct usbprog_jtag *usbprog_jtag,unsigned char value)
-{
- char tmp[2];
- tmp[0] = PORT_SET;
- tmp[1] = (char)value;
- usbprog_jtag_message(usbprog_jtag, tmp, 2);
-}
-
-unsigned char usbprog_jtag_get_port(struct usbprog_jtag *usbprog_jtag)
-{
- char tmp[2];
- tmp[0] = PORT_GET;
- tmp[1] = 0x00;
- return usbprog_jtag_message(usbprog_jtag, tmp, 2);
-}
-
-void usbprog_jtag_set_bit(struct usbprog_jtag *usbprog_jtag,int bit, int value)
-{
- char tmp[3];
- tmp[0] = PORT_SETBIT;
- tmp[1] = (char)bit;
- if (value == 1)
- tmp[2] = 0x01;
- else
- tmp[2] = 0x00;
- usbprog_jtag_message(usbprog_jtag, tmp, 3);
-}
-
-int usbprog_jtag_get_bit(struct usbprog_jtag *usbprog_jtag, int bit)
-{
- char tmp[2];
- tmp[0] = PORT_GETBIT;
- tmp[1] = (char)bit;
-
- if (usbprog_jtag_message(usbprog_jtag, tmp, 2) > 0)
- return 1;
- else
- return 0;
-}
-
-void usbprog_jtag_tms_collect(char tms_scan)
-{
- tms_chain[tms_chain_index] = tms_scan;
- tms_chain_index++;
-}
-
-void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag)
-{
- int i;
- //INFO("TMS SEND");
- if (tms_chain_index > 0)
- {
- char tmp[tms_chain_index + 2];
- tmp[0] = WRITE_TMS_CHAIN;
- tmp[1] = (char)(tms_chain_index);
- for (i = 0; i < tms_chain_index + 1; i++)
- tmp[2 + i] = tms_chain[i];
- usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, tms_chain_index + 2, 1000);
- tms_chain_index = 0;
- }
-}
+/*************************************************************************** + * Copyright (C) 2007 by Benedikt Sauter sauter@ixbat.de * + * based on Dominic Rath's amt_jtagaccel.c * + * * + * usbprog is a free programming adapter. You can easily install * + * different firmware versions from an "online pool" over USB. * + * The adapter can be used for programming and debugging AVR and ARM * + * processors, as USB to RS232 converter, as JTAG interface or as * + * simple I/O interface (5 lines). * + * * + * http://www.embedded-projects.net/usbprog * + * * + * 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 "jtag.h" +#include <usb.h> + +/* system includes */ + +#include "log.h" + +#define VID 0x1781 +#define PID 0x0c63 + +/* Pins at usbprog */ +#define TDO_BIT 0 +#define TDI_BIT 3 +#define TCK_BIT 2 +#define TMS_BIT 1 + +int usbprog_execute_queue(void); +int usbprog_speed(int speed); +int usbprog_register_commands(struct command_context_s *cmd_ctx); +int usbprog_init(void); +int usbprog_quit(void); + +void usbprog_end_state(enum tap_state state); +void usbprog_state_move(void); +void usbprog_path_move(pathmove_command_t *cmd); +void usbprog_runtest(int num_cycles); +void usbprog_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size); + +jtag_interface_t usbprog_interface = +{ + .name = "usbprog", + .execute_queue = usbprog_execute_queue, + .speed = usbprog_speed, + .register_commands = usbprog_register_commands, + .init = usbprog_init, + .quit = usbprog_quit +}; + +#define UNKOWN_COMMAND 0x00 +#define PORT_DIRECTION 0x01 +#define PORT_SET 0x02 +#define PORT_GET 0x03 +#define PORT_SETBIT 0x04 +#define PORT_GETBIT 0x05 +#define WRITE_TDI 0x06 +#define READ_TDO 0x07 +#define WRITE_AND_READ 0x08 +#define WRITE_TMS 0x09 +#define WRITE_TMS_CHAIN 0x0A + +struct usbprog_jtag +{ + struct usb_dev_handle* usb_handle; +}; + +struct usbprog_jtag * usbprog_jtag_handle; + +struct usbprog_jtag* usbprog_jtag_open(); +void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag); +void usbprog_jtag_init(struct usbprog_jtag *usbprog_jtag); +unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen); + +void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char * buffer, int size); +void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char * buffer, int size); +void usbprog_jtag_write_and_read(struct usbprog_jtag *usbprog_jtag, char * buffer, int size); +void usbprog_jtag_write_tms(struct usbprog_jtag *usbprog_jtag, char tms_scan); + +char tms_chain[64]; +int tms_chain_index; +void usbprog_jtag_tms_collect(char tms_scan); +void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag); + +void usbprog_write(int tck, int tms, int tdi); +void usbprog_reset(int trst, int srst); + +void usbprog_jtag_set_direction(struct usbprog_jtag *usbprog_jtag, unsigned char direction); +void usbprog_jtag_write_slice(struct usbprog_jtag *usbprog_jtag,unsigned char value); +unsigned char usbprog_jtag_get_port(struct usbprog_jtag *usbprog_jtag); +void usbprog_jtag_set_bit(struct usbprog_jtag *usbprog_jtag,int bit, int value); +int usbprog_jtag_get_bit(struct usbprog_jtag *usbprog_jtag, int bit); + +int usbprog_speed(int speed) +{ + return ERROR_OK; +} + +int usbprog_register_commands(struct command_context_s *cmd_ctx) +{ + return ERROR_OK; +} + +int usbprog_execute_queue(void) +{ + jtag_command_t *cmd = jtag_command_queue; /* currently processed command */ + int scan_size; + enum scan_type type; + u8 *buffer; + + while (cmd) + { + switch (cmd->type) + { + case JTAG_END_STATE: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("end_state: %i", cmd->cmd.end_state->end_state); +#endif + if (cmd->cmd.end_state->end_state != -1) + usbprog_end_state(cmd->cmd.end_state->end_state); + break; + case JTAG_RESET: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); +#endif + if (cmd->cmd.reset->trst == 1) + { + cur_state = TAP_TLR; + } + usbprog_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + case JTAG_RUNTEST: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); +#endif + if (cmd->cmd.runtest->end_state != -1) + usbprog_end_state(cmd->cmd.runtest->end_state); + usbprog_runtest(cmd->cmd.runtest->num_cycles); + break; + case JTAG_STATEMOVE: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("statemove end in %i", cmd->cmd.statemove->end_state); +#endif + if (cmd->cmd.statemove->end_state != -1) + usbprog_end_state(cmd->cmd.statemove->end_state); + usbprog_state_move(); + break; + case JTAG_PATHMOVE: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, + cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); +#endif + usbprog_path_move(cmd->cmd.pathmove); + break; + case JTAG_SCAN: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("scan end in %i", cmd->cmd.scan->end_state); +#endif + if (cmd->cmd.scan->end_state != -1) + usbprog_end_state(cmd->cmd.scan->end_state); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + type = jtag_scan_type(cmd->cmd.scan); + usbprog_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); + if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) + return ERROR_JTAG_QUEUE_FAILED; + if (buffer) + free(buffer); + break; + case JTAG_SLEEP: +#ifdef _DEBUG_JTAG_IO_ + DEBUG("sleep %i", cmd->cmd.sleep->us); +#endif + jtag_sleep(cmd->cmd.sleep->us); + break; + default: + ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); + } + + cmd = cmd->next; + } + + return ERROR_OK; +} + +int usbprog_init(void) +{ + usbprog_jtag_handle = usbprog_jtag_open(); + + tms_chain_index = 0; + if (usbprog_jtag_handle == 0) + { + ERROR("Can't find USB JTAG Interface! Please check connection and permissions."); + return ERROR_JTAG_INIT_FAILED; + } + + INFO("USB JTAG Interface ready!"); + + usbprog_jtag_init(usbprog_jtag_handle); + usbprog_reset(0, 0); + usbprog_write(0, 0, 0); + + return ERROR_OK; +} + +int usbprog_quit(void) +{ + return ERROR_OK; +} + +/*************** jtag execute commands **********************/ +void usbprog_end_state(enum tap_state state) +{ + if (tap_move_map[state] != -1) + end_state = state; + else + { + ERROR("BUG: %i is not a valid end state", state); + exit(-1); + } +} + +void usbprog_state_move(void) +{ + int i = 0, tms = 0; + u8 tms_scan = TAP_MOVE(cur_state, end_state); + + usbprog_jtag_write_tms(usbprog_jtag_handle, (char)tms_scan); + for (i = 0; i < 7; i++) + { + tms = (tms_scan >> i) & 1; + } + + cur_state = end_state; +} + +void usbprog_path_move(pathmove_command_t *cmd) +{ + int num_states = cmd->num_states; + int state_count; + + state_count = 0; + while (num_states) + { + if (tap_transitions[cur_state].low == cmd->path[state_count]) + { + //INFO("1"); + usbprog_write(0, 0, 0); + usbprog_write(1, 0, 0); + } + else if (tap_transitions[cur_state].high == cmd->path[state_count]) + { + //INFO("2"); + usbprog_write(0, 1, 0); + usbprog_write(1, 1, 0); + } + else + { + ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_strings[cur_state], tap_state_strings[cmd->path[state_count]]); + exit(-1); + } + + cur_state = cmd->path[state_count]; + state_count++; + num_states--; + } + + end_state = cur_state; +} + +void usbprog_runtest(int num_cycles) +{ + int i; + + /* only do a state_move when we're not already in RTI */ + if (cur_state != TAP_RTI) + { + usbprog_end_state(TAP_RTI); + usbprog_state_move(); + } + + /* execute num_cycles */ + if (num_cycles > 0) + { + usbprog_jtag_tms_send(usbprog_jtag_handle); + usbprog_write(0, 0, 0); + } + else + { + usbprog_jtag_tms_send(usbprog_jtag_handle); + //INFO("NUM CYCLES %i",num_cycles); + } + + for (i = 0; i < num_cycles; i++) + { + usbprog_write(1, 0, 0); + usbprog_write(0, 0, 0); + } + + /* finish in end_state */ + /* + usbprog_end_state(saved_end_state); + if (cur_state != end_state) + usbprog_state_move(); + */ +} + +void usbprog_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size) +{ + enum tap_state saved_end_state = end_state; + + if (ir_scan) + usbprog_end_state(TAP_SI); + else + usbprog_end_state(TAP_SD); + + //usbprog_jtag_tms_send(usbprog_jtag_handle); + + usbprog_state_move(); + usbprog_end_state(saved_end_state); + + usbprog_jtag_tms_send(usbprog_jtag_handle); + + if (type == SCAN_OUT) + { + usbprog_jtag_write_tdi(usbprog_jtag_handle,buffer, scan_size); + } + if (type == SCAN_IN) + { + usbprog_jtag_read_tdo(usbprog_jtag_handle,buffer, scan_size); + } + if (type == SCAN_IO) + { + usbprog_jtag_write_and_read(usbprog_jtag_handle,buffer, scan_size); + } + + if (ir_scan) + cur_state = TAP_PI; + else + cur_state = TAP_PD; + + if (cur_state != end_state) + usbprog_state_move(); +} + +/*************** jtag wrapper functions *********************/ + +void usbprog_write(int tck, int tms, int tdi) +{ + unsigned char output_value=0x00; + + if (tms) + output_value |= (1<<TMS_BIT); + if (tdi) + output_value |= (1<<TDI_BIT); + if (tck) + output_value |= (1<<TCK_BIT); + + usbprog_jtag_write_slice(usbprog_jtag_handle,output_value); +} + +/* (1) assert or (0) deassert reset lines */ +void usbprog_reset(int trst, int srst) +{ + DEBUG("trst: %i, srst: %i", trst, srst); + + if (trst) + usbprog_jtag_set_bit(usbprog_jtag_handle, 5, 0); + else + usbprog_jtag_set_bit(usbprog_jtag_handle, 5, 1); + + if (srst) + usbprog_jtag_set_bit(usbprog_jtag_handle, 4, 0); + else + usbprog_jtag_set_bit(usbprog_jtag_handle, 4, 1); +} + +/*************** jtag lowlevel functions ********************/ + +struct usb_bus *busses; + +struct usbprog_jtag* usbprog_jtag_open() +{ + struct usb_bus *bus; + struct usb_device *dev; + + struct usbprog_jtag *tmp; + + tmp = (struct usbprog_jtag*)malloc(sizeof(struct usbprog_jtag)); + + usb_set_debug(10); + usb_init(); + usb_find_busses(); + usb_find_devices(); + + busses = usb_get_busses(); + + /* find usbprog_jtag device in usb bus */ + + for (bus = busses; bus; bus = bus->next) + { + for (dev = bus->devices; dev; dev = dev->next) + { + /* condition for sucessfully hit (too bad, I only check the vendor id)*/ + if (dev->descriptor.idVendor == VID && dev->descriptor.idProduct == PID) + { + tmp->usb_handle = usb_open(dev); + usb_set_configuration(tmp->usb_handle, 1); + usb_claim_interface(tmp->usb_handle, 0); + usb_set_altinterface(tmp->usb_handle, 0); + return tmp; + } + } + } + return 0; +} + +void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag) +{ + usb_close(usbprog_jtag->usb_handle); + free(usbprog_jtag); +} + +unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen) +{ + int res = usb_bulk_write(usbprog_jtag->usb_handle, 3, msg,msglen, 100); + if ((msg[0] == 2) || (msg[0] == 1) || (msg[0] == 4) || (msg[0] == 0) || \ + (msg[0] == 6) || (msg[0] == 0x0A) || (msg[0] == 9)) + return 1; + if (res == msglen) + { + //INFO("HALLLLOOO %i",(int)msg[0]); + res = usb_bulk_read(usbprog_jtag->usb_handle, 0x82, msg, 2, 100); + if (res > 0) + return (unsigned char)msg[1]; + else + return -1; + } + else + return -1; + return 0; +} + +void usbprog_jtag_init(struct usbprog_jtag *usbprog_jtag) +{ + usbprog_jtag_set_direction(usbprog_jtag, 0xFE); +} + +void usbprog_jtag_write_and_read(struct usbprog_jtag *usbprog_jtag, char * buffer, int size) +{ + char tmp[64]; /* fastes packet size for usb controller */ + int send_bits, bufindex = 0, fillindex = 0, i, loops; + + char swap; + /* 61 byte can be transfered (488 bit) */ + + while (size > 0) + { + if (size > 488) + { + send_bits = 488; + size = size - 488; + loops = 61; + } + else + { + send_bits = size; + loops = size / 8; + loops++; + size = 0; + } + tmp[0] = WRITE_AND_READ; + tmp[1] = (char)(send_bits >> 8); /* high */ + tmp[2] = (char)(send_bits); /* low */ + i = 0; + + for (i = 0; i < loops; i++) + { + tmp[3 + i] = buffer[bufindex]; + bufindex++; + } + + if (usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000) == 64) + { + //INFO("HALLLLOOO2 %i",(int)tmp[0]); + usleep(1); + int timeout = 0; + while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 1000) < 1) + { + timeout++; + if (timeout > 10) + break; + } + + for (i = 0; i < loops; i++) + { + swap = tmp[3 + i]; + buffer[fillindex++] = swap; + } + } + } +} + +void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char * buffer, int size) +{ + char tmp[64]; /* fastes packet size for usb controller */ + int send_bits, fillindex = 0, i, loops; + + char swap; + /* 61 byte can be transfered (488 bit) */ + + while (size > 0) + { + if (size > 488) + { + send_bits = 488; + size = size - 488; + loops = 61; + } + else + { + send_bits = size; + loops = size / 8; + loops++; + size = 0; + } + tmp[0] = WRITE_AND_READ; + tmp[1] = (char)(send_bits >> 8); /* high */ + tmp[2] = (char)(send_bits); /* low */ + + usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 3, 1000); + + //INFO("HALLLLOOO3 %i",(int)tmp[0]); + int timeout = 0; + usleep(1); + while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 10) < 1) + { + timeout++; + if (timeout > 10) + break; + } + + for (i = 0; i < loops; i++) + { + swap = tmp[3 + i]; + buffer[fillindex++] = swap; + } + } +} + +void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char * buffer, int size) +{ + char tmp[64]; /* fastes packet size for usb controller */ + int send_bits, bufindex = 0, i, loops; + + /* 61 byte can be transfered (488 bit) */ + while (size > 0) + { + if (size > 488) + { + send_bits = 488; + size = size - 488; + loops = 61; + } + else + { + send_bits = size; + loops = size/8; + //if(loops==0) + loops++; + size = 0; + } + tmp[0] = WRITE_TDI; + tmp[1] = (char)(send_bits >> 8); /* high */ + tmp[2] = (char)(send_bits); /* low */ + i = 0; + + for (i = 0; i < loops; i++) + { + tmp[3 + i] = buffer[bufindex]; + bufindex++; + } + usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000); + } +} + +void usbprog_jtag_write_tms(struct usbprog_jtag *usbprog_jtag, char tms_scan) +{ + usbprog_jtag_tms_collect(tms_scan); +} + +void usbprog_jtag_set_direction(struct usbprog_jtag *usbprog_jtag, unsigned char direction) +{ + char tmp[2]; + tmp[0] = PORT_DIRECTION; + tmp[1] = (char)direction; + usbprog_jtag_message(usbprog_jtag, tmp, 2); +} + +void usbprog_jtag_write_slice(struct usbprog_jtag *usbprog_jtag,unsigned char value) +{ + char tmp[2]; + tmp[0] = PORT_SET; + tmp[1] = (char)value; + usbprog_jtag_message(usbprog_jtag, tmp, 2); +} + +unsigned char usbprog_jtag_get_port(struct usbprog_jtag *usbprog_jtag) +{ + char tmp[2]; + tmp[0] = PORT_GET; + tmp[1] = 0x00; + return usbprog_jtag_message(usbprog_jtag, tmp, 2); +} + +void usbprog_jtag_set_bit(struct usbprog_jtag *usbprog_jtag,int bit, int value) +{ + char tmp[3]; + tmp[0] = PORT_SETBIT; + tmp[1] = (char)bit; + if (value == 1) + tmp[2] = 0x01; + else + tmp[2] = 0x00; + usbprog_jtag_message(usbprog_jtag, tmp, 3); +} + +int usbprog_jtag_get_bit(struct usbprog_jtag *usbprog_jtag, int bit) +{ + char tmp[2]; + tmp[0] = PORT_GETBIT; + tmp[1] = (char)bit; + + if (usbprog_jtag_message(usbprog_jtag, tmp, 2) > 0) + return 1; + else + return 0; +} + +void usbprog_jtag_tms_collect(char tms_scan) +{ + tms_chain[tms_chain_index] = tms_scan; + tms_chain_index++; +} + +void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag) +{ + int i; + //INFO("TMS SEND"); + if (tms_chain_index > 0) + { + char tmp[tms_chain_index + 2]; + tmp[0] = WRITE_TMS_CHAIN; + tmp[1] = (char)(tms_chain_index); + for (i = 0; i < tms_chain_index + 1; i++) + tmp[2 + i] = tms_chain[i]; + usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, tms_chain_index + 2, 1000); + tms_chain_index = 0; + } +} diff --git a/src/openocd.c b/src/openocd.c index c2f8776..d362c64 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -1,157 +1,157 @@ -/***************************************************************************
- * 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. *
- ***************************************************************************/
-
-#define OPENOCD_VERSION "Open On-Chip Debugger " VERSION " (" PKGBLDDATE ") svn:" PKGBLDREV
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "log.h"
-#include "types.h"
-#include "jtag.h"
-#include "configuration.h"
-#include "interpreter.h"
-#include "xsvf.h"
-#include "target.h"
-#include "flash.h"
-#include "nand.h"
-#include "pld.h"
-
-#include "command.h"
-#include "server.h"
-#include "telnet_server.h"
-#include "gdb_server.h"
-
-#include <sys/time.h>
-#include <sys/types.h>
-#include <strings.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-
-/* Give TELNET a way to find out what version this is */
-int handle_version_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- command_print(cmd_ctx, OPENOCD_VERSION);
-
- return ERROR_OK;
-}
-
-void exit_handler(void)
-{
- /* close JTAG interface */
- if (jtag && jtag->quit)
- jtag->quit();
-}
-
-int main(int argc, char *argv[])
-{
- /* initialize commandline interface */
- command_context_t *cmd_ctx, *cfg_cmd_ctx;
- cmd_ctx = command_init();
-
- register_command(cmd_ctx, NULL, "version", handle_version_command,
- COMMAND_EXEC, "show OpenOCD version");
-
- /* register subsystem commands */
- server_register_commands(cmd_ctx);
- telnet_register_commands(cmd_ctx);
- gdb_register_commands(cmd_ctx);
- log_register_commands(cmd_ctx);
- jtag_register_commands(cmd_ctx);
- interpreter_register_commands(cmd_ctx);
- xsvf_register_commands(cmd_ctx);
- target_register_commands(cmd_ctx);
- flash_register_commands(cmd_ctx);
- nand_register_commands(cmd_ctx);
- pld_register_commands(cmd_ctx);
-
- if (log_init(cmd_ctx) != ERROR_OK)
- return EXIT_FAILURE;
- DEBUG("log init complete");
-
- printf( OPENOCD_VERSION );
- printf( "\n$URL$\n");
-
- DEBUG( OPENOCD_VERSION );
- DEBUG( "$URL$");
-
- cfg_cmd_ctx = copy_command_context(cmd_ctx);
- cfg_cmd_ctx->mode = COMMAND_CONFIG;
- command_set_output_handler(cfg_cmd_ctx, configuration_output_handler, NULL);
-
- if (parse_cmdline_args(cfg_cmd_ctx, argc, argv) != ERROR_OK)
- return EXIT_FAILURE;
-
- if (parse_config_file(cfg_cmd_ctx) != ERROR_OK)
- return EXIT_FAILURE;
-
- command_done(cfg_cmd_ctx);
-
- command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);
-
- atexit(exit_handler);
-
- if (jtag_init(cmd_ctx) != ERROR_OK)
- return EXIT_FAILURE;
- DEBUG("jtag init complete");
-
- if (target_init(cmd_ctx) != ERROR_OK)
- return EXIT_FAILURE;
- DEBUG("target init complete");
-
- if (flash_init_drivers(cmd_ctx) != ERROR_OK)
- return EXIT_FAILURE;
- DEBUG("flash init complete");
-
- if (nand_init(cmd_ctx) != ERROR_OK)
- return EXIT_FAILURE;
- DEBUG("NAND init complete");
-
- if (pld_init(cmd_ctx) != ERROR_OK)
- return EXIT_FAILURE;
- DEBUG("pld init complete");
-
- /* initialize tcp server */
- server_init();
-
- /* initialize telnet subsystem */
- telnet_init("Open On-Chip Debugger");
- gdb_init();
-
- /* call any target resets */
- if (target_init_reset(cmd_ctx) != ERROR_OK)
- return EXIT_FAILURE;
- DEBUG("target init reset complete");
-
- /* handle network connections */
- server_loop(cmd_ctx);
-
- /* shut server down */
- server_quit();
-
- /* free commandline interface */
- command_done(cmd_ctx);
-
- return EXIT_SUCCESS;
-}
+/*************************************************************************** + * 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. * + ***************************************************************************/ + +#define OPENOCD_VERSION "Open On-Chip Debugger " VERSION " (" PKGBLDDATE ") svn:" PKGBLDREV + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "log.h" +#include "types.h" +#include "jtag.h" +#include "configuration.h" +#include "interpreter.h" +#include "xsvf.h" +#include "target.h" +#include "flash.h" +#include "nand.h" +#include "pld.h" + +#include "command.h" +#include "server.h" +#include "telnet_server.h" +#include "gdb_server.h" + +#include <sys/time.h> +#include <sys/types.h> +#include <strings.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +/* Give TELNET a way to find out what version this is */ +int handle_version_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + command_print(cmd_ctx, OPENOCD_VERSION); + + return ERROR_OK; +} + +void exit_handler(void) +{ + /* close JTAG interface */ + if (jtag && jtag->quit) + jtag->quit(); +} + +int main(int argc, char *argv[]) +{ + /* initialize commandline interface */ + command_context_t *cmd_ctx, *cfg_cmd_ctx; + cmd_ctx = command_init(); + + register_command(cmd_ctx, NULL, "version", handle_version_command, + COMMAND_EXEC, "show OpenOCD version"); + + /* register subsystem commands */ + server_register_commands(cmd_ctx); + telnet_register_commands(cmd_ctx); + gdb_register_commands(cmd_ctx); + log_register_commands(cmd_ctx); + jtag_register_commands(cmd_ctx); + interpreter_register_commands(cmd_ctx); + xsvf_register_commands(cmd_ctx); + target_register_commands(cmd_ctx); + flash_register_commands(cmd_ctx); + nand_register_commands(cmd_ctx); + pld_register_commands(cmd_ctx); + + if (log_init(cmd_ctx) != ERROR_OK) + return EXIT_FAILURE; + DEBUG("log init complete"); + + printf( OPENOCD_VERSION ); + printf( "\n$URL$\n"); + + DEBUG( OPENOCD_VERSION ); + DEBUG( "$URL$"); + + cfg_cmd_ctx = copy_command_context(cmd_ctx); + cfg_cmd_ctx->mode = COMMAND_CONFIG; + command_set_output_handler(cfg_cmd_ctx, configuration_output_handler, NULL); + + if (parse_cmdline_args(cfg_cmd_ctx, argc, argv) != ERROR_OK) + return EXIT_FAILURE; + + if (parse_config_file(cfg_cmd_ctx) != ERROR_OK) + return EXIT_FAILURE; + + command_done(cfg_cmd_ctx); + + command_set_output_handler(cmd_ctx, configuration_output_handler, NULL); + + atexit(exit_handler); + + if (jtag_init(cmd_ctx) != ERROR_OK) + return EXIT_FAILURE; + DEBUG("jtag init complete"); + + if (target_init(cmd_ctx) != ERROR_OK) + return EXIT_FAILURE; + DEBUG("target init complete"); + + if (flash_init_drivers(cmd_ctx) != ERROR_OK) + return EXIT_FAILURE; + DEBUG("flash init complete"); + + if (nand_init(cmd_ctx) != ERROR_OK) + return EXIT_FAILURE; + DEBUG("NAND init complete"); + + if (pld_init(cmd_ctx) != ERROR_OK) + return EXIT_FAILURE; + DEBUG("pld init complete"); + + /* initialize tcp server */ + server_init(); + + /* initialize telnet subsystem */ + telnet_init("Open On-Chip Debugger"); + gdb_init(); + + /* call any target resets */ + if (target_init_reset(cmd_ctx) != ERROR_OK) + return EXIT_FAILURE; + DEBUG("target init reset complete"); + + /* handle network connections */ + server_loop(cmd_ctx); + + /* shut server down */ + server_quit(); + + /* free commandline interface */ + command_done(cmd_ctx); + + return EXIT_SUCCESS; +} diff --git a/src/pld/virtex2.c b/src/pld/virtex2.c index e0cd1a1..53acc59 100644 --- a/src/pld/virtex2.c +++ b/src/pld/virtex2.c @@ -1,264 +1,264 @@ -/***************************************************************************
- * Copyright (C) 2006 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 "virtex2.h"
-
-#include "pld.h"
-#include "xilinx_bit.h"
-#include "command.h"
-#include "log.h"
-#include "jtag.h"
-
-#include <stdlib.h>
-
-int virtex2_register_commands(struct command_context_s *cmd_ctx);
-int virtex2_pld_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct pld_device_s *pld_device);
-int virtex2_load(struct pld_device_s *pld_device, char *filename);
-
-pld_driver_t virtex2_pld =
-{
- .name = "virtex2",
- .register_commands = virtex2_register_commands,
- .pld_device_command = virtex2_pld_device_command,
- .load = virtex2_load,
-};
-
-int virtex2_set_instr(int chain_pos, u32 new_instr)
-{
- jtag_device_t *device = jtag_get_device(chain_pos);
-
- if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr)
- {
- scan_field_t field;
-
- field.device = chain_pos;
- field.num_bits = device->ir_length;
- field.out_value = calloc(CEIL(field.num_bits, 8), 1);
- buf_set_u32(field.out_value, 0, field.num_bits, new_instr);
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_ir_scan(1, &field, TAP_RTI);
-
- free(field.out_value);
- }
-
- return ERROR_OK;
-}
-
-int virtex2_send_32(struct pld_device_s *pld_device, int num_words, u32 *words)
-{
- virtex2_pld_device_t *virtex2_info = pld_device->driver_priv;
- scan_field_t scan_field;
- u8 *values;
- int i;
-
- values = malloc(num_words * 4);
-
- scan_field.device = virtex2_info->chain_pos;
- scan_field.num_bits = num_words * 32;
- scan_field.out_value = values;
- scan_field.out_mask = NULL;
- scan_field.in_value = NULL;
- scan_field.in_check_value = NULL;
- scan_field.in_check_mask = NULL;
- scan_field.in_handler = NULL;
- scan_field.in_handler_priv = NULL;
-
- for (i = 0; i < num_words; i++)
- buf_set_u32(values + 4 * i, 0, 32, flip_u32(*words++, 32));
-
- virtex2_set_instr(virtex2_info->chain_pos, 0x5); /* CFG_IN */
-
- jtag_add_dr_scan(1, &scan_field, TAP_PD);
-
- free(values);
-
- return ERROR_OK;
-}
-
-int virtex2_jtag_buf_to_u32(u8 *in_buf, void *priv, struct scan_field_s *field)
-{
- u32 *dest = priv;
- *dest = flip_u32(le_to_h_u32(in_buf), 32);
- return ERROR_OK;
-}
-
-int virtex2_receive_32(struct pld_device_s *pld_device, int num_words, u32 *words)
-{
- virtex2_pld_device_t *virtex2_info = pld_device->driver_priv;
- scan_field_t scan_field;
-
- scan_field.device = virtex2_info->chain_pos;
- scan_field.num_bits = 32;
- scan_field.out_value = NULL;
- scan_field.out_mask = NULL;
- scan_field.in_value = NULL;
- scan_field.in_check_value = NULL;
- scan_field.in_check_mask = NULL;
- scan_field.in_handler = virtex2_jtag_buf_to_u32;
-
- virtex2_set_instr(virtex2_info->chain_pos, 0x4); /* CFG_OUT */
-
- while (num_words--)
- {
- scan_field.in_handler_priv = words++;
- jtag_add_dr_scan(1, &scan_field, TAP_PD);
- }
-
- return ERROR_OK;
-}
-
-int virtex2_read_stat(struct pld_device_s *pld_device, u32 *status)
-{
- u32 data[5];
-
- jtag_add_statemove(TAP_TLR);
-
- data[0] = 0xaa995566; /* synch word */
- data[1] = 0x2800E001; /* Type 1, read, address 7, 1 word */
- data[2] = 0x20000000; /* NOOP (Type 1, read, address 0, 0 words */
- data[3] = 0x20000000; /* NOOP */
- data[4] = 0x20000000; /* NOOP */
- virtex2_send_32(pld_device, 5, data);
-
- virtex2_receive_32(pld_device, 1, status);
-
- jtag_execute_queue();
-
- DEBUG("status: 0x%8.8x", *status);
-
- return ERROR_OK;
-}
-
-int virtex2_load(struct pld_device_s *pld_device, char *filename)
-{
- virtex2_pld_device_t *virtex2_info = pld_device->driver_priv;
- xilinx_bit_file_t bit_file;
- int retval;
- int i;
-
- scan_field_t field;
-
- field.device = virtex2_info->chain_pos;
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- if ((retval = xilinx_read_bit_file(&bit_file, filename)) != ERROR_OK)
- return retval;
-
- jtag_add_end_state(TAP_RTI);
- virtex2_set_instr(virtex2_info->chain_pos, 0xb); /* JPROG_B */
- jtag_execute_queue();
- jtag_add_sleep(1000);
-
- virtex2_set_instr(virtex2_info->chain_pos, 0x5); /* CFG_IN */
- jtag_execute_queue();
-
- for (i = 0; i < bit_file.length; i++)
- bit_file.data[i] = flip_u32(bit_file.data[i], 8);
-
- field.num_bits = bit_file.length * 8;
- field.out_value = bit_file.data;
-
- jtag_add_dr_scan(1, &field, TAP_PD);
- jtag_execute_queue();
-
- jtag_add_statemove(TAP_TLR);
-
- jtag_add_end_state(TAP_RTI);
- virtex2_set_instr(virtex2_info->chain_pos, 0xc); /* JSTART */
- jtag_add_runtest(13, TAP_RTI);
- virtex2_set_instr(virtex2_info->chain_pos, 0x3f); /* BYPASS */
- virtex2_set_instr(virtex2_info->chain_pos, 0x3f); /* BYPASS */
- virtex2_set_instr(virtex2_info->chain_pos, 0xc); /* JSTART */
- jtag_add_runtest(13, TAP_RTI);
- virtex2_set_instr(virtex2_info->chain_pos, 0x3f); /* BYPASS */
- jtag_execute_queue();
-
- return ERROR_OK;
-}
-
-int virtex2_handle_read_stat_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- pld_device_t *device;
- virtex2_pld_device_t *virtex2_info;
- u32 status;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "usage: virtex2 read_stat <num>");
- return ERROR_OK;
- }
-
- device = get_pld_device_by_num(strtoul(args[0], NULL, 0));
- if (!device)
- {
- command_print(cmd_ctx, "pld device '#%s' is out of bounds", args[0]);
- return ERROR_OK;
- }
-
- virtex2_info = device->driver_priv;
-
- virtex2_read_stat(device, &status);
-
- command_print(cmd_ctx, "virtex2 status register: 0x%8.8x", status);
-
- return ERROR_OK;
-}
-
-int virtex2_register_commands(struct command_context_s *cmd_ctx)
-{
- command_t *virtex2_cmd = register_command(cmd_ctx, NULL, "virtex2", NULL, COMMAND_ANY, "virtex2 specific commands");
-
- register_command(cmd_ctx, virtex2_cmd, "read_stat", virtex2_handle_read_stat_command, COMMAND_EXEC,
- "read Virtex-II status register");
-
- return ERROR_OK;
-}
-
-int virtex2_pld_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct pld_device_s *pld_device)
-{
- virtex2_pld_device_t *virtex2_info;
-
- if (argc < 2)
- {
- WARNING("incomplete pld device 'virtex2' configuration");
- return ERROR_PLD_DEVICE_INVALID;
- }
-
- virtex2_info = malloc(sizeof(virtex2_pld_device_t));
- pld_device->driver_priv = virtex2_info;
-
- virtex2_info->chain_pos = strtoul(args[1], NULL, 0);
-
- return ERROR_OK;
-}
+/*************************************************************************** + * Copyright (C) 2006 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 "virtex2.h" + +#include "pld.h" +#include "xilinx_bit.h" +#include "command.h" +#include "log.h" +#include "jtag.h" + +#include <stdlib.h> + +int virtex2_register_commands(struct command_context_s *cmd_ctx); +int virtex2_pld_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct pld_device_s *pld_device); +int virtex2_load(struct pld_device_s *pld_device, char *filename); + +pld_driver_t virtex2_pld = +{ + .name = "virtex2", + .register_commands = virtex2_register_commands, + .pld_device_command = virtex2_pld_device_command, + .load = virtex2_load, +}; + +int virtex2_set_instr(int chain_pos, u32 new_instr) +{ + jtag_device_t *device = jtag_get_device(chain_pos); + + if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) + { + scan_field_t field; + + field.device = chain_pos; + field.num_bits = device->ir_length; + field.out_value = calloc(CEIL(field.num_bits, 8), 1); + buf_set_u32(field.out_value, 0, field.num_bits, new_instr); + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_ir_scan(1, &field, TAP_RTI); + + free(field.out_value); + } + + return ERROR_OK; +} + +int virtex2_send_32(struct pld_device_s *pld_device, int num_words, u32 *words) +{ + virtex2_pld_device_t *virtex2_info = pld_device->driver_priv; + scan_field_t scan_field; + u8 *values; + int i; + + values = malloc(num_words * 4); + + scan_field.device = virtex2_info->chain_pos; + scan_field.num_bits = num_words * 32; + scan_field.out_value = values; + scan_field.out_mask = NULL; + scan_field.in_value = NULL; + scan_field.in_check_value = NULL; + scan_field.in_check_mask = NULL; + scan_field.in_handler = NULL; + scan_field.in_handler_priv = NULL; + + for (i = 0; i < num_words; i++) + buf_set_u32(values + 4 * i, 0, 32, flip_u32(*words++, 32)); + + virtex2_set_instr(virtex2_info->chain_pos, 0x5); /* CFG_IN */ + + jtag_add_dr_scan(1, &scan_field, TAP_PD); + + free(values); + + return ERROR_OK; +} + +int virtex2_jtag_buf_to_u32(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + u32 *dest = priv; + *dest = flip_u32(le_to_h_u32(in_buf), 32); + return ERROR_OK; +} + +int virtex2_receive_32(struct pld_device_s *pld_device, int num_words, u32 *words) +{ + virtex2_pld_device_t *virtex2_info = pld_device->driver_priv; + scan_field_t scan_field; + + scan_field.device = virtex2_info->chain_pos; + scan_field.num_bits = 32; + scan_field.out_value = NULL; + scan_field.out_mask = NULL; + scan_field.in_value = NULL; + scan_field.in_check_value = NULL; + scan_field.in_check_mask = NULL; + scan_field.in_handler = virtex2_jtag_buf_to_u32; + + virtex2_set_instr(virtex2_info->chain_pos, 0x4); /* CFG_OUT */ + + while (num_words--) + { + scan_field.in_handler_priv = words++; + jtag_add_dr_scan(1, &scan_field, TAP_PD); + } + + return ERROR_OK; +} + +int virtex2_read_stat(struct pld_device_s *pld_device, u32 *status) +{ + u32 data[5]; + + jtag_add_statemove(TAP_TLR); + + data[0] = 0xaa995566; /* synch word */ + data[1] = 0x2800E001; /* Type 1, read, address 7, 1 word */ + data[2] = 0x20000000; /* NOOP (Type 1, read, address 0, 0 words */ + data[3] = 0x20000000; /* NOOP */ + data[4] = 0x20000000; /* NOOP */ + virtex2_send_32(pld_device, 5, data); + + virtex2_receive_32(pld_device, 1, status); + + jtag_execute_queue(); + + DEBUG("status: 0x%8.8x", *status); + + return ERROR_OK; +} + +int virtex2_load(struct pld_device_s *pld_device, char *filename) +{ + virtex2_pld_device_t *virtex2_info = pld_device->driver_priv; + xilinx_bit_file_t bit_file; + int retval; + int i; + + scan_field_t field; + + field.device = virtex2_info->chain_pos; + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + if ((retval = xilinx_read_bit_file(&bit_file, filename)) != ERROR_OK) + return retval; + + jtag_add_end_state(TAP_RTI); + virtex2_set_instr(virtex2_info->chain_pos, 0xb); /* JPROG_B */ + jtag_execute_queue(); + jtag_add_sleep(1000); + + virtex2_set_instr(virtex2_info->chain_pos, 0x5); /* CFG_IN */ + jtag_execute_queue(); + + for (i = 0; i < bit_file.length; i++) + bit_file.data[i] = flip_u32(bit_file.data[i], 8); + + field.num_bits = bit_file.length * 8; + field.out_value = bit_file.data; + + jtag_add_dr_scan(1, &field, TAP_PD); + jtag_execute_queue(); + + jtag_add_statemove(TAP_TLR); + + jtag_add_end_state(TAP_RTI); + virtex2_set_instr(virtex2_info->chain_pos, 0xc); /* JSTART */ + jtag_add_runtest(13, TAP_RTI); + virtex2_set_instr(virtex2_info->chain_pos, 0x3f); /* BYPASS */ + virtex2_set_instr(virtex2_info->chain_pos, 0x3f); /* BYPASS */ + virtex2_set_instr(virtex2_info->chain_pos, 0xc); /* JSTART */ + jtag_add_runtest(13, TAP_RTI); + virtex2_set_instr(virtex2_info->chain_pos, 0x3f); /* BYPASS */ + jtag_execute_queue(); + + return ERROR_OK; +} + +int virtex2_handle_read_stat_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + pld_device_t *device; + virtex2_pld_device_t *virtex2_info; + u32 status; + + if (argc < 1) + { + command_print(cmd_ctx, "usage: virtex2 read_stat <num>"); + return ERROR_OK; + } + + device = get_pld_device_by_num(strtoul(args[0], NULL, 0)); + if (!device) + { + command_print(cmd_ctx, "pld device '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + virtex2_info = device->driver_priv; + + virtex2_read_stat(device, &status); + + command_print(cmd_ctx, "virtex2 status register: 0x%8.8x", status); + + return ERROR_OK; +} + +int virtex2_register_commands(struct command_context_s *cmd_ctx) +{ + command_t *virtex2_cmd = register_command(cmd_ctx, NULL, "virtex2", NULL, COMMAND_ANY, "virtex2 specific commands"); + + register_command(cmd_ctx, virtex2_cmd, "read_stat", virtex2_handle_read_stat_command, COMMAND_EXEC, + "read Virtex-II status register"); + + return ERROR_OK; +} + +int virtex2_pld_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct pld_device_s *pld_device) +{ + virtex2_pld_device_t *virtex2_info; + + if (argc < 2) + { + WARNING("incomplete pld device 'virtex2' configuration"); + return ERROR_PLD_DEVICE_INVALID; + } + + virtex2_info = malloc(sizeof(virtex2_pld_device_t)); + pld_device->driver_priv = virtex2_info; + + virtex2_info->chain_pos = strtoul(args[1], NULL, 0); + + return ERROR_OK; +} diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index fa203e7..335a4cd 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1,2107 +1,2107 @@ -/***************************************************************************
- * 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 "gdb_server.h"
-
-#include "server.h"
-#include "log.h"
-#include "binarybuffer.h"
-#include "jtag.h"
-#include "breakpoints.h"
-#include "flash.h"
-#include "target_request.h"
-#include "configuration.h"
-
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-#if 0
-#define _DEBUG_GDB_IO_
-#endif
-
-static unsigned short gdb_port;
-static const char *DIGITS = "0123456789abcdef";
-
-static void gdb_log_callback(void *priv, const char *file, int line,
- const char *function, const char *format, va_list args);
-
-enum gdb_detach_mode
-{
- GDB_DETACH_RESUME,
- GDB_DETACH_RESET,
- GDB_DETACH_HALT,
- GDB_DETACH_NOTHING
-};
-
-/* target behaviour on gdb detach */
-enum gdb_detach_mode detach_mode = GDB_DETACH_RESUME;
-
-/* set if we are sending a memory map to gdb
- * via qXfer:memory-map:read packet */
-int gdb_use_memory_map = 0;
-int gdb_flash_program = 0;
-
-/* if set, data aborts cause an error to be reported in memory read packets
- * see the code in gdb_read_memory_packet() for further explanations */
-int gdb_report_data_abort = 0;
-
-int gdb_last_signal(target_t *target)
-{
- switch (target->debug_reason)
- {
- case DBG_REASON_DBGRQ:
- return 0x2; /* SIGINT */
- case DBG_REASON_BREAKPOINT:
- case DBG_REASON_WATCHPOINT:
- case DBG_REASON_WPTANDBKPT:
- return 0x05; /* SIGTRAP */
- case DBG_REASON_SINGLESTEP:
- return 0x05; /* SIGTRAP */
- case DBG_REASON_NOTHALTED:
- return 0x0; /* no signal... shouldn't happen */
- default:
- ERROR("BUG: undefined debug reason");
- exit(-1);
- }
-}
-
-int gdb_get_char(connection_t *connection, int* next_char)
-{
- gdb_connection_t *gdb_con = connection->priv;
-
-#ifdef _DEBUG_GDB_IO_
- char *debug_buffer;
-#endif
-
- if (gdb_con->buf_cnt-- > 0)
- {
- *next_char = *(gdb_con->buf_p++);
- if (gdb_con->buf_cnt > 0)
- connection->input_pending = 1;
- else
- connection->input_pending = 0;
-
-#ifdef _DEBUG_GDB_IO_
- DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);
-#endif
-
- return ERROR_OK;
- }
-
- for (;;)
- {
-#ifndef _WIN32
- /* a non-blocking socket will block if there is 0 bytes available on the socket,
- * but return with as many bytes as are available immediately
- */
- struct timeval tv;
- fd_set read_fds;
-
- FD_ZERO(&read_fds);
- FD_SET(connection->fd, &read_fds);
-
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- if (select(connection->fd + 1, &read_fds, NULL, NULL, &tv) == 0)
- {
- /* This can typically be because a "monitor" command took too long
- * before printing any progress messages
- */
- return ERROR_GDB_TIMEOUT;
- }
-#endif
- gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE);
- if (gdb_con->buf_cnt > 0)
- {
- break;
- }
- if (gdb_con->buf_cnt == 0)
- {
- gdb_con->closed = 1;
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
-#ifdef _WIN32
- errno = WSAGetLastError();
-
- switch(errno)
- {
- case WSAEWOULDBLOCK:
- usleep(1000);
- break;
- case WSAECONNABORTED:
- return ERROR_SERVER_REMOTE_CLOSED;
- case WSAECONNRESET:
- return ERROR_SERVER_REMOTE_CLOSED;
- default:
- ERROR("read: %d", errno);
- exit(-1);
- }
-#else
- switch(errno)
- {
- case EAGAIN:
- usleep(1000);
- break;
- case ECONNABORTED:
- return ERROR_SERVER_REMOTE_CLOSED;
- case ECONNRESET:
- return ERROR_SERVER_REMOTE_CLOSED;
- default:
- ERROR("read: %s", strerror(errno));
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-#endif
- }
-
-#ifdef _DEBUG_GDB_IO_
- debug_buffer = malloc(gdb_con->buf_cnt + 1);
- memcpy(debug_buffer, gdb_con->buffer, gdb_con->buf_cnt);
- debug_buffer[gdb_con->buf_cnt] = 0;
- DEBUG("received '%s'", debug_buffer);
- free(debug_buffer);
-#endif
-
- gdb_con->buf_p = gdb_con->buffer;
- gdb_con->buf_cnt--;
- *next_char = *(gdb_con->buf_p++);
- if (gdb_con->buf_cnt > 0)
- connection->input_pending = 1;
- else
- connection->input_pending = 0;
-#ifdef _DEBUG_GDB_IO_
- DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);
-#endif
-
- return ERROR_OK;
-}
-
-int gdb_putback_char(connection_t *connection, int last_char)
-{
- gdb_connection_t *gdb_con = connection->priv;
-
- if (gdb_con->buf_p > gdb_con->buffer)
- {
- *(--gdb_con->buf_p) = last_char;
- gdb_con->buf_cnt++;
- }
- else
- {
- ERROR("BUG: couldn't put character back");
- }
-
- return ERROR_OK;
-}
-
-/* The only way we can detect that the socket is closed is the first time
- * we write to it, we will fail. Subsequent write operations will
- * succeed. Shudder! */
-int gdb_write(connection_t *connection, void *data, int len)
-{
- gdb_connection_t *gdb_con = connection->priv;
- if (gdb_con->closed)
- return ERROR_SERVER_REMOTE_CLOSED;
-
- if (write_socket(connection->fd, data, len) == len)
- {
- return ERROR_OK;
- }
- gdb_con->closed = 1;
- return ERROR_SERVER_REMOTE_CLOSED;
-}
-
-int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
-{
- int i;
- unsigned char my_checksum = 0;
-#ifdef _DEBUG_GDB_IO_
- char *debug_buffer;
-#endif
- int reply;
- int retval;
- gdb_connection_t *gdb_con = connection->priv;
-
- for (i = 0; i < len; i++)
- my_checksum += buffer[i];
-
- while (1)
- {
-#ifdef _DEBUG_GDB_IO_
- debug_buffer = malloc(len + 1);
- memcpy(debug_buffer, buffer, len);
- debug_buffer[len] = 0;
- DEBUG("sending packet '$%s#%2.2x'", debug_buffer, my_checksum);
- free(debug_buffer);
-#endif
-#if 0
- char checksum[3];
- gdb_write(connection, "$", 1);
- if (len > 0)
- gdb_write(connection, buffer, len);
- gdb_write(connection, "#", 1);
-
- snprintf(checksum, 3, "%2.2x", my_checksum);
-
- gdb_write(connection, checksum, 2);
-#else
- void *allocated = NULL;
- char stackAlloc[1024];
- char *t = stackAlloc;
- int totalLen = 1 + len + 1 + 2;
- if (totalLen > sizeof(stackAlloc))
- {
- allocated = malloc(totalLen);
- t = allocated;
- if (allocated == NULL)
- {
- ERROR("Ran out of memory trying to reply packet %d\n", totalLen);
- exit(-1);
- }
- }
- t[0] = '$';
- memcpy(t + 1, buffer, len);
- t[1 + len] = '#';
- t[1 + len + 1] = DIGITS[(my_checksum >> 4) & 0xf];
- t[1 + len + 2] = DIGITS[my_checksum & 0xf];
-
- gdb_write(connection, t, totalLen);
-
- if (allocated)
- {
- free(allocated);
- }
-#endif
- if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)
- return retval;
-
- if (reply == '+')
- break;
- else if (reply == '-')
- {
- /* Stop sending output packets for now */
- log_remove_callback(gdb_log_callback, connection);
- WARNING("negative reply, retrying");
- }
- else if (reply == 0x3)
- {
- gdb_con->ctrl_c = 1;
- if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)
- return retval;
- if (reply == '+')
- break;
- else if (reply == '-')
- {
- /* Stop sending output packets for now */
- log_remove_callback(gdb_log_callback, connection);
- WARNING("negative reply, retrying");
- }
- else
- {
- ERROR("unknown character 0x%2.2x in reply, dropping connection", reply);
- return ERROR_SERVER_REMOTE_CLOSED;
- }
- }
- else
- {
- ERROR("unknown character 0x%2.2x in reply, dropping connection", reply);
- return ERROR_SERVER_REMOTE_CLOSED;
- }
- }
- if (gdb_con->closed)
- return ERROR_SERVER_REMOTE_CLOSED;
-
- return ERROR_OK;
-}
-
-int gdb_put_packet(connection_t *connection, char *buffer, int len)
-{
- gdb_connection_t *gdb_con = connection->priv;
- gdb_con->busy = 1;
- int retval = gdb_put_packet_inner(connection, buffer, len);
- gdb_con->busy = 0;
- return retval;
-}
-
-int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)
-{
- int character;
- int count = 0;
- int retval;
- char checksum[3];
- unsigned char my_checksum = 0;
- gdb_connection_t *gdb_con = connection->priv;
-
- while (1)
- {
- do
- {
- if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
- return retval;
-
-#ifdef _DEBUG_GDB_IO_
- DEBUG("character: '%c'", character);
-#endif
-
- switch (character)
- {
- case '$':
- break;
- case '+':
- WARNING("acknowledgment received, but no packet pending");
- break;
- case '-':
- WARNING("negative acknowledgment, but no packet pending");
- break;
- case 0x3:
- gdb_con->ctrl_c = 1;
- *len = 0;
- return ERROR_OK;
- default:
- WARNING("ignoring character 0x%x", character);
- break;
- }
- } while (character != '$');
-
- my_checksum = 0;
-
- count = 0;
- gdb_connection_t *gdb_con = connection->priv;
- for (;;)
- {
- /* The common case is that we have an entire packet with no escape chars.
- * We need to leave at least 2 bytes in the buffer to have
- * gdb_get_char() update various bits and bobs correctly.
- */
- if ((gdb_con->buf_cnt > 2) && ((gdb_con->buf_cnt+count) < *len))
- {
- /* The compiler will struggle a bit with constant propagation and
- * aliasing, so we help it by showing that these values do not
- * change inside the loop
- */
- int i;
- char *buf = gdb_con->buf_p;
- int run = gdb_con->buf_cnt - 2;
- i = 0;
- int done = 0;
- while (i < run)
- {
- character = *buf++;
- i++;
- if (character == '#')
- {
- /* Danger! character can be '#' when esc is
- * used so we need an explicit boolean for done here.
- */
- done = 1;
- break;
- }
-
- if (character == '}')
- {
- /* data transmitted in binary mode (X packet)
- * uses 0x7d as escape character */
- my_checksum += character & 0xff;
- character = *buf++;
- i++;
- my_checksum += character & 0xff;
- buffer[count++] = (character ^ 0x20) & 0xff;
- } else
- {
- my_checksum += character & 0xff;
- buffer[count++] = character & 0xff;
- }
- }
- gdb_con->buf_p += i;
- gdb_con->buf_cnt -= i;
- if (done)
- break;
- }
- if (count > *len)
- {
- ERROR("packet buffer too small");
- return ERROR_GDB_BUFFER_TOO_SMALL;
- }
-
- if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
- return retval;
-
- if (character == '#')
- break;
-
- if (character == '}')
- {
- /* data transmitted in binary mode (X packet)
- * uses 0x7d as escape character */
- my_checksum += character & 0xff;
- if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
- return retval;
- my_checksum += character & 0xff;
- buffer[count++] = (character ^ 0x20) & 0xff;
- }
- else
- {
- my_checksum += character & 0xff;
- buffer[count++] = character & 0xff;
- }
-
- }
-
- *len = count;
-
- if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
- return retval;
- checksum[0] = character;
- if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
- return retval;
- checksum[1] = character;
- checksum[2] = 0;
-
- if (my_checksum == strtoul(checksum, NULL, 16))
- {
- gdb_write(connection, "+", 1);
- break;
- }
-
- WARNING("checksum error, requesting retransmission");
- gdb_write(connection, "-", 1);
- }
- if (gdb_con->closed)
- return ERROR_SERVER_REMOTE_CLOSED;
-
- return ERROR_OK;
-}
-
-int gdb_get_packet(connection_t *connection, char *buffer, int *len)
-{
- gdb_connection_t *gdb_con = connection->priv;
- gdb_con->busy = 1;
- int retval = gdb_get_packet_inner(connection, buffer, len);
- gdb_con->busy = 0;
- return retval;
-}
-
-int gdb_output_con(connection_t *connection, char* line)
-{
- char *hex_buffer;
- int i, bin_size;
-
- bin_size = strlen(line);
-
- hex_buffer = malloc(bin_size*2 + 4);
-
- hex_buffer[0] = 'O';
- for (i=0; i<bin_size; i++)
- snprintf(hex_buffer + 1 + i*2, 3, "%2.2x", line[i]);
- hex_buffer[bin_size*2+1] = '0';
- hex_buffer[bin_size*2+2] = 'a';
- hex_buffer[bin_size*2+3] = 0x0;
-
- gdb_put_packet(connection, hex_buffer, bin_size*2 + 3);
-
- free(hex_buffer);
- return ERROR_OK;
-}
-
-int gdb_output(struct command_context_s *context, char* line)
-{
- /* this will be dumped to the log and also sent as an O packet if possible */
- USER(line);
- return ERROR_OK;
-}
-
-int gdb_program_handler(struct target_s *target, enum target_event event, void *priv)
-{
- FILE *script;
- struct command_context_s *cmd_ctx = priv;
-
- if (target->gdb_program_script)
- {
- script = open_file_from_path(cmd_ctx, target->gdb_program_script, "r");
- if (!script)
- {
- ERROR("couldn't open script file %s", target->gdb_program_script);
- return ERROR_OK;
- }
-
- INFO("executing gdb_program script '%s'", target->gdb_program_script);
- command_run_file(cmd_ctx, script, COMMAND_EXEC);
- fclose(script);
-
- jtag_execute_queue();
- }
-
- return ERROR_OK;
-}
-
-int gdb_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv)
-{
- connection_t *connection = priv;
- gdb_connection_t *gdb_connection = connection->priv;
- char sig_reply[4];
- int signal;
-
- switch (event)
- {
- case TARGET_EVENT_HALTED:
- /* In the GDB protocol when we are stepping or coninuing execution,
- * we have a lingering reply. Upon receiving a halted event
- * when we have that lingering packet, we reply to the original
- * step or continue packet.
- *
- * Executing monitor commands can bring the target in and
- * out of the running state so we'll see lots of TARGET_EVENT_XXX
- * that are to be ignored.
- */
- if (gdb_connection->frontend_state == TARGET_RUNNING)
- {
- /* stop forwarding log packets! */
- log_remove_callback(gdb_log_callback, connection);
-
- if (gdb_connection->ctrl_c)
- {
- signal = 0x2;
- gdb_connection->ctrl_c = 0;
- }
- else
- {
- signal = gdb_last_signal(target);
- }
-
- snprintf(sig_reply, 4, "T%2.2x", signal);
- gdb_put_packet(connection, sig_reply, 3);
- gdb_connection->frontend_state = TARGET_HALTED;
- }
- break;
- case TARGET_EVENT_GDB_PROGRAM:
- gdb_program_handler(target, event, connection->cmd_ctx);
- break;
- default:
- break;
- }
-
- return ERROR_OK;
-}
-
-int gdb_new_connection(connection_t *connection)
-{
- gdb_connection_t *gdb_connection = malloc(sizeof(gdb_connection_t));
- gdb_service_t *gdb_service = connection->service->priv;
- int retval;
- int initial_ack;
-
- connection->priv = gdb_connection;
-
- /* initialize gdb connection information */
- gdb_connection->buf_p = gdb_connection->buffer;
- gdb_connection->buf_cnt = 0;
- gdb_connection->ctrl_c = 0;
- gdb_connection->frontend_state = TARGET_HALTED;
- gdb_connection->vflash_image = NULL;
- gdb_connection->closed = 0;
- gdb_connection->busy = 0;
-
- /* output goes through gdb connection */
- command_set_output_handler(connection->cmd_ctx, gdb_output, connection);
-
- /* register callback to be informed about target events */
- target_register_event_callback(gdb_target_callback_event_handler, connection);
-
- /* a gdb session just attached, put the target in halt mode */
- if (((retval = gdb_service->target->type->halt(gdb_service->target)) != ERROR_OK) &&
- (retval != ERROR_TARGET_ALREADY_HALTED))
- {
- ERROR("error(%d) when trying to halt target, falling back to \"reset halt\"", retval);
- command_run_line(connection->cmd_ctx, "reset halt");
- }
-
- /* This will time out after 1 second */
- command_run_line(connection->cmd_ctx, "wait_halt 1");
-
- /* remove the initial ACK from the incoming buffer */
- if ((retval = gdb_get_char(connection, &initial_ack)) != ERROR_OK)
- return retval;
-
- if (initial_ack != '+')
- gdb_putback_char(connection, initial_ack);
-
- return ERROR_OK;
-}
-
-int gdb_connection_closed(connection_t *connection)
-{
- gdb_service_t *gdb_service = connection->service->priv;
- gdb_connection_t *gdb_connection = connection->priv;
-
- /* see if an image built with vFlash commands is left */
- if (gdb_connection->vflash_image)
- {
- image_close(gdb_connection->vflash_image);
- free(gdb_connection->vflash_image);
- gdb_connection->vflash_image = NULL;
- }
-
- /* if this connection registered a debug-message receiver delete it */
- delete_debug_msg_receiver(connection->cmd_ctx, gdb_service->target);
-
- if (connection->priv)
- {
- free(connection->priv);
- connection->priv = NULL;
- }
- else
- {
- ERROR("BUG: connection->priv == NULL");
- }
-
- target_unregister_event_callback(gdb_target_callback_event_handler, connection);
- log_remove_callback(gdb_log_callback, 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];
- int signal;
-
- signal = gdb_last_signal(target);
-
- snprintf(sig_reply, 4, "S%2.2x", signal);
- gdb_put_packet(connection, sig_reply, 3);
-
- return ERROR_OK;
-}
-
-/* Convert register to string of bits. NB! The # of bits in the
- * register might be non-divisible by 8(a byte), in which
- * case an entire byte is shown. */
-void gdb_str_to_target(target_t *target, char *tstr, reg_t *reg)
-{
- int i;
-
- u8 *buf;
- int buf_len;
- buf = reg->value;
- buf_len = CEIL(reg->size, 8);
-
- if (target->endianness == TARGET_LITTLE_ENDIAN)
- {
- for (i = 0; i < buf_len; i++)
- {
- tstr[i*2] = DIGITS[(buf[i]>>4) & 0xf];
- tstr[i*2+1] = DIGITS[buf[i]&0xf];
- }
- }
- else
- {
- for (i = 0; i < buf_len; i++)
- {
- tstr[(buf_len-1-i)*2] = DIGITS[(buf[i]>>4)&0xf];
- tstr[(buf_len-1-i)*2+1] = DIGITS[buf[i]&0xf];
- }
- }
-}
-
-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;
- int retval;
- int reg_packet_size = 0;
- char *reg_packet;
- char *reg_packet_p;
- int i;
-
-#ifdef _DEBUG_GDB_IO_
- DEBUG("-");
-#endif
-
- if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK)
- {
- switch (retval)
- {
- case ERROR_TARGET_NOT_HALTED:
- 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);
- }
- }
-
- for (i = 0; i < reg_list_size; i++)
- {
- reg_packet_size += reg_list[i]->size;
- }
-
- reg_packet = malloc(CEIL(reg_packet_size, 8) * 2);
- reg_packet_p = reg_packet;
-
- for (i = 0; i < reg_list_size; i++)
- {
- gdb_str_to_target(target, reg_packet_p, reg_list[i]);
- reg_packet_p += CEIL(reg_list[i]->size, 8) * 2;
- }
-
-#ifdef _DEBUG_GDB_IO_
- {
- char *reg_packet_p;
- reg_packet_p = strndup(reg_packet, CEIL(reg_packet_size, 8) * 2);
- DEBUG("reg_packet: %s", reg_packet_p);
- free(reg_packet_p);
- }
-#endif
-
- gdb_put_packet(connection, reg_packet, CEIL(reg_packet_size, 8) * 2);
- free(reg_packet);
-
- free(reg_list);
-
- return ERROR_OK;
-}
-
-int gdb_set_registers_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
- int i;
- reg_t **reg_list;
- int reg_list_size;
- int retval;
- char *packet_p;
-
-#ifdef _DEBUG_GDB_IO_
- DEBUG("-");
-#endif
-
- /* skip command character */
- packet++;
- packet_size--;
-
- if (packet_size % 2)
- {
- 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, ®_list, ®_list_size)) != ERROR_OK)
- {
- switch (retval)
- {
- case ERROR_TARGET_NOT_HALTED:
- 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);
- }
- }
-
- packet_p = packet;
- for (i = 0; i < reg_list_size; i++)
- {
- 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;
-}
-
-int gdb_get_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
- char *reg_packet;
- int reg_num = strtoul(packet + 1, NULL, 16);
- reg_t **reg_list;
- int reg_list_size;
- int retval;
-
-#ifdef _DEBUG_GDB_IO_
- DEBUG("-");
-#endif
-
- if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK)
- {
- switch (retval)
- {
- case ERROR_TARGET_NOT_HALTED:
- 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);
- }
- }
-
- if (reg_list_size <= reg_num)
- {
- ERROR("gdb requested a non-existing register");
- exit(-1);
- }
-
- reg_packet = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);
-
- gdb_str_to_target(target, reg_packet, reg_list[reg_num]);
-
- gdb_put_packet(connection, reg_packet, CEIL(reg_list[reg_num]->size, 8) * 2);
-
- free(reg_list);
- free(reg_packet);
-
- return ERROR_OK;
-}
-
-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, ®_list, ®_list_size)) != ERROR_OK)
- {
- switch (retval)
- {
- case ERROR_TARGET_NOT_HALTED:
- 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);
- }
- }
-
- if (reg_list_size < reg_num)
- {
- ERROR("gdb requested a non-existing register");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- if (*separator != '=')
- {
- ERROR("GDB 'set register packet', but no '=' following the register number");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- /* 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;
-}
-
-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;
- 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:
- /* This could be that the target reset itself. */
- ERROR("unexpected error %i. Dropping connection.", retval);
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- return ERROR_OK;
-}
-
-/* We don't have to worry about the default 2 second timeout for GDB packets,
- * because GDB breaks up large memory reads into smaller reads.
- *
- * 8191 bytes by the looks of it. Why 8191 bytes instead of 8192?????
- */
-int gdb_read_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
- char *separator;
- u32 addr = 0;
- u32 len = 0;
-
- u8 *buffer;
- char *hex_buffer;
-
- int retval = ERROR_OK;
-
- /* skip command character */
- packet++;
-
- addr = strtoul(packet, &separator, 16);
-
- if (*separator != ',')
- {
- ERROR("incomplete read memory packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- len = strtoul(separator+1, NULL, 16);
-
- buffer = malloc(len);
-
- DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);
-
- retval = target_read_buffer(target, addr, len, buffer);
-
- if ((retval == ERROR_TARGET_DATA_ABORT) && (!gdb_report_data_abort))
- {
- /* TODO : Here we have to lie and send back all zero's lest stack traces won't work.
- * At some point this might be fixed in GDB, in which case this code can be removed.
- *
- * OpenOCD developers are acutely aware of this problem, but there is nothing
- * gained by involving the user in this problem that hopefully will get resolved
- * eventually
- *
- * http://sourceware.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gdb&pr=2395
- *
- * For now, the default is to fix up things to make current GDB versions work.
- * This can be overwritten using the gdb_report_data_abort <'enable'|'disable'> command.
- */
- memset(buffer, 0, len);
- retval = ERROR_OK;
- }
-
- if (retval == ERROR_OK)
- {
- hex_buffer = malloc(len * 2 + 1);
-
- int i;
- for (i = 0; i < len; i++)
- {
- u8 t = buffer[i];
- hex_buffer[2 * i] = DIGITS[(t >> 4) & 0xf];
- hex_buffer[2 * i + 1] = DIGITS[t & 0xf];
- }
-
- gdb_put_packet(connection, hex_buffer, len * 2);
-
- free(hex_buffer);
- }
- else
- {
- retval = gdb_memory_packet_error(connection, retval);
- }
-
- free(buffer);
-
- return retval;
-}
-
-int gdb_write_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
- char *separator;
- u32 addr = 0;
- u32 len = 0;
-
- u8 *buffer;
-
- int i;
- int retval;
-
- /* skip command character */
- packet++;
-
- addr = strtoul(packet, &separator, 16);
-
- if (*separator != ',')
- {
- ERROR("incomplete write memory packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- len = strtoul(separator+1, &separator, 16);
-
- if (*(separator++) != ':')
- {
- ERROR("incomplete write memory packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- buffer = malloc(len);
-
- DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);
-
- for (i=0; i<len; i++)
- {
- u32 tmp;
- sscanf(separator + 2*i, "%2x", &tmp);
- buffer[i] = tmp;
- }
-
- retval = target_write_buffer(target, addr, len, buffer);
-
- 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;
-}
-
-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;
-
- int retval;
-
- /* skip command character */
- packet++;
-
- addr = strtoul(packet, &separator, 16);
-
- if (*separator != ',')
- {
- ERROR("incomplete write memory binary packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- len = strtoul(separator+1, &separator, 16);
-
- if (*(separator++) != ':')
- {
- ERROR("incomplete write memory binary packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- retval = ERROR_OK;
- if (len)
- {
- DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);
-
- retval = target_write_buffer(target, addr, len, (u8*)separator);
- }
-
- 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)
-{
- int current = 0;
- u32 address = 0x0;
-
- DEBUG("-");
-
- if (packet_size > 1)
- {
- packet[packet_size] = 0;
- address = strtoul(packet + 1, NULL, 16);
- }
- else
- {
- current = 1;
- }
-
- if (packet[0] == 'c')
- {
- DEBUG("continue");
- target->type->resume(target, current, address, 0, 0); /* resume at current address, don't handle breakpoints, not debugging */
- }
- else if (packet[0] == 's')
- {
- DEBUG("step");
- target->type->step(target, current, address, 0); /* step at current or address, don't handle breakpoints */
- }
-}
-
-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 = BKPT_SOFT /* dummy init to avoid warning */;
- enum watchpoint_rw wp_type;
- u32 address;
- u32 size;
- char *separator;
- int retval;
-
- DEBUG("-");
-
- type = strtoul(packet + 1, &separator, 16);
-
- if (type == 0) /* memory breakpoint */
- bp_type = BKPT_SOFT;
- else if (type == 1) /* hardware breakpoint */
- bp_type = BKPT_HARD;
- else if (type == 2) /* write watchpoint */
- wp_type = WPT_WRITE;
- else if (type == 3) /* read watchpoint */
- wp_type = WPT_READ;
- else if (type == 4) /* access watchpoint */
- wp_type = WPT_ACCESS;
-
- if (*separator != ',')
- {
- ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- address = strtoul(separator+1, &separator, 16);
-
- if (*separator != ',')
- {
- ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- size = strtoul(separator+1, &separator, 16);
-
- switch (type)
- {
- case 0:
- case 1:
- if (packet[0] == 'Z')
- {
- if ((retval = breakpoint_add(target, address, size, bp_type)) != ERROR_OK)
- {
- 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);
- }
- break;
- case 2:
- case 3:
- case 4:
- {
- if (packet[0] == 'Z')
- {
- 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);
- }
- break;
- }
- default:
- break;
- }
-
- return ERROR_OK;
-}
-
-/* print out a string and allocate more space as needed, mainly used for XML at this point */
-void xml_printf(int *retval, char **xml, int *pos, int *size, const char *fmt, ...)
-{
- if (*retval != ERROR_OK)
- {
- return;
- }
- int first = 1;
-
- for (;;)
- {
- if ((*xml == NULL) || (!first))
- {
- /* start by 0 to exercise all the code paths.
- * Need minimum 2 bytes to fit 1 char and 0 terminator. */
-
- *size = *size * 2 + 2;
- char *t = *xml;
- *xml = realloc(*xml, *size);
- if (*xml == NULL)
- {
- if (t)
- free(t);
- *retval = ERROR_SERVER_REMOTE_CLOSED;
- return;
- }
- }
-
- va_list ap;
- int ret;
- va_start(ap, fmt);
- ret = vsnprintf(*xml + *pos, *size - *pos, fmt, ap);
- va_end(ap);
- if ((ret > 0) && ((ret + 1) < *size - *pos))
- {
- *pos += ret;
- return;
- }
- /* there was just enough or not enough space, allocate more. */
- first = 0;
- }
-}
-
-static int decode_xfer_read(char *buf, char **annex, int *ofs, unsigned int *len)
-{
- char *separator;
-
- /* Extract and NUL-terminate the annex. */
- *annex = buf;
- while (*buf && *buf != ':')
- buf++;
- if (*buf == '\0')
- return -1;
- *buf++ = 0;
-
- /* After the read marker and annex, qXfer looks like a
- * traditional 'm' packet. */
-
- *ofs = strtoul(buf, &separator, 16);
-
- if (*separator != ',')
- return -1;
-
- *len = strtoul(separator+1, NULL, 16);
-
- return 0;
-}
-
-int gdb_calc_blocksize(flash_bank_t *bank)
-{
- int i;
- int block_size = 0xffffffff;
-
- /* loop through all sectors and return smallest sector size */
-
- for (i = 0; i < bank->num_sectors; i++)
- {
- if (bank->sectors[i].size < block_size)
- block_size = bank->sectors[i].size;
- }
-
- return block_size;
-}
-
-int gdb_query_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
- command_context_t *cmd_ctx = connection->cmd_ctx;
-
- if (strstr(packet, "qRcmd,"))
- {
- if (packet_size > 6)
- {
- char *cmd;
- int i;
- cmd = malloc((packet_size - 6)/2 + 1);
- for (i=0; i < (packet_size - 6)/2; i++)
- {
- u32 tmp;
- sscanf(packet + 6 + 2*i, "%2x", &tmp);
- cmd[i] = tmp;
- }
- cmd[(packet_size - 6)/2] = 0x0;
-
- /* We want to print all debug output to GDB connection */
- log_add_callback(gdb_log_callback, connection);
- target_call_timer_callbacks();
- command_run_line(cmd_ctx, cmd);
- free(cmd);
- }
- gdb_put_packet(connection, "OK", 2);
- return ERROR_OK;
- }
- else if (strstr(packet, "qCRC:"))
- {
- if (packet_size > 5)
- {
- int retval;
- char gdb_reply[10];
- char *separator;
- u32 checksum;
- u32 addr = 0;
- u32 len = 0;
-
- /* skip command character */
- packet += 5;
-
- addr = strtoul(packet, &separator, 16);
-
- if (*separator != ',')
- {
- ERROR("incomplete read memory packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- len = strtoul(separator + 1, NULL, 16);
-
- retval = target_checksum_memory(target, addr, len, &checksum);
-
- if (retval == ERROR_OK)
- {
- snprintf(gdb_reply, 10, "C%8.8x", checksum);
- gdb_put_packet(connection, gdb_reply, 9);
- }
- else
- {
- if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)
- return retval;
- }
-
- return ERROR_OK;
- }
- }
- else if (strstr(packet, "qSupported"))
- {
- /* we currently support packet size and qXfer:memory-map:read (if enabled)
- * disable qXfer:features:read for the moment */
- int retval = ERROR_OK;
- char *buffer = NULL;
- int pos = 0;
- int size = 0;
-
- xml_printf(&retval, &buffer, &pos, &size,
- "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-",
- (GDB_BUFFER_SIZE - 1), gdb_use_memory_map == 1 ? '+' : '-');
-
- if (retval != ERROR_OK)
- {
- gdb_send_error(connection, 01);
- return ERROR_OK;
- }
-
- gdb_put_packet(connection, buffer, strlen(buffer));
- free(buffer);
-
- return ERROR_OK;
- }
- else if (strstr(packet, "qXfer:memory-map:read::"))
- {
- /* We get away with only specifying flash here. Regions that are not
- * specified are treated as if we provided no memory map(if not we
- * could detect the holes and mark them as RAM).
- * Normally we only execute this code once, but no big deal if we
- * have to regenerate it a couple of times. */
-
- flash_bank_t *p;
- char *xml = NULL;
- int size = 0;
- int pos = 0;
- int retval = ERROR_OK;
-
- int offset;
- int length;
- char *separator;
- int blocksize;
-
- /* skip command character */
- packet += 23;
-
- offset = strtoul(packet, &separator, 16);
- length = strtoul(separator + 1, &separator, 16);
-
- xml_printf(&retval, &xml, &pos, &size, "<memory-map>\n");
-
- int i = 0;
- for (;;)
- {
- p = get_flash_bank_by_num(i);
- if (p == NULL)
- break;
-
- /* if device has uneven sector sizes, eg. str7, lpc
- * we pass the smallest sector size to gdb memory map */
- blocksize = gdb_calc_blocksize(p);
-
- xml_printf(&retval, &xml, &pos, &size, "<memory type=\"flash\" start=\"0x%x\" length=\"0x%x\">\n" \
- "<property name=\"blocksize\">0x%x</property>\n" \
- "</memory>\n", \
- p->base, p->size, blocksize);
- i++;
- }
-
- xml_printf(&retval, &xml, &pos, &size, "</memory-map>\n");
-
- if (retval != ERROR_OK)
- {
- gdb_send_error(connection, retval);
- return retval;
- }
-
- if (offset + length > pos)
- {
- length = pos - offset;
- }
-
- char *t = malloc(length + 1);
- t[0] = 'l';
- memcpy(t + 1, xml + offset, length);
- gdb_put_packet(connection, t, length + 1);
-
- free(t);
- free(xml);
- return ERROR_OK;
- }
- else if (strstr(packet, "qXfer:features:read:"))
- {
- char *xml = NULL;
- int size = 0;
- int pos = 0;
- int retval = ERROR_OK;
-
- int offset;
- unsigned int length;
- char *annex;
-
- /* skip command character */
- packet += 20;
-
- if (decode_xfer_read(packet, &annex, &offset, &length) < 0)
- {
- gdb_send_error(connection, 01);
- return ERROR_OK;
- }
-
- if (strcmp(annex, "target.xml") != 0)
- {
- gdb_send_error(connection, 01);
- return ERROR_OK;
- }
-
- xml_printf(&retval, &xml, &pos, &size, \
- "l<target version=\"1.0\">\n<architecture>arm</architecture>\n</target>\n");
-
- if (retval != ERROR_OK)
- {
- gdb_send_error(connection, retval);
- return retval;
- }
-
- gdb_put_packet(connection, xml, strlen(xml) + 1);
-
- free(xml);
- return ERROR_OK;
- }
-
- gdb_put_packet(connection, "", 0);
- return ERROR_OK;
-}
-
-int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
- gdb_connection_t *gdb_connection = connection->priv;
- gdb_service_t *gdb_service = connection->service->priv;
- int result;
-
- /* if flash programming disabled - send a empty reply */
-
- if (gdb_flash_program == 0)
- {
- gdb_put_packet(connection, "", 0);
- return ERROR_OK;
- }
-
- if (strstr(packet, "vFlashErase:"))
- {
- unsigned long addr;
- unsigned long length;
-
- char *parse = packet + 12;
- if (*parse == '\0')
- {
- ERROR("incomplete vFlashErase packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- addr = strtoul(parse, &parse, 16);
-
- if (*(parse++) != ',' || *parse == '\0')
- {
- ERROR("incomplete vFlashErase packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- length = strtoul(parse, &parse, 16);
-
- if (*parse != '\0')
- {
- ERROR("incomplete vFlashErase packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- /* assume all sectors need erasing - stops any problems
- * when flash_write is called multiple times */
- flash_set_dirty();
-
- /* perform any target specific operations before the erase */
- target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_PROGRAM);
-
- /* perform erase */
- if ((result = flash_erase_address_range(gdb_service->target, addr, length)) != ERROR_OK)
- {
- /* GDB doesn't evaluate the actual error number returned,
- * treat a failed erase as an I/O error
- */
- gdb_send_error(connection, EIO);
- ERROR("flash_erase returned %i", result);
- }
- else
- gdb_put_packet(connection, "OK", 2);
-
- return ERROR_OK;
- }
-
- if (strstr(packet, "vFlashWrite:"))
- {
- unsigned long addr;
- unsigned long length;
- char *parse = packet + 12;
-
- if (*parse == '\0')
- {
- ERROR("incomplete vFlashErase packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
- addr = strtoul(parse, &parse, 16);
- if (*(parse++) != ':')
- {
- ERROR("incomplete vFlashErase packet received, dropping connection");
- return ERROR_SERVER_REMOTE_CLOSED;
- }
- length = packet_size - (parse - packet);
-
- /* create a new image if there isn't already one */
- if (gdb_connection->vflash_image == NULL)
- {
- gdb_connection->vflash_image = malloc(sizeof(image_t));
- image_open(gdb_connection->vflash_image, "", "build");
- }
-
- /* create new section with content from packet buffer */
- image_add_section(gdb_connection->vflash_image, addr, length, 0x0, (u8*)parse);
-
- gdb_put_packet(connection, "OK", 2);
-
- return ERROR_OK;
- }
-
- if (!strcmp(packet, "vFlashDone"))
- {
- u32 written;
-
- /* process the flashing buffer. No need to erase as GDB
- * always issues a vFlashErase first. */
- if ((result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0)) != ERROR_OK)
- {
- if (result == ERROR_FLASH_DST_OUT_OF_BANK)
- gdb_put_packet(connection, "E.memtype", 9);
- else
- gdb_send_error(connection, EIO);
- }
- else
- {
- DEBUG("wrote %u bytes from vFlash image to flash", written);
- gdb_put_packet(connection, "OK", 2);
- }
-
- image_close(gdb_connection->vflash_image);
- free(gdb_connection->vflash_image);
- gdb_connection->vflash_image = NULL;
-
- return ERROR_OK;
- }
-
- gdb_put_packet(connection, "", 0);
- return ERROR_OK;
-}
-
-int gdb_detach(connection_t *connection, target_t *target)
-{
- switch( detach_mode )
- {
- case GDB_DETACH_RESUME:
- target->type->resume(target, 1, 0, 1, 0);
- break;
-
- case GDB_DETACH_RESET:
- target_process_reset(connection->cmd_ctx);
- break;
-
- case GDB_DETACH_HALT:
- target->type->halt(target);
- break;
-
- case GDB_DETACH_NOTHING:
- break;
- }
-
- gdb_put_packet(connection, "OK", 2);
-
- return ERROR_OK;
-}
-
-static void gdb_log_callback(void *priv, const char *file, int line,
- const char *function, const char *format, va_list args)
-{
- connection_t *connection = priv;
- gdb_connection_t *gdb_con = connection->priv;
-
- if (gdb_con->busy)
- {
- /* do not reply this using the O packet */
- return;
- }
-
- char *t = alloc_printf(format, args);
- if (t == NULL)
- return;
-
- gdb_output_con(connection, t);
-
- free(t);
-}
-
-int gdb_input_inner(connection_t *connection)
-{
- gdb_service_t *gdb_service = connection->service->priv;
- target_t *target = gdb_service->target;
- char packet[GDB_BUFFER_SIZE];
- int packet_size;
- int retval;
- gdb_connection_t *gdb_con = connection->priv;
- static int extended_protocol = 0;
-
- /* drain input buffer */
- do
- {
- packet_size = GDB_BUFFER_SIZE-1;
- if ((retval = gdb_get_packet(connection, packet, &packet_size)) != ERROR_OK)
- {
- return retval;
- }
-
- /* terminate with zero */
- packet[packet_size] = 0;
-
- DEBUG("received packet: '%s'", packet);
-
- if (packet_size > 0)
- {
- retval = ERROR_OK;
- switch (packet[0])
- {
- case 'H':
- /* Hct... -- set thread
- * we don't have threads, send empty reply */
- gdb_put_packet(connection, NULL, 0);
- break;
- case 'q':
- retval = gdb_query_packet(connection, target, packet, packet_size);
- break;
- case 'g':
- retval = gdb_get_registers_packet(connection, target, packet, packet_size);
- break;
- case 'G':
- retval = gdb_set_registers_packet(connection, target, packet, packet_size);
- break;
- case 'p':
- retval = gdb_get_register_packet(connection, target, packet, packet_size);
- break;
- case 'P':
- retval = gdb_set_register_packet(connection, target, packet, packet_size);
- break;
- case 'm':
- retval = gdb_read_memory_packet(connection, target, packet, packet_size);
- break;
- case 'M':
- retval = gdb_write_memory_packet(connection, target, packet, packet_size);
- break;
- case 'z':
- case 'Z':
- retval = gdb_breakpoint_watchpoint_packet(connection, target, packet, packet_size);
- break;
- case '?':
- gdb_last_signal_packet(connection, target, packet, packet_size);
- break;
- case 'c':
- case 's':
- {
- /* We're running/stepping, in which case we can
- * forward log output until the target is halted */
- gdb_connection_t *gdb_con = connection->priv;
- gdb_con->frontend_state = TARGET_RUNNING;
- log_add_callback(gdb_log_callback, connection);
- gdb_step_continue_packet(connection, target, packet, packet_size);
- }
- break;
- case 'v':
- retval = gdb_v_packet(connection, target, packet, packet_size);
- break;
- case 'D':
- retval = gdb_detach(connection, target);
- extended_protocol = 0;
- break;
- case 'X':
- if ((retval = gdb_write_memory_binary_packet(connection, target, packet, packet_size)) != ERROR_OK)
- return retval;
- break;
- case 'k':
- if (extended_protocol != 0)
- break;
- gdb_put_packet(connection, "OK", 2);
- return ERROR_SERVER_REMOTE_CLOSED;
- case '!':
- /* handle extended remote protocol */
- extended_protocol = 1;
- gdb_put_packet(connection, "OK", 2);
- break;
- case 'R':
- /* handle extended restart packet */
- target_process_reset(connection->cmd_ctx);
- break;
- default:
- /* ignore unkown packets */
- DEBUG("ignoring 0x%2.2x packet", packet[0]);
- 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)
- {
- if (target->state == TARGET_RUNNING)
- {
- target->type->halt(target);
- gdb_con->ctrl_c = 0;
- }
- }
-
- } while (gdb_con->buf_cnt > 0);
-
- return ERROR_OK;
-}
-
-int gdb_input(connection_t *connection)
-{
- int retval = gdb_input_inner(connection);
- if (retval == ERROR_SERVER_REMOTE_CLOSED)
- return retval;
- /* we'll recover from any other errors(e.g. temporary timeouts, etc.) */
- return ERROR_OK;
-}
-
-int gdb_init()
-{
- gdb_service_t *gdb_service;
- target_t *target = targets;
- int i = 0;
-
- if (!target)
- {
- WARNING("no gdb ports allocated as no target has been specified");
- return ERROR_OK;
- }
-
- if (gdb_port == 0)
- {
- WARNING("no gdb port specified, using default port 3333");
- gdb_port = 3333;
- }
-
- while (target)
- {
- char service_name[8];
-
- snprintf(service_name, 8, "gdb-%2.2i", i);
-
- gdb_service = malloc(sizeof(gdb_service_t));
- gdb_service->target = target;
-
- add_service("gdb", CONNECTION_GDB, gdb_port + i, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service);
-
- DEBUG("gdb service for target %s at port %i", target->type->name, gdb_port + i);
-
- i++;
- target = target->next;
- }
-
- return ERROR_OK;
-}
-
-/* daemon configuration command gdb_port */
-int handle_gdb_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 0)
- return ERROR_OK;
-
- /* only if the port wasn't overwritten by cmdline */
- if (gdb_port == 0)
- gdb_port = strtoul(args[0], NULL, 0);
-
- return ERROR_OK;
-}
-
-int handle_gdb_detach_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 1)
- {
- if (strcmp(args[0], "resume") == 0)
- {
- detach_mode = GDB_DETACH_RESUME;
- return ERROR_OK;
- }
- else if (strcmp(args[0], "reset") == 0)
- {
- detach_mode = GDB_DETACH_RESET;
- return ERROR_OK;
- }
- else if (strcmp(args[0], "halt") == 0)
- {
- detach_mode = GDB_DETACH_HALT;
- return ERROR_OK;
- }
- else if (strcmp(args[0], "nothing") == 0)
- {
- detach_mode = GDB_DETACH_NOTHING;
- return ERROR_OK;
- }
- }
-
- WARNING("invalid gdb_detach configuration directive: %s", args[0]);
- return ERROR_OK;
-}
-
-int handle_gdb_memory_map_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 1)
- {
- if (strcmp(args[0], "enable") == 0)
- {
- gdb_use_memory_map = 1;
- return ERROR_OK;
- }
- else if (strcmp(args[0], "disable") == 0)
- {
- gdb_use_memory_map = 0;
- return ERROR_OK;
- }
- }
-
- WARNING("invalid gdb_memory_map configuration directive: %s", args[0]);
- return ERROR_OK;
-}
-
-int handle_gdb_flash_program_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 1)
- {
- if (strcmp(args[0], "enable") == 0)
- {
- gdb_flash_program = 1;
- return ERROR_OK;
- }
- else if (strcmp(args[0], "disable") == 0)
- {
- gdb_flash_program = 0;
- return ERROR_OK;
- }
- }
-
- WARNING("invalid gdb_memory_map configuration directive: %s", args[0]);
- return ERROR_OK;
-}
-
-int handle_gdb_report_data_abort_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 1)
- {
- if (strcmp(args[0], "enable") == 0)
- {
- gdb_report_data_abort = 1;
- return ERROR_OK;
- }
- else if (strcmp(args[0], "disable") == 0)
- {
- gdb_report_data_abort = 0;
- return ERROR_OK;
- }
- }
-
- WARNING("invalid gdb_report_data_abort configuration directive: %s", args[0]);
- return ERROR_OK;
-}
-
-int gdb_register_commands(command_context_t *command_context)
-{
- register_command(command_context, NULL, "gdb_port", handle_gdb_port_command,
- COMMAND_CONFIG, "");
- register_command(command_context, NULL, "gdb_detach", handle_gdb_detach_command,
- COMMAND_CONFIG, "");
- register_command(command_context, NULL, "gdb_memory_map", handle_gdb_memory_map_command,
- COMMAND_CONFIG, "");
- register_command(command_context, NULL, "gdb_flash_program", handle_gdb_flash_program_command,
- COMMAND_CONFIG, "");
- register_command(command_context, NULL, "gdb_report_data_abort", handle_gdb_report_data_abort_command,
- COMMAND_CONFIG, "");
- return ERROR_OK;
-}
+/*************************************************************************** + * 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 "gdb_server.h" + +#include "server.h" +#include "log.h" +#include "binarybuffer.h" +#include "jtag.h" +#include "breakpoints.h" +#include "flash.h" +#include "target_request.h" +#include "configuration.h" + +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> + +#if 0 +#define _DEBUG_GDB_IO_ +#endif + +static unsigned short gdb_port; +static const char *DIGITS = "0123456789abcdef"; + +static void gdb_log_callback(void *priv, const char *file, int line, + const char *function, const char *format, va_list args); + +enum gdb_detach_mode +{ + GDB_DETACH_RESUME, + GDB_DETACH_RESET, + GDB_DETACH_HALT, + GDB_DETACH_NOTHING +}; + +/* target behaviour on gdb detach */ +enum gdb_detach_mode detach_mode = GDB_DETACH_RESUME; + +/* set if we are sending a memory map to gdb + * via qXfer:memory-map:read packet */ +int gdb_use_memory_map = 0; +int gdb_flash_program = 0; + +/* if set, data aborts cause an error to be reported in memory read packets + * see the code in gdb_read_memory_packet() for further explanations */ +int gdb_report_data_abort = 0; + +int gdb_last_signal(target_t *target) +{ + switch (target->debug_reason) + { + case DBG_REASON_DBGRQ: + return 0x2; /* SIGINT */ + case DBG_REASON_BREAKPOINT: + case DBG_REASON_WATCHPOINT: + case DBG_REASON_WPTANDBKPT: + return 0x05; /* SIGTRAP */ + case DBG_REASON_SINGLESTEP: + return 0x05; /* SIGTRAP */ + case DBG_REASON_NOTHALTED: + return 0x0; /* no signal... shouldn't happen */ + default: + ERROR("BUG: undefined debug reason"); + exit(-1); + } +} + +int gdb_get_char(connection_t *connection, int* next_char) +{ + gdb_connection_t *gdb_con = connection->priv; + +#ifdef _DEBUG_GDB_IO_ + char *debug_buffer; +#endif + + if (gdb_con->buf_cnt-- > 0) + { + *next_char = *(gdb_con->buf_p++); + if (gdb_con->buf_cnt > 0) + connection->input_pending = 1; + else + connection->input_pending = 0; + +#ifdef _DEBUG_GDB_IO_ + DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char); +#endif + + return ERROR_OK; + } + + for (;;) + { +#ifndef _WIN32 + /* a non-blocking socket will block if there is 0 bytes available on the socket, + * but return with as many bytes as are available immediately + */ + struct timeval tv; + fd_set read_fds; + + FD_ZERO(&read_fds); + FD_SET(connection->fd, &read_fds); + + tv.tv_sec = 1; + tv.tv_usec = 0; + if (select(connection->fd + 1, &read_fds, NULL, NULL, &tv) == 0) + { + /* This can typically be because a "monitor" command took too long + * before printing any progress messages + */ + return ERROR_GDB_TIMEOUT; + } +#endif + gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE); + if (gdb_con->buf_cnt > 0) + { + break; + } + if (gdb_con->buf_cnt == 0) + { + gdb_con->closed = 1; + return ERROR_SERVER_REMOTE_CLOSED; + } + +#ifdef _WIN32 + errno = WSAGetLastError(); + + switch(errno) + { + case WSAEWOULDBLOCK: + usleep(1000); + break; + case WSAECONNABORTED: + return ERROR_SERVER_REMOTE_CLOSED; + case WSAECONNRESET: + return ERROR_SERVER_REMOTE_CLOSED; + default: + ERROR("read: %d", errno); + exit(-1); + } +#else + switch(errno) + { + case EAGAIN: + usleep(1000); + break; + case ECONNABORTED: + return ERROR_SERVER_REMOTE_CLOSED; + case ECONNRESET: + return ERROR_SERVER_REMOTE_CLOSED; + default: + ERROR("read: %s", strerror(errno)); + return ERROR_SERVER_REMOTE_CLOSED; + } +#endif + } + +#ifdef _DEBUG_GDB_IO_ + debug_buffer = malloc(gdb_con->buf_cnt + 1); + memcpy(debug_buffer, gdb_con->buffer, gdb_con->buf_cnt); + debug_buffer[gdb_con->buf_cnt] = 0; + DEBUG("received '%s'", debug_buffer); + free(debug_buffer); +#endif + + gdb_con->buf_p = gdb_con->buffer; + gdb_con->buf_cnt--; + *next_char = *(gdb_con->buf_p++); + if (gdb_con->buf_cnt > 0) + connection->input_pending = 1; + else + connection->input_pending = 0; +#ifdef _DEBUG_GDB_IO_ + DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char); +#endif + + return ERROR_OK; +} + +int gdb_putback_char(connection_t *connection, int last_char) +{ + gdb_connection_t *gdb_con = connection->priv; + + if (gdb_con->buf_p > gdb_con->buffer) + { + *(--gdb_con->buf_p) = last_char; + gdb_con->buf_cnt++; + } + else + { + ERROR("BUG: couldn't put character back"); + } + + return ERROR_OK; +} + +/* The only way we can detect that the socket is closed is the first time + * we write to it, we will fail. Subsequent write operations will + * succeed. Shudder! */ +int gdb_write(connection_t *connection, void *data, int len) +{ + gdb_connection_t *gdb_con = connection->priv; + if (gdb_con->closed) + return ERROR_SERVER_REMOTE_CLOSED; + + if (write_socket(connection->fd, data, len) == len) + { + return ERROR_OK; + } + gdb_con->closed = 1; + return ERROR_SERVER_REMOTE_CLOSED; +} + +int gdb_put_packet_inner(connection_t *connection, char *buffer, int len) +{ + int i; + unsigned char my_checksum = 0; +#ifdef _DEBUG_GDB_IO_ + char *debug_buffer; +#endif + int reply; + int retval; + gdb_connection_t *gdb_con = connection->priv; + + for (i = 0; i < len; i++) + my_checksum += buffer[i]; + + while (1) + { +#ifdef _DEBUG_GDB_IO_ + debug_buffer = malloc(len + 1); + memcpy(debug_buffer, buffer, len); + debug_buffer[len] = 0; + DEBUG("sending packet '$%s#%2.2x'", debug_buffer, my_checksum); + free(debug_buffer); +#endif +#if 0 + char checksum[3]; + gdb_write(connection, "$", 1); + if (len > 0) + gdb_write(connection, buffer, len); + gdb_write(connection, "#", 1); + + snprintf(checksum, 3, "%2.2x", my_checksum); + + gdb_write(connection, checksum, 2); +#else + void *allocated = NULL; + char stackAlloc[1024]; + char *t = stackAlloc; + int totalLen = 1 + len + 1 + 2; + if (totalLen > sizeof(stackAlloc)) + { + allocated = malloc(totalLen); + t = allocated; + if (allocated == NULL) + { + ERROR("Ran out of memory trying to reply packet %d\n", totalLen); + exit(-1); + } + } + t[0] = '$'; + memcpy(t + 1, buffer, len); + t[1 + len] = '#'; + t[1 + len + 1] = DIGITS[(my_checksum >> 4) & 0xf]; + t[1 + len + 2] = DIGITS[my_checksum & 0xf]; + + gdb_write(connection, t, totalLen); + + if (allocated) + { + free(allocated); + } +#endif + if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK) + return retval; + + if (reply == '+') + break; + else if (reply == '-') + { + /* Stop sending output packets for now */ + log_remove_callback(gdb_log_callback, connection); + WARNING("negative reply, retrying"); + } + else if (reply == 0x3) + { + gdb_con->ctrl_c = 1; + if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK) + return retval; + if (reply == '+') + break; + else if (reply == '-') + { + /* Stop sending output packets for now */ + log_remove_callback(gdb_log_callback, connection); + WARNING("negative reply, retrying"); + } + else + { + ERROR("unknown character 0x%2.2x in reply, dropping connection", reply); + return ERROR_SERVER_REMOTE_CLOSED; + } + } + else + { + ERROR("unknown character 0x%2.2x in reply, dropping connection", reply); + return ERROR_SERVER_REMOTE_CLOSED; + } + } + if (gdb_con->closed) + return ERROR_SERVER_REMOTE_CLOSED; + + return ERROR_OK; +} + +int gdb_put_packet(connection_t *connection, char *buffer, int len) +{ + gdb_connection_t *gdb_con = connection->priv; + gdb_con->busy = 1; + int retval = gdb_put_packet_inner(connection, buffer, len); + gdb_con->busy = 0; + return retval; +} + +int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len) +{ + int character; + int count = 0; + int retval; + char checksum[3]; + unsigned char my_checksum = 0; + gdb_connection_t *gdb_con = connection->priv; + + while (1) + { + do + { + if ((retval = gdb_get_char(connection, &character)) != ERROR_OK) + return retval; + +#ifdef _DEBUG_GDB_IO_ + DEBUG("character: '%c'", character); +#endif + + switch (character) + { + case '$': + break; + case '+': + WARNING("acknowledgment received, but no packet pending"); + break; + case '-': + WARNING("negative acknowledgment, but no packet pending"); + break; + case 0x3: + gdb_con->ctrl_c = 1; + *len = 0; + return ERROR_OK; + default: + WARNING("ignoring character 0x%x", character); + break; + } + } while (character != '$'); + + my_checksum = 0; + + count = 0; + gdb_connection_t *gdb_con = connection->priv; + for (;;) + { + /* The common case is that we have an entire packet with no escape chars. + * We need to leave at least 2 bytes in the buffer to have + * gdb_get_char() update various bits and bobs correctly. + */ + if ((gdb_con->buf_cnt > 2) && ((gdb_con->buf_cnt+count) < *len)) + { + /* The compiler will struggle a bit with constant propagation and + * aliasing, so we help it by showing that these values do not + * change inside the loop + */ + int i; + char *buf = gdb_con->buf_p; + int run = gdb_con->buf_cnt - 2; + i = 0; + int done = 0; + while (i < run) + { + character = *buf++; + i++; + if (character == '#') + { + /* Danger! character can be '#' when esc is + * used so we need an explicit boolean for done here. + */ + done = 1; + break; + } + + if (character == '}') + { + /* data transmitted in binary mode (X packet) + * uses 0x7d as escape character */ + my_checksum += character & 0xff; + character = *buf++; + i++; + my_checksum += character & 0xff; + buffer[count++] = (character ^ 0x20) & 0xff; + } else + { + my_checksum += character & 0xff; + buffer[count++] = character & 0xff; + } + } + gdb_con->buf_p += i; + gdb_con->buf_cnt -= i; + if (done) + break; + } + if (count > *len) + { + ERROR("packet buffer too small"); + return ERROR_GDB_BUFFER_TOO_SMALL; + } + + if ((retval = gdb_get_char(connection, &character)) != ERROR_OK) + return retval; + + if (character == '#') + break; + + if (character == '}') + { + /* data transmitted in binary mode (X packet) + * uses 0x7d as escape character */ + my_checksum += character & 0xff; + if ((retval = gdb_get_char(connection, &character)) != ERROR_OK) + return retval; + my_checksum += character & 0xff; + buffer[count++] = (character ^ 0x20) & 0xff; + } + else + { + my_checksum += character & 0xff; + buffer[count++] = character & 0xff; + } + + } + + *len = count; + + if ((retval = gdb_get_char(connection, &character)) != ERROR_OK) + return retval; + checksum[0] = character; + if ((retval = gdb_get_char(connection, &character)) != ERROR_OK) + return retval; + checksum[1] = character; + checksum[2] = 0; + + if (my_checksum == strtoul(checksum, NULL, 16)) + { + gdb_write(connection, "+", 1); + break; + } + + WARNING("checksum error, requesting retransmission"); + gdb_write(connection, "-", 1); + } + if (gdb_con->closed) + return ERROR_SERVER_REMOTE_CLOSED; + + return ERROR_OK; +} + +int gdb_get_packet(connection_t *connection, char *buffer, int *len) +{ + gdb_connection_t *gdb_con = connection->priv; + gdb_con->busy = 1; + int retval = gdb_get_packet_inner(connection, buffer, len); + gdb_con->busy = 0; + return retval; +} + +int gdb_output_con(connection_t *connection, char* line) +{ + char *hex_buffer; + int i, bin_size; + + bin_size = strlen(line); + + hex_buffer = malloc(bin_size*2 + 4); + + hex_buffer[0] = 'O'; + for (i=0; i<bin_size; i++) + snprintf(hex_buffer + 1 + i*2, 3, "%2.2x", line[i]); + hex_buffer[bin_size*2+1] = '0'; + hex_buffer[bin_size*2+2] = 'a'; + hex_buffer[bin_size*2+3] = 0x0; + + gdb_put_packet(connection, hex_buffer, bin_size*2 + 3); + + free(hex_buffer); + return ERROR_OK; +} + +int gdb_output(struct command_context_s *context, char* line) +{ + /* this will be dumped to the log and also sent as an O packet if possible */ + USER(line); + return ERROR_OK; +} + +int gdb_program_handler(struct target_s *target, enum target_event event, void *priv) +{ + FILE *script; + struct command_context_s *cmd_ctx = priv; + + if (target->gdb_program_script) + { + script = open_file_from_path(cmd_ctx, target->gdb_program_script, "r"); + if (!script) + { + ERROR("couldn't open script file %s", target->gdb_program_script); + return ERROR_OK; + } + + INFO("executing gdb_program script '%s'", target->gdb_program_script); + command_run_file(cmd_ctx, script, COMMAND_EXEC); + fclose(script); + + jtag_execute_queue(); + } + + return ERROR_OK; +} + +int gdb_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv) +{ + connection_t *connection = priv; + gdb_connection_t *gdb_connection = connection->priv; + char sig_reply[4]; + int signal; + + switch (event) + { + case TARGET_EVENT_HALTED: + /* In the GDB protocol when we are stepping or coninuing execution, + * we have a lingering reply. Upon receiving a halted event + * when we have that lingering packet, we reply to the original + * step or continue packet. + * + * Executing monitor commands can bring the target in and + * out of the running state so we'll see lots of TARGET_EVENT_XXX + * that are to be ignored. + */ + if (gdb_connection->frontend_state == TARGET_RUNNING) + { + /* stop forwarding log packets! */ + log_remove_callback(gdb_log_callback, connection); + + if (gdb_connection->ctrl_c) + { + signal = 0x2; + gdb_connection->ctrl_c = 0; + } + else + { + signal = gdb_last_signal(target); + } + + snprintf(sig_reply, 4, "T%2.2x", signal); + gdb_put_packet(connection, sig_reply, 3); + gdb_connection->frontend_state = TARGET_HALTED; + } + break; + case TARGET_EVENT_GDB_PROGRAM: + gdb_program_handler(target, event, connection->cmd_ctx); + break; + default: + break; + } + + return ERROR_OK; +} + +int gdb_new_connection(connection_t *connection) +{ + gdb_connection_t *gdb_connection = malloc(sizeof(gdb_connection_t)); + gdb_service_t *gdb_service = connection->service->priv; + int retval; + int initial_ack; + + connection->priv = gdb_connection; + + /* initialize gdb connection information */ + gdb_connection->buf_p = gdb_connection->buffer; + gdb_connection->buf_cnt = 0; + gdb_connection->ctrl_c = 0; + gdb_connection->frontend_state = TARGET_HALTED; + gdb_connection->vflash_image = NULL; + gdb_connection->closed = 0; + gdb_connection->busy = 0; + + /* output goes through gdb connection */ + command_set_output_handler(connection->cmd_ctx, gdb_output, connection); + + /* register callback to be informed about target events */ + target_register_event_callback(gdb_target_callback_event_handler, connection); + + /* a gdb session just attached, put the target in halt mode */ + if (((retval = gdb_service->target->type->halt(gdb_service->target)) != ERROR_OK) && + (retval != ERROR_TARGET_ALREADY_HALTED)) + { + ERROR("error(%d) when trying to halt target, falling back to \"reset halt\"", retval); + command_run_line(connection->cmd_ctx, "reset halt"); + } + + /* This will time out after 1 second */ + command_run_line(connection->cmd_ctx, "wait_halt 1"); + + /* remove the initial ACK from the incoming buffer */ + if ((retval = gdb_get_char(connection, &initial_ack)) != ERROR_OK) + return retval; + + if (initial_ack != '+') + gdb_putback_char(connection, initial_ack); + + return ERROR_OK; +} + +int gdb_connection_closed(connection_t *connection) +{ + gdb_service_t *gdb_service = connection->service->priv; + gdb_connection_t *gdb_connection = connection->priv; + + /* see if an image built with vFlash commands is left */ + if (gdb_connection->vflash_image) + { + image_close(gdb_connection->vflash_image); + free(gdb_connection->vflash_image); + gdb_connection->vflash_image = NULL; + } + + /* if this connection registered a debug-message receiver delete it */ + delete_debug_msg_receiver(connection->cmd_ctx, gdb_service->target); + + if (connection->priv) + { + free(connection->priv); + connection->priv = NULL; + } + else + { + ERROR("BUG: connection->priv == NULL"); + } + + target_unregister_event_callback(gdb_target_callback_event_handler, connection); + log_remove_callback(gdb_log_callback, 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]; + int signal; + + signal = gdb_last_signal(target); + + snprintf(sig_reply, 4, "S%2.2x", signal); + gdb_put_packet(connection, sig_reply, 3); + + return ERROR_OK; +} + +/* Convert register to string of bits. NB! The # of bits in the + * register might be non-divisible by 8(a byte), in which + * case an entire byte is shown. */ +void gdb_str_to_target(target_t *target, char *tstr, reg_t *reg) +{ + int i; + + u8 *buf; + int buf_len; + buf = reg->value; + buf_len = CEIL(reg->size, 8); + + if (target->endianness == TARGET_LITTLE_ENDIAN) + { + for (i = 0; i < buf_len; i++) + { + tstr[i*2] = DIGITS[(buf[i]>>4) & 0xf]; + tstr[i*2+1] = DIGITS[buf[i]&0xf]; + } + } + else + { + for (i = 0; i < buf_len; i++) + { + tstr[(buf_len-1-i)*2] = DIGITS[(buf[i]>>4)&0xf]; + tstr[(buf_len-1-i)*2+1] = DIGITS[buf[i]&0xf]; + } + } +} + +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; + int retval; + int reg_packet_size = 0; + char *reg_packet; + char *reg_packet_p; + int i; + +#ifdef _DEBUG_GDB_IO_ + DEBUG("-"); +#endif + + if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_NOT_HALTED: + 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); + } + } + + for (i = 0; i < reg_list_size; i++) + { + reg_packet_size += reg_list[i]->size; + } + + reg_packet = malloc(CEIL(reg_packet_size, 8) * 2); + reg_packet_p = reg_packet; + + for (i = 0; i < reg_list_size; i++) + { + gdb_str_to_target(target, reg_packet_p, reg_list[i]); + reg_packet_p += CEIL(reg_list[i]->size, 8) * 2; + } + +#ifdef _DEBUG_GDB_IO_ + { + char *reg_packet_p; + reg_packet_p = strndup(reg_packet, CEIL(reg_packet_size, 8) * 2); + DEBUG("reg_packet: %s", reg_packet_p); + free(reg_packet_p); + } +#endif + + gdb_put_packet(connection, reg_packet, CEIL(reg_packet_size, 8) * 2); + free(reg_packet); + + free(reg_list); + + return ERROR_OK; +} + +int gdb_set_registers_packet(connection_t *connection, target_t *target, char *packet, int packet_size) +{ + int i; + reg_t **reg_list; + int reg_list_size; + int retval; + char *packet_p; + +#ifdef _DEBUG_GDB_IO_ + DEBUG("-"); +#endif + + /* skip command character */ + packet++; + packet_size--; + + if (packet_size % 2) + { + 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, ®_list, ®_list_size)) != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_NOT_HALTED: + 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); + } + } + + packet_p = packet; + for (i = 0; i < reg_list_size; i++) + { + 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; +} + +int gdb_get_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size) +{ + char *reg_packet; + int reg_num = strtoul(packet + 1, NULL, 16); + reg_t **reg_list; + int reg_list_size; + int retval; + +#ifdef _DEBUG_GDB_IO_ + DEBUG("-"); +#endif + + if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_NOT_HALTED: + 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); + } + } + + if (reg_list_size <= reg_num) + { + ERROR("gdb requested a non-existing register"); + exit(-1); + } + + reg_packet = malloc(CEIL(reg_list[reg_num]->size, 8) * 2); + + gdb_str_to_target(target, reg_packet, reg_list[reg_num]); + + gdb_put_packet(connection, reg_packet, CEIL(reg_list[reg_num]->size, 8) * 2); + + free(reg_list); + free(reg_packet); + + return ERROR_OK; +} + +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, ®_list, ®_list_size)) != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_NOT_HALTED: + 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); + } + } + + if (reg_list_size < reg_num) + { + ERROR("gdb requested a non-existing register"); + return ERROR_SERVER_REMOTE_CLOSED; + } + + if (*separator != '=') + { + ERROR("GDB 'set register packet', but no '=' following the register number"); + return ERROR_SERVER_REMOTE_CLOSED; + } + + /* 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; +} + +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; + 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: + /* This could be that the target reset itself. */ + ERROR("unexpected error %i. Dropping connection.", retval); + return ERROR_SERVER_REMOTE_CLOSED; + } + + return ERROR_OK; +} + +/* We don't have to worry about the default 2 second timeout for GDB packets, + * because GDB breaks up large memory reads into smaller reads. + * + * 8191 bytes by the looks of it. Why 8191 bytes instead of 8192????? + */ +int gdb_read_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size) +{ + char *separator; + u32 addr = 0; + u32 len = 0; + + u8 *buffer; + char *hex_buffer; + + int retval = ERROR_OK; + + /* skip command character */ + packet++; + + addr = strtoul(packet, &separator, 16); + + if (*separator != ',') + { + ERROR("incomplete read memory packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } + + len = strtoul(separator+1, NULL, 16); + + buffer = malloc(len); + + DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len); + + retval = target_read_buffer(target, addr, len, buffer); + + if ((retval == ERROR_TARGET_DATA_ABORT) && (!gdb_report_data_abort)) + { + /* TODO : Here we have to lie and send back all zero's lest stack traces won't work. + * At some point this might be fixed in GDB, in which case this code can be removed. + * + * OpenOCD developers are acutely aware of this problem, but there is nothing + * gained by involving the user in this problem that hopefully will get resolved + * eventually + * + * http://sourceware.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gdb&pr=2395 + * + * For now, the default is to fix up things to make current GDB versions work. + * This can be overwritten using the gdb_report_data_abort <'enable'|'disable'> command. + */ + memset(buffer, 0, len); + retval = ERROR_OK; + } + + if (retval == ERROR_OK) + { + hex_buffer = malloc(len * 2 + 1); + + int i; + for (i = 0; i < len; i++) + { + u8 t = buffer[i]; + hex_buffer[2 * i] = DIGITS[(t >> 4) & 0xf]; + hex_buffer[2 * i + 1] = DIGITS[t & 0xf]; + } + + gdb_put_packet(connection, hex_buffer, len * 2); + + free(hex_buffer); + } + else + { + retval = gdb_memory_packet_error(connection, retval); + } + + free(buffer); + + return retval; +} + +int gdb_write_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size) +{ + char *separator; + u32 addr = 0; + u32 len = 0; + + u8 *buffer; + + int i; + int retval; + + /* skip command character */ + packet++; + + addr = strtoul(packet, &separator, 16); + + if (*separator != ',') + { + ERROR("incomplete write memory packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } + + len = strtoul(separator+1, &separator, 16); + + if (*(separator++) != ':') + { + ERROR("incomplete write memory packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } + + buffer = malloc(len); + + DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len); + + for (i=0; i<len; i++) + { + u32 tmp; + sscanf(separator + 2*i, "%2x", &tmp); + buffer[i] = tmp; + } + + retval = target_write_buffer(target, addr, len, buffer); + + 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; +} + +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; + + int retval; + + /* skip command character */ + packet++; + + addr = strtoul(packet, &separator, 16); + + if (*separator != ',') + { + ERROR("incomplete write memory binary packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } + + len = strtoul(separator+1, &separator, 16); + + if (*(separator++) != ':') + { + ERROR("incomplete write memory binary packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } + + retval = ERROR_OK; + if (len) + { + DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len); + + retval = target_write_buffer(target, addr, len, (u8*)separator); + } + + 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) +{ + int current = 0; + u32 address = 0x0; + + DEBUG("-"); + + if (packet_size > 1) + { + packet[packet_size] = 0; + address = strtoul(packet + 1, NULL, 16); + } + else + { + current = 1; + } + + if (packet[0] == 'c') + { + DEBUG("continue"); + target->type->resume(target, current, address, 0, 0); /* resume at current address, don't handle breakpoints, not debugging */ + } + else if (packet[0] == 's') + { + DEBUG("step"); + target->type->step(target, current, address, 0); /* step at current or address, don't handle breakpoints */ + } +} + +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 = BKPT_SOFT /* dummy init to avoid warning */; + enum watchpoint_rw wp_type; + u32 address; + u32 size; + char *separator; + int retval; + + DEBUG("-"); + + type = strtoul(packet + 1, &separator, 16); + + if (type == 0) /* memory breakpoint */ + bp_type = BKPT_SOFT; + else if (type == 1) /* hardware breakpoint */ + bp_type = BKPT_HARD; + else if (type == 2) /* write watchpoint */ + wp_type = WPT_WRITE; + else if (type == 3) /* read watchpoint */ + wp_type = WPT_READ; + else if (type == 4) /* access watchpoint */ + wp_type = WPT_ACCESS; + + if (*separator != ',') + { + ERROR("incomplete breakpoint/watchpoint packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } + + address = strtoul(separator+1, &separator, 16); + + if (*separator != ',') + { + ERROR("incomplete breakpoint/watchpoint packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } + + size = strtoul(separator+1, &separator, 16); + + switch (type) + { + case 0: + case 1: + if (packet[0] == 'Z') + { + if ((retval = breakpoint_add(target, address, size, bp_type)) != ERROR_OK) + { + 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); + } + break; + case 2: + case 3: + case 4: + { + if (packet[0] == 'Z') + { + 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); + } + break; + } + default: + break; + } + + return ERROR_OK; +} + +/* print out a string and allocate more space as needed, mainly used for XML at this point */ +void xml_printf(int *retval, char **xml, int *pos, int *size, const char *fmt, ...) +{ + if (*retval != ERROR_OK) + { + return; + } + int first = 1; + + for (;;) + { + if ((*xml == NULL) || (!first)) + { + /* start by 0 to exercise all the code paths. + * Need minimum 2 bytes to fit 1 char and 0 terminator. */ + + *size = *size * 2 + 2; + char *t = *xml; + *xml = realloc(*xml, *size); + if (*xml == NULL) + { + if (t) + free(t); + *retval = ERROR_SERVER_REMOTE_CLOSED; + return; + } + } + + va_list ap; + int ret; + va_start(ap, fmt); + ret = vsnprintf(*xml + *pos, *size - *pos, fmt, ap); + va_end(ap); + if ((ret > 0) && ((ret + 1) < *size - *pos)) + { + *pos += ret; + return; + } + /* there was just enough or not enough space, allocate more. */ + first = 0; + } +} + +static int decode_xfer_read(char *buf, char **annex, int *ofs, unsigned int *len) +{ + char *separator; + + /* Extract and NUL-terminate the annex. */ + *annex = buf; + while (*buf && *buf != ':') + buf++; + if (*buf == '\0') + return -1; + *buf++ = 0; + + /* After the read marker and annex, qXfer looks like a + * traditional 'm' packet. */ + + *ofs = strtoul(buf, &separator, 16); + + if (*separator != ',') + return -1; + + *len = strtoul(separator+1, NULL, 16); + + return 0; +} + +int gdb_calc_blocksize(flash_bank_t *bank) +{ + int i; + int block_size = 0xffffffff; + + /* loop through all sectors and return smallest sector size */ + + for (i = 0; i < bank->num_sectors; i++) + { + if (bank->sectors[i].size < block_size) + block_size = bank->sectors[i].size; + } + + return block_size; +} + +int gdb_query_packet(connection_t *connection, target_t *target, char *packet, int packet_size) +{ + command_context_t *cmd_ctx = connection->cmd_ctx; + + if (strstr(packet, "qRcmd,")) + { + if (packet_size > 6) + { + char *cmd; + int i; + cmd = malloc((packet_size - 6)/2 + 1); + for (i=0; i < (packet_size - 6)/2; i++) + { + u32 tmp; + sscanf(packet + 6 + 2*i, "%2x", &tmp); + cmd[i] = tmp; + } + cmd[(packet_size - 6)/2] = 0x0; + + /* We want to print all debug output to GDB connection */ + log_add_callback(gdb_log_callback, connection); + target_call_timer_callbacks(); + command_run_line(cmd_ctx, cmd); + free(cmd); + } + gdb_put_packet(connection, "OK", 2); + return ERROR_OK; + } + else if (strstr(packet, "qCRC:")) + { + if (packet_size > 5) + { + int retval; + char gdb_reply[10]; + char *separator; + u32 checksum; + u32 addr = 0; + u32 len = 0; + + /* skip command character */ + packet += 5; + + addr = strtoul(packet, &separator, 16); + + if (*separator != ',') + { + ERROR("incomplete read memory packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } + + len = strtoul(separator + 1, NULL, 16); + + retval = target_checksum_memory(target, addr, len, &checksum); + + if (retval == ERROR_OK) + { + snprintf(gdb_reply, 10, "C%8.8x", checksum); + gdb_put_packet(connection, gdb_reply, 9); + } + else + { + if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK) + return retval; + } + + return ERROR_OK; + } + } + else if (strstr(packet, "qSupported")) + { + /* we currently support packet size and qXfer:memory-map:read (if enabled) + * disable qXfer:features:read for the moment */ + int retval = ERROR_OK; + char *buffer = NULL; + int pos = 0; + int size = 0; + + xml_printf(&retval, &buffer, &pos, &size, + "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-", + (GDB_BUFFER_SIZE - 1), gdb_use_memory_map == 1 ? '+' : '-'); + + if (retval != ERROR_OK) + { + gdb_send_error(connection, 01); + return ERROR_OK; + } + + gdb_put_packet(connection, buffer, strlen(buffer)); + free(buffer); + + return ERROR_OK; + } + else if (strstr(packet, "qXfer:memory-map:read::")) + { + /* We get away with only specifying flash here. Regions that are not + * specified are treated as if we provided no memory map(if not we + * could detect the holes and mark them as RAM). + * Normally we only execute this code once, but no big deal if we + * have to regenerate it a couple of times. */ + + flash_bank_t *p; + char *xml = NULL; + int size = 0; + int pos = 0; + int retval = ERROR_OK; + + int offset; + int length; + char *separator; + int blocksize; + + /* skip command character */ + packet += 23; + + offset = strtoul(packet, &separator, 16); + length = strtoul(separator + 1, &separator, 16); + + xml_printf(&retval, &xml, &pos, &size, "<memory-map>\n"); + + int i = 0; + for (;;) + { + p = get_flash_bank_by_num(i); + if (p == NULL) + break; + + /* if device has uneven sector sizes, eg. str7, lpc + * we pass the smallest sector size to gdb memory map */ + blocksize = gdb_calc_blocksize(p); + + xml_printf(&retval, &xml, &pos, &size, "<memory type=\"flash\" start=\"0x%x\" length=\"0x%x\">\n" \ + "<property name=\"blocksize\">0x%x</property>\n" \ + "</memory>\n", \ + p->base, p->size, blocksize); + i++; + } + + xml_printf(&retval, &xml, &pos, &size, "</memory-map>\n"); + + if (retval != ERROR_OK) + { + gdb_send_error(connection, retval); + return retval; + } + + if (offset + length > pos) + { + length = pos - offset; + } + + char *t = malloc(length + 1); + t[0] = 'l'; + memcpy(t + 1, xml + offset, length); + gdb_put_packet(connection, t, length + 1); + + free(t); + free(xml); + return ERROR_OK; + } + else if (strstr(packet, "qXfer:features:read:")) + { + char *xml = NULL; + int size = 0; + int pos = 0; + int retval = ERROR_OK; + + int offset; + unsigned int length; + char *annex; + + /* skip command character */ + packet += 20; + + if (decode_xfer_read(packet, &annex, &offset, &length) < 0) + { + gdb_send_error(connection, 01); + return ERROR_OK; + } + + if (strcmp(annex, "target.xml") != 0) + { + gdb_send_error(connection, 01); + return ERROR_OK; + } + + xml_printf(&retval, &xml, &pos, &size, \ + "l<target version=\"1.0\">\n<architecture>arm</architecture>\n</target>\n"); + + if (retval != ERROR_OK) + { + gdb_send_error(connection, retval); + return retval; + } + + gdb_put_packet(connection, xml, strlen(xml) + 1); + + free(xml); + return ERROR_OK; + } + + gdb_put_packet(connection, "", 0); + return ERROR_OK; +} + +int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int packet_size) +{ + gdb_connection_t *gdb_connection = connection->priv; + gdb_service_t *gdb_service = connection->service->priv; + int result; + + /* if flash programming disabled - send a empty reply */ + + if (gdb_flash_program == 0) + { + gdb_put_packet(connection, "", 0); + return ERROR_OK; + } + + if (strstr(packet, "vFlashErase:")) + { + unsigned long addr; + unsigned long length; + + char *parse = packet + 12; + if (*parse == '\0') + { + ERROR("incomplete vFlashErase packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } + + addr = strtoul(parse, &parse, 16); + + if (*(parse++) != ',' || *parse == '\0') + { + ERROR("incomplete vFlashErase packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } + + length = strtoul(parse, &parse, 16); + + if (*parse != '\0') + { + ERROR("incomplete vFlashErase packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } + + /* assume all sectors need erasing - stops any problems + * when flash_write is called multiple times */ + flash_set_dirty(); + + /* perform any target specific operations before the erase */ + target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_PROGRAM); + + /* perform erase */ + if ((result = flash_erase_address_range(gdb_service->target, addr, length)) != ERROR_OK) + { + /* GDB doesn't evaluate the actual error number returned, + * treat a failed erase as an I/O error + */ + gdb_send_error(connection, EIO); + ERROR("flash_erase returned %i", result); + } + else + gdb_put_packet(connection, "OK", 2); + + return ERROR_OK; + } + + if (strstr(packet, "vFlashWrite:")) + { + unsigned long addr; + unsigned long length; + char *parse = packet + 12; + + if (*parse == '\0') + { + ERROR("incomplete vFlashErase packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } + addr = strtoul(parse, &parse, 16); + if (*(parse++) != ':') + { + ERROR("incomplete vFlashErase packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } + length = packet_size - (parse - packet); + + /* create a new image if there isn't already one */ + if (gdb_connection->vflash_image == NULL) + { + gdb_connection->vflash_image = malloc(sizeof(image_t)); + image_open(gdb_connection->vflash_image, "", "build"); + } + + /* create new section with content from packet buffer */ + image_add_section(gdb_connection->vflash_image, addr, length, 0x0, (u8*)parse); + + gdb_put_packet(connection, "OK", 2); + + return ERROR_OK; + } + + if (!strcmp(packet, "vFlashDone")) + { + u32 written; + + /* process the flashing buffer. No need to erase as GDB + * always issues a vFlashErase first. */ + if ((result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0)) != ERROR_OK) + { + if (result == ERROR_FLASH_DST_OUT_OF_BANK) + gdb_put_packet(connection, "E.memtype", 9); + else + gdb_send_error(connection, EIO); + } + else + { + DEBUG("wrote %u bytes from vFlash image to flash", written); + gdb_put_packet(connection, "OK", 2); + } + + image_close(gdb_connection->vflash_image); + free(gdb_connection->vflash_image); + gdb_connection->vflash_image = NULL; + + return ERROR_OK; + } + + gdb_put_packet(connection, "", 0); + return ERROR_OK; +} + +int gdb_detach(connection_t *connection, target_t *target) +{ + switch( detach_mode ) + { + case GDB_DETACH_RESUME: + target->type->resume(target, 1, 0, 1, 0); + break; + + case GDB_DETACH_RESET: + target_process_reset(connection->cmd_ctx); + break; + + case GDB_DETACH_HALT: + target->type->halt(target); + break; + + case GDB_DETACH_NOTHING: + break; + } + + gdb_put_packet(connection, "OK", 2); + + return ERROR_OK; +} + +static void gdb_log_callback(void *priv, const char *file, int line, + const char *function, const char *format, va_list args) +{ + connection_t *connection = priv; + gdb_connection_t *gdb_con = connection->priv; + + if (gdb_con->busy) + { + /* do not reply this using the O packet */ + return; + } + + char *t = alloc_printf(format, args); + if (t == NULL) + return; + + gdb_output_con(connection, t); + + free(t); +} + +int gdb_input_inner(connection_t *connection) +{ + gdb_service_t *gdb_service = connection->service->priv; + target_t *target = gdb_service->target; + char packet[GDB_BUFFER_SIZE]; + int packet_size; + int retval; + gdb_connection_t *gdb_con = connection->priv; + static int extended_protocol = 0; + + /* drain input buffer */ + do + { + packet_size = GDB_BUFFER_SIZE-1; + if ((retval = gdb_get_packet(connection, packet, &packet_size)) != ERROR_OK) + { + return retval; + } + + /* terminate with zero */ + packet[packet_size] = 0; + + DEBUG("received packet: '%s'", packet); + + if (packet_size > 0) + { + retval = ERROR_OK; + switch (packet[0]) + { + case 'H': + /* Hct... -- set thread + * we don't have threads, send empty reply */ + gdb_put_packet(connection, NULL, 0); + break; + case 'q': + retval = gdb_query_packet(connection, target, packet, packet_size); + break; + case 'g': + retval = gdb_get_registers_packet(connection, target, packet, packet_size); + break; + case 'G': + retval = gdb_set_registers_packet(connection, target, packet, packet_size); + break; + case 'p': + retval = gdb_get_register_packet(connection, target, packet, packet_size); + break; + case 'P': + retval = gdb_set_register_packet(connection, target, packet, packet_size); + break; + case 'm': + retval = gdb_read_memory_packet(connection, target, packet, packet_size); + break; + case 'M': + retval = gdb_write_memory_packet(connection, target, packet, packet_size); + break; + case 'z': + case 'Z': + retval = gdb_breakpoint_watchpoint_packet(connection, target, packet, packet_size); + break; + case '?': + gdb_last_signal_packet(connection, target, packet, packet_size); + break; + case 'c': + case 's': + { + /* We're running/stepping, in which case we can + * forward log output until the target is halted */ + gdb_connection_t *gdb_con = connection->priv; + gdb_con->frontend_state = TARGET_RUNNING; + log_add_callback(gdb_log_callback, connection); + gdb_step_continue_packet(connection, target, packet, packet_size); + } + break; + case 'v': + retval = gdb_v_packet(connection, target, packet, packet_size); + break; + case 'D': + retval = gdb_detach(connection, target); + extended_protocol = 0; + break; + case 'X': + if ((retval = gdb_write_memory_binary_packet(connection, target, packet, packet_size)) != ERROR_OK) + return retval; + break; + case 'k': + if (extended_protocol != 0) + break; + gdb_put_packet(connection, "OK", 2); + return ERROR_SERVER_REMOTE_CLOSED; + case '!': + /* handle extended remote protocol */ + extended_protocol = 1; + gdb_put_packet(connection, "OK", 2); + break; + case 'R': + /* handle extended restart packet */ + target_process_reset(connection->cmd_ctx); + break; + default: + /* ignore unkown packets */ + DEBUG("ignoring 0x%2.2x packet", packet[0]); + 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) + { + if (target->state == TARGET_RUNNING) + { + target->type->halt(target); + gdb_con->ctrl_c = 0; + } + } + + } while (gdb_con->buf_cnt > 0); + + return ERROR_OK; +} + +int gdb_input(connection_t *connection) +{ + int retval = gdb_input_inner(connection); + if (retval == ERROR_SERVER_REMOTE_CLOSED) + return retval; + /* we'll recover from any other errors(e.g. temporary timeouts, etc.) */ + return ERROR_OK; +} + +int gdb_init() +{ + gdb_service_t *gdb_service; + target_t *target = targets; + int i = 0; + + if (!target) + { + WARNING("no gdb ports allocated as no target has been specified"); + return ERROR_OK; + } + + if (gdb_port == 0) + { + WARNING("no gdb port specified, using default port 3333"); + gdb_port = 3333; + } + + while (target) + { + char service_name[8]; + + snprintf(service_name, 8, "gdb-%2.2i", i); + + gdb_service = malloc(sizeof(gdb_service_t)); + gdb_service->target = target; + + add_service("gdb", CONNECTION_GDB, gdb_port + i, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service); + + DEBUG("gdb service for target %s at port %i", target->type->name, gdb_port + i); + + i++; + target = target->next; + } + + return ERROR_OK; +} + +/* daemon configuration command gdb_port */ +int handle_gdb_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 0) + return ERROR_OK; + + /* only if the port wasn't overwritten by cmdline */ + if (gdb_port == 0) + gdb_port = strtoul(args[0], NULL, 0); + + return ERROR_OK; +} + +int handle_gdb_detach_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 1) + { + if (strcmp(args[0], "resume") == 0) + { + detach_mode = GDB_DETACH_RESUME; + return ERROR_OK; + } + else if (strcmp(args[0], "reset") == 0) + { + detach_mode = GDB_DETACH_RESET; + return ERROR_OK; + } + else if (strcmp(args[0], "halt") == 0) + { + detach_mode = GDB_DETACH_HALT; + return ERROR_OK; + } + else if (strcmp(args[0], "nothing") == 0) + { + detach_mode = GDB_DETACH_NOTHING; + return ERROR_OK; + } + } + + WARNING("invalid gdb_detach configuration directive: %s", args[0]); + return ERROR_OK; +} + +int handle_gdb_memory_map_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 1) + { + if (strcmp(args[0], "enable") == 0) + { + gdb_use_memory_map = 1; + return ERROR_OK; + } + else if (strcmp(args[0], "disable") == 0) + { + gdb_use_memory_map = 0; + return ERROR_OK; + } + } + + WARNING("invalid gdb_memory_map configuration directive: %s", args[0]); + return ERROR_OK; +} + +int handle_gdb_flash_program_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 1) + { + if (strcmp(args[0], "enable") == 0) + { + gdb_flash_program = 1; + return ERROR_OK; + } + else if (strcmp(args[0], "disable") == 0) + { + gdb_flash_program = 0; + return ERROR_OK; + } + } + + WARNING("invalid gdb_memory_map configuration directive: %s", args[0]); + return ERROR_OK; +} + +int handle_gdb_report_data_abort_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 1) + { + if (strcmp(args[0], "enable") == 0) + { + gdb_report_data_abort = 1; + return ERROR_OK; + } + else if (strcmp(args[0], "disable") == 0) + { + gdb_report_data_abort = 0; + return ERROR_OK; + } + } + + WARNING("invalid gdb_report_data_abort configuration directive: %s", args[0]); + return ERROR_OK; +} + +int gdb_register_commands(command_context_t *command_context) +{ + register_command(command_context, NULL, "gdb_port", handle_gdb_port_command, + COMMAND_CONFIG, ""); + register_command(command_context, NULL, "gdb_detach", handle_gdb_detach_command, + COMMAND_CONFIG, ""); + register_command(command_context, NULL, "gdb_memory_map", handle_gdb_memory_map_command, + COMMAND_CONFIG, ""); + register_command(command_context, NULL, "gdb_flash_program", handle_gdb_flash_program_command, + COMMAND_CONFIG, ""); + register_command(command_context, NULL, "gdb_report_data_abort", handle_gdb_report_data_abort_command, + COMMAND_CONFIG, ""); + return ERROR_OK; +} diff --git a/src/server/server.c b/src/server/server.c index 0aa3383..6aa72b9 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -1,450 +1,450 @@ -/***************************************************************************
- * 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 "server.h"
-
-#include "log.h"
-#include "telnet_server.h"
-#include "target.h"
-
-#include <command.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <signal.h>
-
-service_t *services = NULL;
-
-/* shutdown_openocd == 1: exit the main event loop, and quit the debugger */
-static int shutdown_openocd = 0;
-int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-int add_connection(service_t *service, command_context_t *cmd_ctx)
-{
- unsigned int address_size;
- connection_t *c, **p;
- int retval;
-
- c = malloc(sizeof(connection_t));
- c->fd = -1;
- memset(&c->sin, 0, sizeof(c->sin));
- c->cmd_ctx = copy_command_context(cmd_ctx);
- c->service = service;
- c->input_pending = 0;
- c->priv = NULL;
- c->next = NULL;
-
- address_size = sizeof(c->sin);
- c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
-
- if ((retval = service->new_connection(c)) == ERROR_OK)
- {
- INFO("accepted '%s' connection from %i", service->name, c->sin.sin_port);
- }
- else
- {
- close_socket(c->fd);
- INFO("attempted '%s' connection rejected", service->name);
- free(c);
- }
-
- /* add to the end of linked list */
- for (p = &service->connections; *p; p = &(*p)->next);
- *p = c;
-
- service->max_connections--;
-
- return ERROR_OK;
-}
-
-int remove_connection(service_t *service, connection_t *connection)
-{
- connection_t **p = &service->connections;
- connection_t *c;
-
- /* find connection */
- while(c = *p)
- {
- if (c->fd == connection->fd)
- {
- service->connection_closed(c);
- close_socket(c->fd);
- command_done(c->cmd_ctx);
-
- /* delete connection */
- *p = c->next;
- free(c);
-
- service->max_connections++;
- break;
- }
-
- /* redirect p to next list pointer */
- p = &(*p)->next;
- }
-
- return ERROR_OK;
-}
-
-int add_service(char *name, enum connection_type type, unsigned short port, int max_connections, new_connection_handler_t new_connection_handler, input_handler_t input_handler, connection_closed_handler_t connection_closed_handler, void *priv)
-{
- service_t *c, **p;
- int so_reuseaddr_option = 1;
-
- c = malloc(sizeof(service_t));
-
- c->name = strdup(name);
- c->type = type;
- c->port = port;
- c->max_connections = max_connections;
- c->fd = -1;
- c->connections = NULL;
- c->new_connection = new_connection_handler;
- c->input = input_handler;
- c->connection_closed = connection_closed_handler;
- c->priv = priv;
- c->next = NULL;
-
- if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
- {
- ERROR("error creating socket: %s", strerror(errno));
- exit(-1);
- }
-
- setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, (void*)&so_reuseaddr_option, sizeof(int));
-
- socket_nonblock(c->fd);
-
- memset(&c->sin, 0, sizeof(c->sin));
- c->sin.sin_family = AF_INET;
- c->sin.sin_addr.s_addr = INADDR_ANY;
- c->sin.sin_port = htons(port);
-
- if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1)
- {
- ERROR("couldn't bind to socket: %s", strerror(errno));
- exit(-1);
- }
-
- if (listen(c->fd, 1) == -1)
- {
- ERROR("couldn't listen on socket: %s", strerror(errno));
- exit(-1);
- }
-
- /* add to the end of linked list */
- for (p = &services; *p; p = &(*p)->next);
- *p = c;
-
- return ERROR_OK;
-}
-
-int remove_service(unsigned short port)
-{
- service_t **p = &services;
- service_t *c;
-
- /* find service */
- while(c = *p)
- {
- if (c->port == port)
- {
- if (c->name)
- free(c->name);
-
- if (c->priv)
- free(c->priv);
-
- /* delete service */
- *p = c->next;
- free(c);
- }
-
- /* redirect p to next list pointer */
- p = &(*p)->next;
- }
-
- return ERROR_OK;
-}
-
-int remove_services()
-{
- service_t *c = services;
-
- /* loop service */
- while(c)
- {
- service_t *next = c->next;
-
- if (c->name)
- free(c->name);
-
- if (c->priv)
- free(c->priv);
-
- /* delete service */
- free(c);
-
- /* remember the last service for unlinking */
- c = next;
- }
-
- services = NULL;
-
- return ERROR_OK;
-}
-
-int server_loop(command_context_t *command_context)
-{
- service_t *service;
-
- /* used in select() */
- fd_set read_fds;
- struct timeval tv;
- int fd_max;
-
- /* used in accept() */
- int retval;
-
-#ifndef _WIN32
- if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
- ERROR("couldn't set SIGPIPE to SIG_IGN");
-#endif
-
- /* do regular tasks after at most 10ms */
- tv.tv_sec = 0;
- tv.tv_usec = 10000;
-
- while(!shutdown_openocd)
- {
- /* monitor sockets for acitvity */
- fd_max = 0;
- FD_ZERO(&read_fds);
-
- /* add service and connection fds to read_fds */
- for (service = services; service; service = service->next)
- {
- if (service->fd != -1)
- {
- /* listen for new connections */
- FD_SET(service->fd, &read_fds);
-
- if (service->fd > fd_max)
- fd_max = service->fd;
- }
-
- if (service->connections)
- {
- connection_t *c;
-
- for (c = service->connections; c; c = c->next)
- {
- /* check for activity on the connection */
- FD_SET(c->fd, &read_fds);
- if (c->fd > fd_max)
- fd_max = c->fd;
- }
- }
- }
-
-#ifndef _WIN32
- /* add STDIN to read_fds */
- FD_SET(fileno(stdin), &read_fds);
-#endif
-
- retval = select(fd_max + 1, &read_fds, NULL, NULL, &tv);
-
- if (retval == -1)
- {
-#ifdef _WIN32
-
- errno = WSAGetLastError();
-
- if (errno == WSAEINTR)
- FD_ZERO(&read_fds);
- else
- {
- ERROR("error during select: %s", strerror(errno));
- exit(-1);
- }
-#else
-
- if (errno == EINTR)
- {
- FD_ZERO(&read_fds);
- }
- else
- {
- ERROR("error during select: %s", strerror(errno));
- exit(-1);
- }
-#endif
- }
-
- target_call_timer_callbacks();
-
- if (retval == 0)
- {
- /* do regular tasks after at most 100ms */
- tv.tv_sec = 0;
- tv.tv_usec = 10000;
- FD_ZERO(&read_fds); /* eCos leaves read_fds unchanged in this case! */
- }
-
- for (service = services; service; service = service->next)
- {
- /* handle new connections on listeners */
- if ((service->fd != -1)
- && (FD_ISSET(service->fd, &read_fds)))
- {
- if (service->max_connections > 0)
- {
- add_connection(service, command_context);
- }
- else
- {
- struct sockaddr_in sin;
- unsigned int address_size = sizeof(sin);
- int tmp_fd;
- tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
- close_socket(tmp_fd);
- INFO("rejected '%s' connection, no more connections allowed", service->name);
- }
- }
-
- /* handle activity on connections */
- if (service->connections)
- {
- connection_t *c;
-
- for (c = service->connections; c;)
- {
- if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending)
- {
- if (service->input(c) != ERROR_OK)
- {
- connection_t *next = c->next;
- remove_connection(service, c);
- INFO("dropped '%s' connection", service->name);
- c = next;
- continue;
- }
- }
- c = c->next;
- }
- }
- }
-
-#ifndef _WIN32
- if (FD_ISSET(fileno(stdin), &read_fds))
- {
- if (getc(stdin) == 'x')
- {
- shutdown_openocd = 1;
- }
- }
-#else
- MSG msg;
- while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
- {
- if (msg.message == WM_QUIT)
- shutdown_openocd = 1;
- }
-#endif
- }
-
- return ERROR_OK;
-}
-
-#ifdef _WIN32
-BOOL WINAPI ControlHandler(DWORD dwCtrlType)
-{
- shutdown_openocd = 1;
- return TRUE;
-}
-
-void sig_handler(int sig) {
- shutdown_openocd = 1;
-}
-#endif
-
-int server_init()
-{
-#ifdef _WIN32
- WORD wVersionRequested;
- WSADATA wsaData;
-
- wVersionRequested = MAKEWORD( 2, 2 );
-
- if (WSAStartup(wVersionRequested, &wsaData) != 0)
- {
- ERROR("Failed to Open Winsock");
- exit(-1);
- }
-
- SetConsoleCtrlHandler( ControlHandler, TRUE );
-
- signal(SIGINT, sig_handler);
- signal(SIGTERM, sig_handler);
- signal(SIGBREAK, sig_handler);
- signal(SIGABRT, sig_handler);
-#endif
-
-
- return ERROR_OK;
-}
-
-int server_quit()
-{
- remove_services();
-
-#ifdef _WIN32
- WSACleanup();
- SetConsoleCtrlHandler( ControlHandler, FALSE );
-#endif
-
- return ERROR_OK;
-}
-
-int server_register_commands(command_context_t *context)
-{
- register_command(context, NULL, "shutdown", handle_shutdown_command,
- COMMAND_ANY, "shut the server down");
-
- return ERROR_OK;
-}
-
-/* tell the server we want to shut down */
-int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- shutdown_openocd = 1;
-
- return ERROR_COMMAND_CLOSE_CONNECTION;
-}
-
-
+/*************************************************************************** + * 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 "server.h" + +#include "log.h" +#include "telnet_server.h" +#include "target.h" + +#include <command.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <signal.h> + +service_t *services = NULL; + +/* shutdown_openocd == 1: exit the main event loop, and quit the debugger */ +static int shutdown_openocd = 0; +int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int add_connection(service_t *service, command_context_t *cmd_ctx) +{ + unsigned int address_size; + connection_t *c, **p; + int retval; + + c = malloc(sizeof(connection_t)); + c->fd = -1; + memset(&c->sin, 0, sizeof(c->sin)); + c->cmd_ctx = copy_command_context(cmd_ctx); + c->service = service; + c->input_pending = 0; + c->priv = NULL; + c->next = NULL; + + address_size = sizeof(c->sin); + c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size); + + if ((retval = service->new_connection(c)) == ERROR_OK) + { + INFO("accepted '%s' connection from %i", service->name, c->sin.sin_port); + } + else + { + close_socket(c->fd); + INFO("attempted '%s' connection rejected", service->name); + free(c); + } + + /* add to the end of linked list */ + for (p = &service->connections; *p; p = &(*p)->next); + *p = c; + + service->max_connections--; + + return ERROR_OK; +} + +int remove_connection(service_t *service, connection_t *connection) +{ + connection_t **p = &service->connections; + connection_t *c; + + /* find connection */ + while(c = *p) + { + if (c->fd == connection->fd) + { + service->connection_closed(c); + close_socket(c->fd); + command_done(c->cmd_ctx); + + /* delete connection */ + *p = c->next; + free(c); + + service->max_connections++; + break; + } + + /* redirect p to next list pointer */ + p = &(*p)->next; + } + + return ERROR_OK; +} + +int add_service(char *name, enum connection_type type, unsigned short port, int max_connections, new_connection_handler_t new_connection_handler, input_handler_t input_handler, connection_closed_handler_t connection_closed_handler, void *priv) +{ + service_t *c, **p; + int so_reuseaddr_option = 1; + + c = malloc(sizeof(service_t)); + + c->name = strdup(name); + c->type = type; + c->port = port; + c->max_connections = max_connections; + c->fd = -1; + c->connections = NULL; + c->new_connection = new_connection_handler; + c->input = input_handler; + c->connection_closed = connection_closed_handler; + c->priv = priv; + c->next = NULL; + + if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + ERROR("error creating socket: %s", strerror(errno)); + exit(-1); + } + + setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, (void*)&so_reuseaddr_option, sizeof(int)); + + socket_nonblock(c->fd); + + memset(&c->sin, 0, sizeof(c->sin)); + c->sin.sin_family = AF_INET; + c->sin.sin_addr.s_addr = INADDR_ANY; + c->sin.sin_port = htons(port); + + if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) + { + ERROR("couldn't bind to socket: %s", strerror(errno)); + exit(-1); + } + + if (listen(c->fd, 1) == -1) + { + ERROR("couldn't listen on socket: %s", strerror(errno)); + exit(-1); + } + + /* add to the end of linked list */ + for (p = &services; *p; p = &(*p)->next); + *p = c; + + return ERROR_OK; +} + +int remove_service(unsigned short port) +{ + service_t **p = &services; + service_t *c; + + /* find service */ + while(c = *p) + { + if (c->port == port) + { + if (c->name) + free(c->name); + + if (c->priv) + free(c->priv); + + /* delete service */ + *p = c->next; + free(c); + } + + /* redirect p to next list pointer */ + p = &(*p)->next; + } + + return ERROR_OK; +} + +int remove_services() +{ + service_t *c = services; + + /* loop service */ + while(c) + { + service_t *next = c->next; + + if (c->name) + free(c->name); + + if (c->priv) + free(c->priv); + + /* delete service */ + free(c); + + /* remember the last service for unlinking */ + c = next; + } + + services = NULL; + + return ERROR_OK; +} + +int server_loop(command_context_t *command_context) +{ + service_t *service; + + /* used in select() */ + fd_set read_fds; + struct timeval tv; + int fd_max; + + /* used in accept() */ + int retval; + +#ifndef _WIN32 + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) + ERROR("couldn't set SIGPIPE to SIG_IGN"); +#endif + + /* do regular tasks after at most 10ms */ + tv.tv_sec = 0; + tv.tv_usec = 10000; + + while(!shutdown_openocd) + { + /* monitor sockets for acitvity */ + fd_max = 0; + FD_ZERO(&read_fds); + + /* add service and connection fds to read_fds */ + for (service = services; service; service = service->next) + { + if (service->fd != -1) + { + /* listen for new connections */ + FD_SET(service->fd, &read_fds); + + if (service->fd > fd_max) + fd_max = service->fd; + } + + if (service->connections) + { + connection_t *c; + + for (c = service->connections; c; c = c->next) + { + /* check for activity on the connection */ + FD_SET(c->fd, &read_fds); + if (c->fd > fd_max) + fd_max = c->fd; + } + } + } + +#ifndef _WIN32 + /* add STDIN to read_fds */ + FD_SET(fileno(stdin), &read_fds); +#endif + + retval = select(fd_max + 1, &read_fds, NULL, NULL, &tv); + + if (retval == -1) + { +#ifdef _WIN32 + + errno = WSAGetLastError(); + + if (errno == WSAEINTR) + FD_ZERO(&read_fds); + else + { + ERROR("error during select: %s", strerror(errno)); + exit(-1); + } +#else + + if (errno == EINTR) + { + FD_ZERO(&read_fds); + } + else + { + ERROR("error during select: %s", strerror(errno)); + exit(-1); + } +#endif + } + + target_call_timer_callbacks(); + + if (retval == 0) + { + /* do regular tasks after at most 100ms */ + tv.tv_sec = 0; + tv.tv_usec = 10000; + FD_ZERO(&read_fds); /* eCos leaves read_fds unchanged in this case! */ + } + + for (service = services; service; service = service->next) + { + /* handle new connections on listeners */ + if ((service->fd != -1) + && (FD_ISSET(service->fd, &read_fds))) + { + if (service->max_connections > 0) + { + add_connection(service, command_context); + } + else + { + struct sockaddr_in sin; + unsigned int address_size = sizeof(sin); + int tmp_fd; + tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size); + close_socket(tmp_fd); + INFO("rejected '%s' connection, no more connections allowed", service->name); + } + } + + /* handle activity on connections */ + if (service->connections) + { + connection_t *c; + + for (c = service->connections; c;) + { + if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending) + { + if (service->input(c) != ERROR_OK) + { + connection_t *next = c->next; + remove_connection(service, c); + INFO("dropped '%s' connection", service->name); + c = next; + continue; + } + } + c = c->next; + } + } + } + +#ifndef _WIN32 + if (FD_ISSET(fileno(stdin), &read_fds)) + { + if (getc(stdin) == 'x') + { + shutdown_openocd = 1; + } + } +#else + MSG msg; + while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) + { + if (msg.message == WM_QUIT) + shutdown_openocd = 1; + } +#endif + } + + return ERROR_OK; +} + +#ifdef _WIN32 +BOOL WINAPI ControlHandler(DWORD dwCtrlType) +{ + shutdown_openocd = 1; + return TRUE; +} + +void sig_handler(int sig) { + shutdown_openocd = 1; +} +#endif + +int server_init() +{ +#ifdef _WIN32 + WORD wVersionRequested; + WSADATA wsaData; + + wVersionRequested = MAKEWORD( 2, 2 ); + + if (WSAStartup(wVersionRequested, &wsaData) != 0) + { + ERROR("Failed to Open Winsock"); + exit(-1); + } + + SetConsoleCtrlHandler( ControlHandler, TRUE ); + + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + signal(SIGBREAK, sig_handler); + signal(SIGABRT, sig_handler); +#endif + + + return ERROR_OK; +} + +int server_quit() +{ + remove_services(); + +#ifdef _WIN32 + WSACleanup(); + SetConsoleCtrlHandler( ControlHandler, FALSE ); +#endif + + return ERROR_OK; +} + +int server_register_commands(command_context_t *context) +{ + register_command(context, NULL, "shutdown", handle_shutdown_command, + COMMAND_ANY, "shut the server down"); + + return ERROR_OK; +} + +/* tell the server we want to shut down */ +int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + shutdown_openocd = 1; + + return ERROR_COMMAND_CLOSE_CONNECTION; +} + + diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index 830cf64..5cfb0ab 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -1,631 +1,631 @@ -/***************************************************************************
- * 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 "telnet_server.h"
-
-#include "server.h"
-#include "log.h"
-#include "command.h"
-#include "target.h"
-#include "target_request.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <ctype.h>
-
-static unsigned short telnet_port = 0;
-
-int handle_exit_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_telnet_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-static char *negotiate =
- "\xFF\xFB\x03" /* IAC WILL Suppress Go Ahead */
- "\xFF\xFB\x01" /* IAC WILL Echo */
- "\xFF\xFD\x03" /* IAC DO Suppress Go Ahead */
- "\xFF\xFE\x01"; /* IAC DON'T Echo */
-
-#define CTRL(c) (c - '@')
-
-/* The only way we can detect that the socket is closed is the first time
- * we write to it, we will fail. Subsequent write operations will
- * succeed. Shudder!
- */
-int telnet_write(connection_t *connection, void *data, int len)
-{
- telnet_connection_t *t_con = connection->priv;
- if (t_con->closed)
- return ERROR_SERVER_REMOTE_CLOSED;
-
- if (write_socket(connection->fd, data, len) == len)
- {
- return ERROR_OK;
- }
- t_con->closed = 1;
- return ERROR_SERVER_REMOTE_CLOSED;
-}
-
-int telnet_prompt(connection_t *connection)
-{
- telnet_connection_t *t_con = connection->priv;
-
- return telnet_write(connection, t_con->prompt, strlen(t_con->prompt));
-}
-
-int telnet_outputline(connection_t *connection, char* line)
-{
- telnet_write(connection, line, strlen(line));
- return telnet_write(connection, "\r\n\0", 3);
-}
-
-int telnet_output(struct command_context_s *cmd_ctx, char* line)
-{
- connection_t *connection = cmd_ctx->output_handler_priv;
-
- return telnet_outputline(connection, line);
-}
-
-void telnet_log_callback(void *priv, const char *file, int line,
- const char *function, const char *format, va_list args)
-{
- connection_t *connection = priv;
- char *t = alloc_printf(format, args);
- char *t2;
- if (t == NULL)
- return;
- t2=t;
- char *endline;
- do
- {
- if ((endline=strchr(t2, '\n'))!=NULL)
- {
- *endline=0;
- }
- telnet_outputline(connection, t2);
- t2=endline+1;
- } while (endline);
-
- free(t);
-}
-
-int telnet_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv)
-{
- struct command_context_s *cmd_ctx = priv;
- connection_t *connection = cmd_ctx->output_handler_priv;
- telnet_connection_t *t_con = connection->priv;
-
- switch (event)
- {
- case TARGET_EVENT_HALTED:
- target_arch_state(target);
- if (!t_con->suppress_prompt)
- telnet_prompt(connection);
- break;
- case TARGET_EVENT_RESUMED:
- if (!t_con->suppress_prompt)
- telnet_prompt(connection);
- break;
- default:
- break;
- }
-
- return ERROR_OK;
-}
-
-int telnet_new_connection(connection_t *connection)
-{
- telnet_connection_t *telnet_connection = malloc(sizeof(telnet_connection_t));
- telnet_service_t *telnet_service = connection->service->priv;
- int i;
-
- connection->priv = telnet_connection;
-
- /* initialize telnet connection information */
- telnet_connection->closed = 0;
- telnet_connection->line_size = 0;
- telnet_connection->line_cursor = 0;
- telnet_connection->option_size = 0;
- telnet_connection->prompt = strdup("> ");
- telnet_connection->suppress_prompt = 0;
- telnet_connection->state = TELNET_STATE_DATA;
-
- /* output goes through telnet connection */
- command_set_output_handler(connection->cmd_ctx, telnet_output, connection);
-
- /* negotiate telnet options */
- telnet_write(connection, negotiate, strlen(negotiate));
-
- /* print connection banner */
- if (telnet_service->banner)
- {
- telnet_write(connection, telnet_service->banner, strlen(telnet_service->banner));
- telnet_write(connection, "\r\n\0", 3);
- }
-
- telnet_prompt(connection);
-
- /* initialize history */
- for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++)
- {
- telnet_connection->history[i] = NULL;
- }
- telnet_connection->next_history = 0;
- telnet_connection->current_history = 0;
-
- target_register_event_callback(telnet_target_callback_event_handler, connection->cmd_ctx);
-
- return ERROR_OK;
-}
-
-void telnet_clear_line(connection_t *connection, telnet_connection_t *t_con)
-{
- /* move to end of line */
- if (t_con->line_cursor < t_con->line_size)
- {
- telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);
- }
-
- /* backspace, overwrite with space, backspace */
- while (t_con->line_size > 0)
- {
- telnet_write(connection, "\b \b", 3);
- t_con->line_size--;
- }
- t_con->line_cursor = 0;
-}
-
-int telnet_input(connection_t *connection)
-{
- int bytes_read;
- char buffer[TELNET_BUFFER_SIZE];
- char *buf_p;
- telnet_connection_t *t_con = connection->priv;
- command_context_t *command_context = connection->cmd_ctx;
-
- bytes_read = read_socket(connection->fd, buffer, TELNET_BUFFER_SIZE);
-
- if (bytes_read == 0)
- return ERROR_SERVER_REMOTE_CLOSED;
- else if (bytes_read == -1)
- {
- ERROR("error during read: %s", strerror(errno));
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- buf_p = buffer;
- while (bytes_read)
- {
- switch (t_con->state)
- {
- case TELNET_STATE_DATA:
- if (*buf_p == '\xff')
- {
- t_con->state = TELNET_STATE_IAC;
- }
- else
- {
- if (isprint(*buf_p)) /* printable character */
- {
- telnet_write(connection, buf_p, 1);
- if (t_con->line_cursor == t_con->line_size)
- {
- t_con->line[t_con->line_size++] = *buf_p;
- t_con->line_cursor++;
- }
- else
- {
- int i;
- memmove(t_con->line + t_con->line_cursor + 1, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);
- t_con->line[t_con->line_cursor++] = *buf_p;
- t_con->line_size++;
- telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);
- for (i = t_con->line_cursor; i < t_con->line_size; i++)
- {
- telnet_write(connection, "\b", 1);
- }
- }
- }
- else /* non-printable */
- {
- if (*buf_p == 0x1b) /* escape */
- {
- t_con->state = TELNET_STATE_ESCAPE;
- t_con->last_escape = '\x00';
- }
- else if ((*buf_p == 0xd) || (*buf_p == 0xa)) /* CR/LF */
- {
- int retval;
-
- /* skip over combinations with CR/LF + NUL */
- if (((*(buf_p + 1) == 0xa) || (*(buf_p + 1) == 0xd)) && (bytes_read > 1))
- {
- buf_p++;
- bytes_read--;
- }
- if ((*(buf_p + 1) == 0) && (bytes_read > 1))
- {
- buf_p++;
- bytes_read--;
- }
- t_con->line[t_con->line_size] = 0;
-
- telnet_write(connection, "\r\n\x00", 3);
-
- if (strcmp(t_con->line, "history") == 0)
- {
- int i;
- for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++)
- {
- if (t_con->history[i])
- {
- telnet_write(connection, t_con->history[i], strlen(t_con->history[i]));
- telnet_write(connection, "\r\n\x00", 3);
- }
- }
- telnet_prompt(connection);
- t_con->line_size = 0;
- t_con->line_cursor = 0;
- continue;
- }
-
- log_add_callback(telnet_log_callback, connection);
- t_con->suppress_prompt = 1;
-
- retval = command_run_line(command_context, t_con->line);
-
- log_remove_callback(telnet_log_callback, connection);
- t_con->suppress_prompt = 0;
-
- if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
- {
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- /* Save only non-blank lines in the history */
- if (t_con->line_size > 0)
- {
- /* if the history slot is already taken, free it */
- if (t_con->history[t_con->next_history])
- {
- free(t_con->history[t_con->next_history]);
- }
-
- /* add line to history */
- t_con->history[t_con->next_history] = strdup(t_con->line);
-
- /* wrap history at TELNET_LINE_HISTORY_SIZE */
- t_con->next_history = (t_con->next_history + 1) % TELNET_LINE_HISTORY_SIZE;
-
- /* current history line starts at the new entry */
- t_con->current_history = t_con->next_history;
-
- if (t_con->history[t_con->current_history])
- {
- free(t_con->history[t_con->current_history]);
- }
- t_con->history[t_con->current_history] = strdup("");
- }
-
- int t = telnet_prompt(connection);
- if (t == ERROR_SERVER_REMOTE_CLOSED)
- return t;
-
- t_con->line_size = 0;
- t_con->line_cursor = 0;
- }
- else if ((*buf_p == 0x7f) || (*buf_p == 0x8)) /* delete character */
- {
- if (t_con->line_cursor > 0)
- {
- if (t_con->line_cursor != t_con->line_size)
- {
- int i;
- telnet_write(connection, "\b", 1);
- t_con->line_cursor--;
- t_con->line_size--;
- memmove(t_con->line + t_con->line_cursor, t_con->line + t_con->line_cursor + 1, t_con->line_size - t_con->line_cursor);
-
- telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);
- telnet_write(connection, " \b", 2);
- for (i = t_con->line_cursor; i < t_con->line_size; i++)
- {
- telnet_write(connection, "\b", 1);
- }
- }
- else
- {
- t_con->line_size--;
- t_con->line_cursor--;
- /* back space: move the 'printer' head one char back, overwrite with space, move back again */
- telnet_write(connection, "\b \b", 3);
- }
- }
- }
- else if (*buf_p == 0x15) /* clear line */
- {
- telnet_clear_line(connection, t_con);
- }
- else if (*buf_p == CTRL('B')) /* cursor left */
- {
- if (t_con->line_cursor > 0)
- {
- telnet_write(connection, "\b", 1);
- t_con->line_cursor--;
- }
- t_con->state = TELNET_STATE_DATA;
- }
- else if (*buf_p == CTRL('F')) /* cursor right */
- {
- if (t_con->line_cursor < t_con->line_size)
- {
- telnet_write(connection, t_con->line + t_con->line_cursor++, 1);
- }
- t_con->state = TELNET_STATE_DATA;
- }
- else
- {
- DEBUG("unhandled nonprintable: %2.2x", *buf_p);
- }
- }
- }
- break;
- case TELNET_STATE_IAC:
- switch (*buf_p)
- {
- case '\xfe':
- t_con->state = TELNET_STATE_DONT;
- break;
- case '\xfd':
- t_con->state = TELNET_STATE_DO;
- break;
- case '\xfc':
- t_con->state = TELNET_STATE_WONT;
- break;
- case '\xfb':
- t_con->state = TELNET_STATE_WILL;
- break;
- }
- break;
- case TELNET_STATE_SB:
- break;
- case TELNET_STATE_SE:
- break;
- case TELNET_STATE_WILL:
- case TELNET_STATE_WONT:
- case TELNET_STATE_DO:
- case TELNET_STATE_DONT:
- t_con->state = TELNET_STATE_DATA;
- break;
- case TELNET_STATE_ESCAPE:
- if (t_con->last_escape == '[')
- {
- if (*buf_p == 'D') /* cursor left */
- {
- if (t_con->line_cursor > 0)
- {
- telnet_write(connection, "\b", 1);
- t_con->line_cursor--;
- }
- t_con->state = TELNET_STATE_DATA;
- }
- else if (*buf_p == 'C') /* cursor right */
- {
- if (t_con->line_cursor < t_con->line_size)
- {
- telnet_write(connection, t_con->line + t_con->line_cursor++, 1);
- }
- t_con->state = TELNET_STATE_DATA;
- }
- else if (*buf_p == 'A') /* cursor up */
- {
- int last_history = (t_con->current_history > 0) ? t_con->current_history - 1 : TELNET_LINE_HISTORY_SIZE-1;
- if (t_con->history[last_history])
- {
- telnet_clear_line(connection, t_con);
- t_con->line_size = strlen(t_con->history[last_history]);
- t_con->line_cursor = t_con->line_size;
- memcpy(t_con->line, t_con->history[last_history], t_con->line_size + 1);
- telnet_write(connection, t_con->line, t_con->line_size);
- t_con->current_history = last_history;
- }
- t_con->state = TELNET_STATE_DATA;
- }
- else if (*buf_p == 'B') /* cursor down */
- {
- int next_history = (t_con->current_history + 1) % TELNET_LINE_HISTORY_SIZE;
- if (t_con->history[next_history])
- {
- telnet_clear_line(connection, t_con);
- t_con->line_size = strlen(t_con->history[next_history]);
- t_con->line_cursor = t_con->line_size;
- memcpy(t_con->line, t_con->history[next_history], t_con->line_size + 1);
- telnet_write(connection, t_con->line, t_con->line_size);
- t_con->current_history = next_history;
- }
- t_con->state = TELNET_STATE_DATA;
- }
- else if (*buf_p == '3')
- {
- t_con->last_escape = *buf_p;
- }
- else
- {
- t_con->state = TELNET_STATE_DATA;
- }
- }
- else if (t_con->last_escape == '3')
- {
- /* Remove character */
- if (*buf_p == '~')
- {
- if (t_con->line_cursor < t_con->line_size)
- {
- int i;
- t_con->line_size--;
- /* remove char from line buffer */
- memmove(t_con->line + t_con->line_cursor, t_con->line + t_con->line_cursor + 1, t_con->line_size - t_con->line_cursor);
-
- /* print remainder of buffer */
- telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);
- /* overwrite last char with whitespace */
- telnet_write(connection, " \b", 2);
-
- /* move back to cursor position*/
- for (i = t_con->line_cursor; i < t_con->line_size; i++)
- {
- telnet_write(connection, "\b", 1);
- }
- }
-
- t_con->state = TELNET_STATE_DATA;
- }
- else
- {
- t_con->state = TELNET_STATE_DATA;
- }
- }
- else if (t_con->last_escape == '\x00')
- {
- if (*buf_p == '[')
- {
- t_con->last_escape = *buf_p;
- }
- else
- {
- t_con->state = TELNET_STATE_DATA;
- }
- }
- else
- {
- ERROR("BUG: unexpected value in t_con->last_escape");
- t_con->state = TELNET_STATE_DATA;
- }
-
- break;
- default:
- ERROR("unknown telnet state");
- exit(-1);
- }
-
- bytes_read--;
- buf_p++;
- }
-
- return ERROR_OK;
-}
-
-int telnet_connection_closed(connection_t *connection)
-{
- telnet_connection_t *t_con = connection->priv;
- int i;
-
- if (t_con->prompt)
- {
- free(t_con->prompt);
- t_con->prompt = NULL;
- }
-
- for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++)
- {
- if (t_con->history[i])
- {
- free(t_con->history[i]);
- t_con->history[i] = NULL;
- }
- }
-
- /* if this connection registered a debug-message receiver delete it */
- delete_debug_msg_receiver(connection->cmd_ctx, NULL);
-
- if (connection->priv)
- {
- free(connection->priv);
- connection->priv = NULL;
- }
- else
- {
- ERROR("BUG: connection->priv == NULL");
- }
-
- target_unregister_event_callback(telnet_target_callback_event_handler, connection->cmd_ctx);
-
- return ERROR_OK;
-}
-
-int telnet_set_prompt(connection_t *connection, char *prompt)
-{
- telnet_connection_t *t_con = connection->priv;
-
- t_con->prompt = strdup(prompt);
-
- return ERROR_OK;
-}
-
-int telnet_init(char *banner)
-{
- telnet_service_t *telnet_service = malloc(sizeof(telnet_service_t));
-
- if (telnet_port == 0)
- {
- WARNING("no telnet port specified, using default port 4444");
- telnet_port = 4444;
- }
-
- telnet_service->banner = banner;
-
- add_service("telnet", CONNECTION_TELNET, telnet_port, 1, telnet_new_connection, telnet_input, telnet_connection_closed, telnet_service);
-
- return ERROR_OK;
-}
-
-int telnet_register_commands(command_context_t *command_context)
-{
- register_command(command_context, NULL, "exit", handle_exit_command,
- COMMAND_EXEC, "exit telnet session");
-
- register_command(command_context, NULL, "telnet_port", handle_telnet_port_command,
- COMMAND_CONFIG, "");
-
- return ERROR_OK;
-}
-
-/* daemon configuration command telnet_port */
-int handle_telnet_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 0)
- return ERROR_OK;
-
- /* only if the port wasn't overwritten by cmdline */
- if (telnet_port == 0)
- telnet_port = strtoul(args[0], NULL, 0);
-
- return ERROR_OK;
-}
-
-int handle_exit_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- return ERROR_COMMAND_CLOSE_CONNECTION;
-}
+/*************************************************************************** + * 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 "telnet_server.h" + +#include "server.h" +#include "log.h" +#include "command.h" +#include "target.h" +#include "target_request.h" + +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <ctype.h> + +static unsigned short telnet_port = 0; + +int handle_exit_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_telnet_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +static char *negotiate = + "\xFF\xFB\x03" /* IAC WILL Suppress Go Ahead */ + "\xFF\xFB\x01" /* IAC WILL Echo */ + "\xFF\xFD\x03" /* IAC DO Suppress Go Ahead */ + "\xFF\xFE\x01"; /* IAC DON'T Echo */ + +#define CTRL(c) (c - '@') + +/* The only way we can detect that the socket is closed is the first time + * we write to it, we will fail. Subsequent write operations will + * succeed. Shudder! + */ +int telnet_write(connection_t *connection, void *data, int len) +{ + telnet_connection_t *t_con = connection->priv; + if (t_con->closed) + return ERROR_SERVER_REMOTE_CLOSED; + + if (write_socket(connection->fd, data, len) == len) + { + return ERROR_OK; + } + t_con->closed = 1; + return ERROR_SERVER_REMOTE_CLOSED; +} + +int telnet_prompt(connection_t *connection) +{ + telnet_connection_t *t_con = connection->priv; + + return telnet_write(connection, t_con->prompt, strlen(t_con->prompt)); +} + +int telnet_outputline(connection_t *connection, char* line) +{ + telnet_write(connection, line, strlen(line)); + return telnet_write(connection, "\r\n\0", 3); +} + +int telnet_output(struct command_context_s *cmd_ctx, char* line) +{ + connection_t *connection = cmd_ctx->output_handler_priv; + + return telnet_outputline(connection, line); +} + +void telnet_log_callback(void *priv, const char *file, int line, + const char *function, const char *format, va_list args) +{ + connection_t *connection = priv; + char *t = alloc_printf(format, args); + char *t2; + if (t == NULL) + return; + t2=t; + char *endline; + do + { + if ((endline=strchr(t2, '\n'))!=NULL) + { + *endline=0; + } + telnet_outputline(connection, t2); + t2=endline+1; + } while (endline); + + free(t); +} + +int telnet_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv) +{ + struct command_context_s *cmd_ctx = priv; + connection_t *connection = cmd_ctx->output_handler_priv; + telnet_connection_t *t_con = connection->priv; + + switch (event) + { + case TARGET_EVENT_HALTED: + target_arch_state(target); + if (!t_con->suppress_prompt) + telnet_prompt(connection); + break; + case TARGET_EVENT_RESUMED: + if (!t_con->suppress_prompt) + telnet_prompt(connection); + break; + default: + break; + } + + return ERROR_OK; +} + +int telnet_new_connection(connection_t *connection) +{ + telnet_connection_t *telnet_connection = malloc(sizeof(telnet_connection_t)); + telnet_service_t *telnet_service = connection->service->priv; + int i; + + connection->priv = telnet_connection; + + /* initialize telnet connection information */ + telnet_connection->closed = 0; + telnet_connection->line_size = 0; + telnet_connection->line_cursor = 0; + telnet_connection->option_size = 0; + telnet_connection->prompt = strdup("> "); + telnet_connection->suppress_prompt = 0; + telnet_connection->state = TELNET_STATE_DATA; + + /* output goes through telnet connection */ + command_set_output_handler(connection->cmd_ctx, telnet_output, connection); + + /* negotiate telnet options */ + telnet_write(connection, negotiate, strlen(negotiate)); + + /* print connection banner */ + if (telnet_service->banner) + { + telnet_write(connection, telnet_service->banner, strlen(telnet_service->banner)); + telnet_write(connection, "\r\n\0", 3); + } + + telnet_prompt(connection); + + /* initialize history */ + for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++) + { + telnet_connection->history[i] = NULL; + } + telnet_connection->next_history = 0; + telnet_connection->current_history = 0; + + target_register_event_callback(telnet_target_callback_event_handler, connection->cmd_ctx); + + return ERROR_OK; +} + +void telnet_clear_line(connection_t *connection, telnet_connection_t *t_con) +{ + /* move to end of line */ + if (t_con->line_cursor < t_con->line_size) + { + telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor); + } + + /* backspace, overwrite with space, backspace */ + while (t_con->line_size > 0) + { + telnet_write(connection, "\b \b", 3); + t_con->line_size--; + } + t_con->line_cursor = 0; +} + +int telnet_input(connection_t *connection) +{ + int bytes_read; + char buffer[TELNET_BUFFER_SIZE]; + char *buf_p; + telnet_connection_t *t_con = connection->priv; + command_context_t *command_context = connection->cmd_ctx; + + bytes_read = read_socket(connection->fd, buffer, TELNET_BUFFER_SIZE); + + if (bytes_read == 0) + return ERROR_SERVER_REMOTE_CLOSED; + else if (bytes_read == -1) + { + ERROR("error during read: %s", strerror(errno)); + return ERROR_SERVER_REMOTE_CLOSED; + } + + buf_p = buffer; + while (bytes_read) + { + switch (t_con->state) + { + case TELNET_STATE_DATA: + if (*buf_p == '\xff') + { + t_con->state = TELNET_STATE_IAC; + } + else + { + if (isprint(*buf_p)) /* printable character */ + { + telnet_write(connection, buf_p, 1); + if (t_con->line_cursor == t_con->line_size) + { + t_con->line[t_con->line_size++] = *buf_p; + t_con->line_cursor++; + } + else + { + int i; + memmove(t_con->line + t_con->line_cursor + 1, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor); + t_con->line[t_con->line_cursor++] = *buf_p; + t_con->line_size++; + telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor); + for (i = t_con->line_cursor; i < t_con->line_size; i++) + { + telnet_write(connection, "\b", 1); + } + } + } + else /* non-printable */ + { + if (*buf_p == 0x1b) /* escape */ + { + t_con->state = TELNET_STATE_ESCAPE; + t_con->last_escape = '\x00'; + } + else if ((*buf_p == 0xd) || (*buf_p == 0xa)) /* CR/LF */ + { + int retval; + + /* skip over combinations with CR/LF + NUL */ + if (((*(buf_p + 1) == 0xa) || (*(buf_p + 1) == 0xd)) && (bytes_read > 1)) + { + buf_p++; + bytes_read--; + } + if ((*(buf_p + 1) == 0) && (bytes_read > 1)) + { + buf_p++; + bytes_read--; + } + t_con->line[t_con->line_size] = 0; + + telnet_write(connection, "\r\n\x00", 3); + + if (strcmp(t_con->line, "history") == 0) + { + int i; + for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++) + { + if (t_con->history[i]) + { + telnet_write(connection, t_con->history[i], strlen(t_con->history[i])); + telnet_write(connection, "\r\n\x00", 3); + } + } + telnet_prompt(connection); + t_con->line_size = 0; + t_con->line_cursor = 0; + continue; + } + + log_add_callback(telnet_log_callback, connection); + t_con->suppress_prompt = 1; + + retval = command_run_line(command_context, t_con->line); + + log_remove_callback(telnet_log_callback, connection); + t_con->suppress_prompt = 0; + + if (retval == ERROR_COMMAND_CLOSE_CONNECTION) + { + return ERROR_SERVER_REMOTE_CLOSED; + } + + /* Save only non-blank lines in the history */ + if (t_con->line_size > 0) + { + /* if the history slot is already taken, free it */ + if (t_con->history[t_con->next_history]) + { + free(t_con->history[t_con->next_history]); + } + + /* add line to history */ + t_con->history[t_con->next_history] = strdup(t_con->line); + + /* wrap history at TELNET_LINE_HISTORY_SIZE */ + t_con->next_history = (t_con->next_history + 1) % TELNET_LINE_HISTORY_SIZE; + + /* current history line starts at the new entry */ + t_con->current_history = t_con->next_history; + + if (t_con->history[t_con->current_history]) + { + free(t_con->history[t_con->current_history]); + } + t_con->history[t_con->current_history] = strdup(""); + } + + int t = telnet_prompt(connection); + if (t == ERROR_SERVER_REMOTE_CLOSED) + return t; + + t_con->line_size = 0; + t_con->line_cursor = 0; + } + else if ((*buf_p == 0x7f) || (*buf_p == 0x8)) /* delete character */ + { + if (t_con->line_cursor > 0) + { + if (t_con->line_cursor != t_con->line_size) + { + int i; + telnet_write(connection, "\b", 1); + t_con->line_cursor--; + t_con->line_size--; + memmove(t_con->line + t_con->line_cursor, t_con->line + t_con->line_cursor + 1, t_con->line_size - t_con->line_cursor); + + telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor); + telnet_write(connection, " \b", 2); + for (i = t_con->line_cursor; i < t_con->line_size; i++) + { + telnet_write(connection, "\b", 1); + } + } + else + { + t_con->line_size--; + t_con->line_cursor--; + /* back space: move the 'printer' head one char back, overwrite with space, move back again */ + telnet_write(connection, "\b \b", 3); + } + } + } + else if (*buf_p == 0x15) /* clear line */ + { + telnet_clear_line(connection, t_con); + } + else if (*buf_p == CTRL('B')) /* cursor left */ + { + if (t_con->line_cursor > 0) + { + telnet_write(connection, "\b", 1); + t_con->line_cursor--; + } + t_con->state = TELNET_STATE_DATA; + } + else if (*buf_p == CTRL('F')) /* cursor right */ + { + if (t_con->line_cursor < t_con->line_size) + { + telnet_write(connection, t_con->line + t_con->line_cursor++, 1); + } + t_con->state = TELNET_STATE_DATA; + } + else + { + DEBUG("unhandled nonprintable: %2.2x", *buf_p); + } + } + } + break; + case TELNET_STATE_IAC: + switch (*buf_p) + { + case '\xfe': + t_con->state = TELNET_STATE_DONT; + break; + case '\xfd': + t_con->state = TELNET_STATE_DO; + break; + case '\xfc': + t_con->state = TELNET_STATE_WONT; + break; + case '\xfb': + t_con->state = TELNET_STATE_WILL; + break; + } + break; + case TELNET_STATE_SB: + break; + case TELNET_STATE_SE: + break; + case TELNET_STATE_WILL: + case TELNET_STATE_WONT: + case TELNET_STATE_DO: + case TELNET_STATE_DONT: + t_con->state = TELNET_STATE_DATA; + break; + case TELNET_STATE_ESCAPE: + if (t_con->last_escape == '[') + { + if (*buf_p == 'D') /* cursor left */ + { + if (t_con->line_cursor > 0) + { + telnet_write(connection, "\b", 1); + t_con->line_cursor--; + } + t_con->state = TELNET_STATE_DATA; + } + else if (*buf_p == 'C') /* cursor right */ + { + if (t_con->line_cursor < t_con->line_size) + { + telnet_write(connection, t_con->line + t_con->line_cursor++, 1); + } + t_con->state = TELNET_STATE_DATA; + } + else if (*buf_p == 'A') /* cursor up */ + { + int last_history = (t_con->current_history > 0) ? t_con->current_history - 1 : TELNET_LINE_HISTORY_SIZE-1; + if (t_con->history[last_history]) + { + telnet_clear_line(connection, t_con); + t_con->line_size = strlen(t_con->history[last_history]); + t_con->line_cursor = t_con->line_size; + memcpy(t_con->line, t_con->history[last_history], t_con->line_size + 1); + telnet_write(connection, t_con->line, t_con->line_size); + t_con->current_history = last_history; + } + t_con->state = TELNET_STATE_DATA; + } + else if (*buf_p == 'B') /* cursor down */ + { + int next_history = (t_con->current_history + 1) % TELNET_LINE_HISTORY_SIZE; + if (t_con->history[next_history]) + { + telnet_clear_line(connection, t_con); + t_con->line_size = strlen(t_con->history[next_history]); + t_con->line_cursor = t_con->line_size; + memcpy(t_con->line, t_con->history[next_history], t_con->line_size + 1); + telnet_write(connection, t_con->line, t_con->line_size); + t_con->current_history = next_history; + } + t_con->state = TELNET_STATE_DATA; + } + else if (*buf_p == '3') + { + t_con->last_escape = *buf_p; + } + else + { + t_con->state = TELNET_STATE_DATA; + } + } + else if (t_con->last_escape == '3') + { + /* Remove character */ + if (*buf_p == '~') + { + if (t_con->line_cursor < t_con->line_size) + { + int i; + t_con->line_size--; + /* remove char from line buffer */ + memmove(t_con->line + t_con->line_cursor, t_con->line + t_con->line_cursor + 1, t_con->line_size - t_con->line_cursor); + + /* print remainder of buffer */ + telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor); + /* overwrite last char with whitespace */ + telnet_write(connection, " \b", 2); + + /* move back to cursor position*/ + for (i = t_con->line_cursor; i < t_con->line_size; i++) + { + telnet_write(connection, "\b", 1); + } + } + + t_con->state = TELNET_STATE_DATA; + } + else + { + t_con->state = TELNET_STATE_DATA; + } + } + else if (t_con->last_escape == '\x00') + { + if (*buf_p == '[') + { + t_con->last_escape = *buf_p; + } + else + { + t_con->state = TELNET_STATE_DATA; + } + } + else + { + ERROR("BUG: unexpected value in t_con->last_escape"); + t_con->state = TELNET_STATE_DATA; + } + + break; + default: + ERROR("unknown telnet state"); + exit(-1); + } + + bytes_read--; + buf_p++; + } + + return ERROR_OK; +} + +int telnet_connection_closed(connection_t *connection) +{ + telnet_connection_t *t_con = connection->priv; + int i; + + if (t_con->prompt) + { + free(t_con->prompt); + t_con->prompt = NULL; + } + + for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++) + { + if (t_con->history[i]) + { + free(t_con->history[i]); + t_con->history[i] = NULL; + } + } + + /* if this connection registered a debug-message receiver delete it */ + delete_debug_msg_receiver(connection->cmd_ctx, NULL); + + if (connection->priv) + { + free(connection->priv); + connection->priv = NULL; + } + else + { + ERROR("BUG: connection->priv == NULL"); + } + + target_unregister_event_callback(telnet_target_callback_event_handler, connection->cmd_ctx); + + return ERROR_OK; +} + +int telnet_set_prompt(connection_t *connection, char *prompt) +{ + telnet_connection_t *t_con = connection->priv; + + t_con->prompt = strdup(prompt); + + return ERROR_OK; +} + +int telnet_init(char *banner) +{ + telnet_service_t *telnet_service = malloc(sizeof(telnet_service_t)); + + if (telnet_port == 0) + { + WARNING("no telnet port specified, using default port 4444"); + telnet_port = 4444; + } + + telnet_service->banner = banner; + + add_service("telnet", CONNECTION_TELNET, telnet_port, 1, telnet_new_connection, telnet_input, telnet_connection_closed, telnet_service); + + return ERROR_OK; +} + +int telnet_register_commands(command_context_t *command_context) +{ + register_command(command_context, NULL, "exit", handle_exit_command, + COMMAND_EXEC, "exit telnet session"); + + register_command(command_context, NULL, "telnet_port", handle_telnet_port_command, + COMMAND_CONFIG, ""); + + return ERROR_OK; +} + +/* daemon configuration command telnet_port */ +int handle_telnet_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 0) + return ERROR_OK; + + /* only if the port wasn't overwritten by cmdline */ + if (telnet_port == 0) + telnet_port = strtoul(args[0], NULL, 0); + + return ERROR_OK; +} + +int handle_exit_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + return ERROR_COMMAND_CLOSE_CONNECTION; +} diff --git a/src/target/arm11.c b/src/target/arm11.c index 11e376a..d02518a 100644 --- a/src/target/arm11.c +++ b/src/target/arm11.c @@ -1,1358 +1,1358 @@ -/***************************************************************************
- * Copyright (C) 2008 digenius technology GmbH. *
- * *
- * 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 "arm11.h"
-#include "jtag.h"
-#include "log.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#if 0
-#define _DEBUG_INSTRUCTION_EXECUTION_
-#endif
-
-
-#if 0
-#define FNC_INFO DEBUG("-")
-#else
-#define FNC_INFO
-#endif
-
-#if 1
-#define FNC_INFO_NOTIMPLEMENTED do { DEBUG("NOT IMPLEMENTED"); /*exit(-1);*/ } while (0)
-#else
-#define FNC_INFO_NOTIMPLEMENTED
-#endif
-
-static void arm11_on_enter_debug_state(arm11_common_t * arm11);
-
-
-#define ARM11_HANDLER(x) \
- .x = arm11_##x
-
-target_type_t arm11_target =
-{
- .name = "arm11",
-
- ARM11_HANDLER(poll),
- ARM11_HANDLER(arch_state),
-
- ARM11_HANDLER(target_request_data),
-
- ARM11_HANDLER(halt),
- ARM11_HANDLER(resume),
- ARM11_HANDLER(step),
-
- ARM11_HANDLER(assert_reset),
- ARM11_HANDLER(deassert_reset),
- ARM11_HANDLER(soft_reset_halt),
- ARM11_HANDLER(prepare_reset_halt),
-
- ARM11_HANDLER(get_gdb_reg_list),
-
- ARM11_HANDLER(read_memory),
- ARM11_HANDLER(write_memory),
-
- ARM11_HANDLER(bulk_write_memory),
-
- ARM11_HANDLER(checksum_memory),
-
- ARM11_HANDLER(add_breakpoint),
- ARM11_HANDLER(remove_breakpoint),
- ARM11_HANDLER(add_watchpoint),
- ARM11_HANDLER(remove_watchpoint),
-
- ARM11_HANDLER(run_algorithm),
-
- ARM11_HANDLER(register_commands),
- ARM11_HANDLER(target_command),
- ARM11_HANDLER(init_target),
- ARM11_HANDLER(quit),
-};
-
-int arm11_regs_arch_type = -1;
-
-
-enum arm11_regtype
-{
- ARM11_REGISTER_CORE,
- ARM11_REGISTER_CPSR,
-
- ARM11_REGISTER_FX,
- ARM11_REGISTER_FPS,
-
- ARM11_REGISTER_FIQ,
- ARM11_REGISTER_SVC,
- ARM11_REGISTER_ABT,
- ARM11_REGISTER_IRQ,
- ARM11_REGISTER_UND,
- ARM11_REGISTER_MON,
-
- ARM11_REGISTER_SPSR_FIQ,
- ARM11_REGISTER_SPSR_SVC,
- ARM11_REGISTER_SPSR_ABT,
- ARM11_REGISTER_SPSR_IRQ,
- ARM11_REGISTER_SPSR_UND,
- ARM11_REGISTER_SPSR_MON,
-
- /* debug regs */
- ARM11_REGISTER_DSCR,
- ARM11_REGISTER_WDTR,
- ARM11_REGISTER_RDTR,
-};
-
-
-typedef struct arm11_reg_defs_s
-{
- char * name;
- u32 num;
- int gdb_num;
- enum arm11_regtype type;
-} arm11_reg_defs_t;
-
-/* update arm11_regcache_ids when changing this */
-static const arm11_reg_defs_t arm11_reg_defs[] =
-{
- {"r0", 0, 0, ARM11_REGISTER_CORE},
- {"r1", 1, 1, ARM11_REGISTER_CORE},
- {"r2", 2, 2, ARM11_REGISTER_CORE},
- {"r3", 3, 3, ARM11_REGISTER_CORE},
- {"r4", 4, 4, ARM11_REGISTER_CORE},
- {"r5", 5, 5, ARM11_REGISTER_CORE},
- {"r6", 6, 6, ARM11_REGISTER_CORE},
- {"r7", 7, 7, ARM11_REGISTER_CORE},
- {"r8", 8, 8, ARM11_REGISTER_CORE},
- {"r9", 9, 9, ARM11_REGISTER_CORE},
- {"r10", 10, 10, ARM11_REGISTER_CORE},
- {"r11", 11, 11, ARM11_REGISTER_CORE},
- {"r12", 12, 12, ARM11_REGISTER_CORE},
- {"sp", 13, 13, ARM11_REGISTER_CORE},
- {"lr", 14, 14, ARM11_REGISTER_CORE},
- {"pc", 15, 15, ARM11_REGISTER_CORE},
-
-#if ARM11_REGCACHE_FREGS
- {"f0", 0, 16, ARM11_REGISTER_FX},
- {"f1", 1, 17, ARM11_REGISTER_FX},
- {"f2", 2, 18, ARM11_REGISTER_FX},
- {"f3", 3, 19, ARM11_REGISTER_FX},
- {"f4", 4, 20, ARM11_REGISTER_FX},
- {"f5", 5, 21, ARM11_REGISTER_FX},
- {"f6", 6, 22, ARM11_REGISTER_FX},
- {"f7", 7, 23, ARM11_REGISTER_FX},
- {"fps", 0, 24, ARM11_REGISTER_FPS},
-#endif
-
- {"cpsr", 0, 25, ARM11_REGISTER_CPSR},
-
-#if ARM11_REGCACHE_MODEREGS
- {"r8_fiq", 8, -1, ARM11_REGISTER_FIQ},
- {"r9_fiq", 9, -1, ARM11_REGISTER_FIQ},
- {"r10_fiq", 10, -1, ARM11_REGISTER_FIQ},
- {"r11_fiq", 11, -1, ARM11_REGISTER_FIQ},
- {"r12_fiq", 12, -1, ARM11_REGISTER_FIQ},
- {"r13_fiq", 13, -1, ARM11_REGISTER_FIQ},
- {"r14_fiq", 14, -1, ARM11_REGISTER_FIQ},
- {"spsr_fiq", 0, -1, ARM11_REGISTER_SPSR_FIQ},
-
- {"r13_svc", 13, -1, ARM11_REGISTER_SVC},
- {"r14_svc", 14, -1, ARM11_REGISTER_SVC},
- {"spsr_svc", 0, -1, ARM11_REGISTER_SPSR_SVC},
-
- {"r13_abt", 13, -1, ARM11_REGISTER_ABT},
- {"r14_abt", 14, -1, ARM11_REGISTER_ABT},
- {"spsr_abt", 0, -1, ARM11_REGISTER_SPSR_ABT},
-
- {"r13_irq", 13, -1, ARM11_REGISTER_IRQ},
- {"r14_irq", 14, -1, ARM11_REGISTER_IRQ},
- {"spsr_irq", 0, -1, ARM11_REGISTER_SPSR_IRQ},
-
- {"r13_und", 13, -1, ARM11_REGISTER_UND},
- {"r14_und", 14, -1, ARM11_REGISTER_UND},
- {"spsr_und", 0, -1, ARM11_REGISTER_SPSR_UND},
-
- /* ARM1176 only */
- {"r13_mon", 13, -1, ARM11_REGISTER_MON},
- {"r14_mon", 14, -1, ARM11_REGISTER_MON},
- {"spsr_mon", 0, -1, ARM11_REGISTER_SPSR_MON},
-#endif
-
- /* Debug Registers */
- {"dscr", 0, -1, ARM11_REGISTER_DSCR},
- {"wdtr", 0, -1, ARM11_REGISTER_WDTR},
- {"rdtr", 0, -1, ARM11_REGISTER_RDTR},
-};
-
-enum arm11_regcache_ids
-{
- ARM11_RC_R0,
- ARM11_RC_RX = ARM11_RC_R0,
-
- ARM11_RC_R1,
- ARM11_RC_R2,
- ARM11_RC_R3,
- ARM11_RC_R4,
- ARM11_RC_R5,
- ARM11_RC_R6,
- ARM11_RC_R7,
- ARM11_RC_R8,
- ARM11_RC_R9,
- ARM11_RC_R10,
- ARM11_RC_R11,
- ARM11_RC_R12,
- ARM11_RC_R13,
- ARM11_RC_SP = ARM11_RC_R13,
- ARM11_RC_R14,
- ARM11_RC_LR = ARM11_RC_R14,
- ARM11_RC_R15,
- ARM11_RC_PC = ARM11_RC_R15,
-
-#if ARM11_REGCACHE_FREGS
- ARM11_RC_F0,
- ARM11_RC_FX = ARM11_RC_F0,
- ARM11_RC_F1,
- ARM11_RC_F2,
- ARM11_RC_F3,
- ARM11_RC_F4,
- ARM11_RC_F5,
- ARM11_RC_F6,
- ARM11_RC_F7,
- ARM11_RC_FPS,
-#endif
-
- ARM11_RC_CPSR,
-
-#if ARM11_REGCACHE_MODEREGS
- ARM11_RC_R8_FIQ,
- ARM11_RC_R9_FIQ,
- ARM11_RC_R10_FIQ,
- ARM11_RC_R11_FIQ,
- ARM11_RC_R12_FIQ,
- ARM11_RC_R13_FIQ,
- ARM11_RC_R14_FIQ,
- ARM11_RC_SPSR_FIQ,
-
- ARM11_RC_R13_SVC,
- ARM11_RC_R14_SVC,
- ARM11_RC_SPSR_SVC,
-
- ARM11_RC_R13_ABT,
- ARM11_RC_R14_ABT,
- ARM11_RC_SPSR_ABT,
-
- ARM11_RC_R13_IRQ,
- ARM11_RC_R14_IRQ,
- ARM11_RC_SPSR_IRQ,
-
- ARM11_RC_R13_UND,
- ARM11_RC_R14_UND,
- ARM11_RC_SPSR_UND,
-
- ARM11_RC_R13_MON,
- ARM11_RC_R14_MON,
- ARM11_RC_SPSR_MON,
-#endif
-
- ARM11_RC_DSCR,
- ARM11_RC_WDTR,
- ARM11_RC_RDTR,
-
-
- ARM11_RC_MAX,
-};
-
-#define ARM11_GDB_REGISTER_COUNT 26
-
-u8 arm11_gdb_dummy_fp_value[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-reg_t arm11_gdb_dummy_fp_reg =
-{
- "GDB dummy floating-point register", arm11_gdb_dummy_fp_value, 0, 1, 96, NULL, 0, NULL, 0
-};
-
-u8 arm11_gdb_dummy_fps_value[] = {0, 0, 0, 0};
-
-reg_t arm11_gdb_dummy_fps_reg =
-{
- "GDB dummy floating-point status register", arm11_gdb_dummy_fps_value, 0, 1, 32, NULL, 0, NULL, 0
-};
-
-
-
-/** Check and if necessary take control of the system
- *
- * \param arm11 Target state variable.
- * \param dscr If the current DSCR content is
- * available a pointer to a word holding the
- * DSCR can be passed. Otherwise use NULL.
- */
-void arm11_check_init(arm11_common_t * arm11, u32 * dscr)
-{
- FNC_INFO;
-
- u32 dscr_local_tmp_copy;
-
- if (!dscr)
- {
- dscr = &dscr_local_tmp_copy;
- *dscr = arm11_read_DSCR(arm11);
- }
-
- if (!(*dscr & ARM11_DSCR_MODE_SELECT))
- {
- DEBUG("Bringing target into debug mode");
-
- *dscr |= ARM11_DSCR_MODE_SELECT; /* Halt debug-mode */
- arm11_write_DSCR(arm11, *dscr);
-
- /* add further reset initialization here */
-
- if (*dscr & ARM11_DSCR_CORE_HALTED)
- {
- arm11->target->state = TARGET_HALTED;
- arm11->target->debug_reason = arm11_get_DSCR_debug_reason(*dscr);
- }
- else
- {
- arm11->target->state = TARGET_RUNNING;
- arm11->target->debug_reason = DBG_REASON_NOTHALTED;
- }
-
- arm11_sc7_clear_bw(arm11);
- }
-}
-
-
-
-#define R(x) \
- (arm11->reg_values[ARM11_RC_##x])
-
-/** Save processor state.
- *
- * This is called when the HALT instruction has succeeded
- * or on other occasions that stop the processor.
- *
- */
-static void arm11_on_enter_debug_state(arm11_common_t * arm11)
-{
- FNC_INFO;
-
- {size_t i;
- for(i = 0; i < asizeof(arm11->reg_values); i++)
- {
- arm11->reg_list[i].valid = 1;
- arm11->reg_list[i].dirty = 0;
- }}
-
- /* Save DSCR */
-
- R(DSCR) = arm11_read_DSCR(arm11);
-
- /* Save wDTR */
-
- if (R(DSCR) & ARM11_DSCR_WDTR_FULL)
- {
- arm11_add_debug_SCAN_N(arm11, 0x05, -1);
-
- arm11_add_IR(arm11, ARM11_INTEST, -1);
-
- scan_field_t chain5_fields[3];
-
- arm11_setup_field(arm11, 32, NULL, &R(WDTR), chain5_fields + 0);
- arm11_setup_field(arm11, 1, NULL, NULL, chain5_fields + 1);
- arm11_setup_field(arm11, 1, NULL, NULL, chain5_fields + 2);
-
- jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD);
- }
- else
- {
- arm11->reg_list[ARM11_RC_WDTR].valid = 0;
- }
-
-
- /* DSCR: set ARM11_DSCR_EXECUTE_ARM_INSTRUCTION_ENABLE */
- /* ARM1176 spec says this is needed only for wDTR/rDTR's "ITR mode", but not to issue ITRs
- ARM1136 seems to require this to issue ITR's as well */
-
- u32 new_dscr = R(DSCR) | ARM11_DSCR_EXECUTE_ARM_INSTRUCTION_ENABLE;
-
- /* this executes JTAG queue: */
-
- arm11_write_DSCR(arm11, new_dscr);
-
-// jtag_execute_queue();
-
-
-
-// DEBUG("SAVE DSCR %08x", R(DSCR));
-
-// if (R(DSCR) & ARM11_DSCR_WDTR_FULL)
-// DEBUG("SAVE wDTR %08x", R(WDTR));
-
-
- /* From the spec:
- Before executing any instruction in debug state you have to drain the write buffer.
- This ensures that no imprecise Data Aborts can return at a later point:*/
-
- /** \todo TODO: Test drain write buffer. */
-
-#if 0
- while (1)
- {
- /* MRC p14,0,R0,c5,c10,0 */
-// arm11_run_instr_no_data1(arm11, /*0xee150e1a*/0xe320f000);
-
- /* mcr 15, 0, r0, cr7, cr10, {4} */
- arm11_run_instr_no_data1(arm11, 0xee070f9a);
-
- u32 dscr = arm11_read_DSCR(arm11);
-
- DEBUG("DRAIN, DSCR %08x", dscr);
-
- if (dscr & ARM11_DSCR_STICKY_IMPRECISE_DATA_ABORT)
- {
- arm11_run_instr_no_data1(arm11, 0xe320f000);
-
- dscr = arm11_read_DSCR(arm11);
-
- DEBUG("DRAIN, DSCR %08x (DONE)", dscr);
-
- break;
- }
- }
-#endif
-
-
- arm11_run_instr_data_prepare(arm11);
-
- /* save r0 - r14 */
-
-
- /** \todo TODO: handle other mode registers */
-
- {size_t i;
- for (i = 0; i < 15; i++)
- {
- /* MCR p14,0,R?,c0,c5,0 */
- arm11_run_instr_data_from_core(arm11, 0xEE000E15 | (i << 12), &R(RX + i), 1);
- }}
-
-
- /* save rDTR */
-
- /* check rDTRfull in DSCR */
-
- if (R(DSCR) & ARM11_DSCR_RDTR_FULL)
- {
- /* MRC p14,0,R0,c0,c5,0 (move rDTR -> r0 (-> wDTR -> local var)) */
- arm11_run_instr_data_from_core_via_r0(arm11, 0xEE100E15, &R(RDTR));
- }
- else
- {
- arm11->reg_list[ARM11_RC_RDTR].valid = 0;
- }
-
- /* save CPSR */
-
- /* MRS r0,CPSR (move CPSR -> r0 (-> wDTR -> local var)) */
- arm11_run_instr_data_from_core_via_r0(arm11, 0xE10F0000, &R(CPSR));
-
- /* save PC */
-
- /* MOV R0,PC (move PC -> r0 (-> wDTR -> local var)) */
- arm11_run_instr_data_from_core_via_r0(arm11, 0xE1A0000F, &R(PC));
-
- /* adjust PC depending on ARM state */
-
- if (R(CPSR) & ARM11_CPSR_J) /* Java state */
- {
- arm11->reg_values[ARM11_RC_PC] -= 0;
- }
- else if (R(CPSR) & ARM11_CPSR_T) /* Thumb state */
- {
- arm11->reg_values[ARM11_RC_PC] -= 4;
- }
- else /* ARM state */
- {
- arm11->reg_values[ARM11_RC_PC] -= 8;
- }
-
-// DEBUG("SAVE PC %08x", R(PC));
-
- arm11_run_instr_data_finish(arm11);
-
-
- {size_t i;
- for(i = 0; i < ARM11_REGCACHE_COUNT; i++)
- {
- if (!arm11->reg_list[i].valid)
- {
- if (arm11->reg_history[i].valid)
- INFO("%8s INVALID (%08x)", arm11_reg_defs[i].name, arm11->reg_history[i].value);
- }
- else
- {
- if (arm11->reg_history[i].valid)
- {
- if (arm11->reg_history[i].value != arm11->reg_values[i])
- INFO("%8s %08x (%08x)", arm11_reg_defs[i].name, arm11->reg_values[i], arm11->reg_history[i].value);
- }
- else
- {
- INFO("%8s %08x (INVALID)", arm11_reg_defs[i].name, arm11->reg_values[i]);
- }
- }
- }}
-}
-
-
-/** Restore processor state
- *
- * This is called in preparation for the RESTART function.
- *
- */
-void arm11_leave_debug_state(arm11_common_t * arm11)
-{
- FNC_INFO;
-
- arm11_run_instr_data_prepare(arm11);
-
- /** \todo TODO: handle other mode registers */
-
- /* restore R1 - R14 */
- {size_t i;
- for (i = 1; i < 15; i++)
- {
- if (!arm11->reg_list[ARM11_RC_RX + i].dirty)
- continue;
-
- /* MRC p14,0,r?,c0,c5,0 */
- arm11_run_instr_data_to_core1(arm11, 0xee100e15 | (i << 12), R(RX + i));
-
-// DEBUG("RESTORE R%d %08x", i, R(RX + i));
- }}
-
- arm11_run_instr_data_finish(arm11);
-
-
- /* spec says clear wDTR and rDTR; we assume they are clear as
- otherwide out programming would be sloppy */
-
- {
- u32 DSCR = arm11_read_DSCR(arm11);
-
- if (DSCR & (ARM11_DSCR_RDTR_FULL | ARM11_DSCR_WDTR_FULL))
- {
- ERROR("wDTR/rDTR inconsistent (DSCR %08x)", DSCR);
- }
- }
-
- arm11_run_instr_data_prepare(arm11);
-
- /* restore original wDTR */
-
- if ((R(DSCR) & ARM11_DSCR_WDTR_FULL) || arm11->reg_list[ARM11_RC_WDTR].dirty)
- {
- /* MCR p14,0,R0,c0,c5,0 */
- arm11_run_instr_data_to_core_via_r0(arm11, 0xee000e15, R(WDTR));
- }
-
- /* restore CPSR */
-
- /* MSR CPSR,R0*/
- arm11_run_instr_data_to_core_via_r0(arm11, 0xe129f000, R(CPSR));
-
-
- /* restore PC */
-
- /* MOV PC,R0 */
- arm11_run_instr_data_to_core_via_r0(arm11, 0xe1a0f000, R(PC));
-
-
- /* restore R0 */
-
- /* MRC p14,0,r0,c0,c5,0 */
- arm11_run_instr_data_to_core1(arm11, 0xee100e15, R(R0));
-
- arm11_run_instr_data_finish(arm11);
-
-
- /* restore DSCR */
-
- arm11_write_DSCR(arm11, R(DSCR));
-
-
- /* restore rDTR */
-
- if (R(DSCR) & ARM11_DSCR_RDTR_FULL || arm11->reg_list[ARM11_RC_RDTR].dirty)
- {
- arm11_add_debug_SCAN_N(arm11, 0x05, -1);
-
- arm11_add_IR(arm11, ARM11_EXTEST, -1);
-
- scan_field_t chain5_fields[3];
-
- u8 Ready = 0; /* ignored */
- u8 Valid = 0; /* ignored */
-
- arm11_setup_field(arm11, 32, &R(RDTR), NULL, chain5_fields + 0);
- arm11_setup_field(arm11, 1, &Ready, NULL, chain5_fields + 1);
- arm11_setup_field(arm11, 1, &Valid, NULL, chain5_fields + 2);
-
- jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD);
- }
-
-
- {size_t i;
- for(i = 0; i < ARM11_REGCACHE_COUNT; i++)
- {
- arm11->reg_history[i].value = arm11->reg_values[i];
- arm11->reg_history[i].valid = arm11->reg_list[i].valid;
-
- arm11->reg_list[i].valid = 0;
- arm11->reg_list[i].dirty = 0;
- }}
-}
-
-
-/* poll current target status */
-int arm11_poll(struct target_s *target)
-{
- FNC_INFO;
-
- arm11_common_t * arm11 = target->arch_info;
-
- if (arm11->trst_active)
- return ERROR_OK;
-
- u32 dscr = arm11_read_DSCR(arm11);
-
- DEBUG("DSCR %08x", dscr);
-
- arm11_check_init(arm11, &dscr);
-
- if (dscr & ARM11_DSCR_CORE_HALTED)
- {
-// DEBUG("CH %d", target->state);
-
- if (target->state != TARGET_HALTED)
- {
- DEBUG("enter TARGET_HALTED");
- target->state = TARGET_HALTED;
- target->debug_reason = arm11_get_DSCR_debug_reason(dscr);
- arm11_on_enter_debug_state(arm11);
- }
- }
- else
- {
-// DEBUG("CR %d", target->state);
-
- if (target->state != TARGET_RUNNING)
- {
- DEBUG("enter TARGET_RUNNING");
- target->state = TARGET_RUNNING;
- target->debug_reason = DBG_REASON_NOTHALTED;
- }
- }
-
- return ERROR_OK;
-}
-/* architecture specific status reply */
-int arm11_arch_state(struct target_s *target)
-{
- FNC_INFO_NOTIMPLEMENTED;
-
- return ERROR_OK;
-}
-
-
-/* target request support */
-int arm11_target_request_data(struct target_s *target, u32 size, u8 *buffer)
-{
- FNC_INFO_NOTIMPLEMENTED;
-
- return ERROR_OK;
-}
-
-
-
-/* target execution control */
-int arm11_halt(struct target_s *target)
-{
- FNC_INFO;
-
- arm11_common_t * arm11 = target->arch_info;
-
- DEBUG("target->state: %s", target_state_strings[target->state]);
-
- if (target->state == TARGET_HALTED)
- {
- WARNING("target was already halted");
- return ERROR_TARGET_ALREADY_HALTED;
- }
-
- if (arm11->trst_active)
- {
- arm11->halt_requested = true;
- return ERROR_OK;
- }
-
- arm11_add_IR(arm11, ARM11_HALT, TAP_RTI);
-
- jtag_execute_queue();
-
- u32 dscr;
-
- while (1)
- {
- dscr = arm11_read_DSCR(arm11);
-
- if (dscr & ARM11_DSCR_CORE_HALTED)
- break;
- }
-
- arm11_on_enter_debug_state(arm11);
-
- target->state = TARGET_HALTED;
- target->debug_reason = arm11_get_DSCR_debug_reason(dscr);
-
- return ERROR_OK;
-}
-
-
-int arm11_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution)
-{
- FNC_INFO;
-
- arm11_common_t * arm11 = target->arch_info;
-
- DEBUG("target->state: %s", target_state_strings[target->state]);
-
- if (target->state != TARGET_HALTED)
- {
- WARNING("target was not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (!current)
- R(PC) = address;
-
- target->state = TARGET_RUNNING;
- target->debug_reason = DBG_REASON_NOTHALTED;
-
- arm11_leave_debug_state(arm11);
-
- arm11_add_IR(arm11, ARM11_RESTART, TAP_RTI);
-
- jtag_execute_queue();
-
- while (1)
- {
- u32 dscr = arm11_read_DSCR(arm11);
-
- DEBUG("DSCR %08x", dscr);
-
- if (dscr & ARM11_DSCR_CORE_RESTARTED)
- break;
- }
-
- DEBUG("RES %d", target->state);
-
- return ERROR_OK;
-}
-
-int arm11_step(struct target_s *target, int current, u32 address, int handle_breakpoints)
-{
- FNC_INFO;
-
- DEBUG("target->state: %s", target_state_strings[target->state]);
-
- if (target->state != TARGET_HALTED)
- {
- WARNING("target was not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- arm11_common_t * arm11 = target->arch_info;
-
- /** \todo TODO: check if break-/watchpoints make any sense at all in combination
- * with this. */
-
- /** \todo TODO: check if disabling IRQs might be a good idea here. Alternatively
- the VCR might be something worth looking into. */
-
- /* Set up breakpoint for stepping */
-
- arm11_sc7_action_t brp[2];
-
- brp[0].write = 1;
- brp[0].address = ARM11_SC7_BVR0;
- brp[0].value = R(PC);
- brp[1].write = 1;
- brp[1].address = ARM11_SC7_BCR0;
- brp[1].value = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (2 << 21);
-
- arm11_sc7_run(arm11, brp, asizeof(brp));
-
- /* resume */
-
- arm11_leave_debug_state(arm11);
-
- arm11_add_IR(arm11, ARM11_RESTART, TAP_RTI);
-
- jtag_execute_queue();
-
- /** \todo TODO: add a timeout */
-
- /* wait for halt */
-
- while (1)
- {
- u32 dscr = arm11_read_DSCR(arm11);
-
- DEBUG("DSCR %08x", dscr);
-
- if ((dscr & (ARM11_DSCR_CORE_RESTARTED | ARM11_DSCR_CORE_HALTED)) ==
- (ARM11_DSCR_CORE_RESTARTED | ARM11_DSCR_CORE_HALTED))
- break;
- }
-
-
- /* clear breakpoint */
-
- arm11_sc7_clear_bw(arm11);
-
-
- /* save state */
-
- arm11_on_enter_debug_state(arm11);
-
-// target->state = TARGET_HALTED;
- target->debug_reason = DBG_REASON_SINGLESTEP;
-
- return ERROR_OK;
-}
-
-
-/* target reset control */
-int arm11_assert_reset(struct target_s *target)
-{
- FNC_INFO;
-
-#if 0
- /* assert reset lines */
- /* resets only the DBGTAP, not the ARM */
-
- jtag_add_reset(1, 0);
- jtag_add_sleep(5000);
-
- arm11_common_t * arm11 = target->arch_info;
- arm11->trst_active = true;
-#endif
-
- return ERROR_OK;
-}
-
-int arm11_deassert_reset(struct target_s *target)
-{
- FNC_INFO;
-
-#if 0
- DEBUG("target->state: %s", target_state_strings[target->state]);
-
- /* deassert reset lines */
- jtag_add_reset(0, 0);
-
- arm11_common_t * arm11 = target->arch_info;
- arm11->trst_active = false;
-
- if (arm11->halt_requested)
- return arm11_halt(target);
-#endif
-
- return ERROR_OK;
-}
-
-int arm11_soft_reset_halt(struct target_s *target)
-{
- FNC_INFO_NOTIMPLEMENTED;
-
- return ERROR_OK;
-}
-
-int arm11_prepare_reset_halt(struct target_s *target)
-{
- FNC_INFO_NOTIMPLEMENTED;
-
- return ERROR_OK;
-}
-
-
-/* target register access for gdb */
-int arm11_get_gdb_reg_list(struct target_s *target, struct reg_s **reg_list[], int *reg_list_size)
-{
- FNC_INFO;
-
- arm11_common_t * arm11 = target->arch_info;
-
- if (target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- *reg_list_size = ARM11_GDB_REGISTER_COUNT;
- *reg_list = malloc(sizeof(reg_t*) * ARM11_GDB_REGISTER_COUNT);
-
- {size_t i;
- for (i = 16; i < 24; i++)
- {
- (*reg_list)[i] = &arm11_gdb_dummy_fp_reg;
- }}
-
- (*reg_list)[24] = &arm11_gdb_dummy_fps_reg;
-
-
- {size_t i;
- for (i = 0; i < ARM11_REGCACHE_COUNT; i++)
- {
- if (arm11_reg_defs[i].gdb_num == -1)
- continue;
-
- (*reg_list)[arm11_reg_defs[i].gdb_num] = arm11->reg_list + i;
- }}
-
- return ERROR_OK;
-}
-
-
-/* target memory access
-* size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit)
-* count: number of items of <size>
-*/
-int arm11_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
-{
- /** \todo TODO: check if buffer cast to u32* and u16* might cause alignment problems */
-
- FNC_INFO;
-
- DEBUG("ADDR %08x SIZE %08x COUNT %08x", address, size, count);
-
- arm11_common_t * arm11 = target->arch_info;
-
- arm11_run_instr_data_prepare(arm11);
-
- /* MRC p14,0,r0,c0,c5,0 */
- arm11_run_instr_data_to_core1(arm11, 0xee100e15, address);
-
- switch (size)
- {
- case 1:
- /** \todo TODO: check if dirty is the right choice to force a rewrite on arm11_resume() */
- arm11->reg_list[ARM11_RC_R1].dirty = 1;
-
- while (count--)
- {
- /* ldrb r1, [r0], #1 */
- arm11_run_instr_no_data1(arm11, 0xe4d01001);
-
- u32 res;
- /* MCR p14,0,R1,c0,c5,0 */
- arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1);
-
- *buffer++ = res;
- }
- break;
-
- case 2:
- {
- arm11->reg_list[ARM11_RC_R1].dirty = 1;
-
- u16 * buf16 = (u16*)buffer;
-
- while (count--)
- {
- /* ldrh r1, [r0], #2 */
- arm11_run_instr_no_data1(arm11, 0xe0d010b2);
-
- u32 res;
-
- /* MCR p14,0,R1,c0,c5,0 */
- arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1);
-
- *buf16++ = res;
- }
- break;
- }
-
- case 4:
-
- /* LDC p14,c5,[R0],#4 */
- arm11_run_instr_data_from_core(arm11, 0xecb05e01, (u32 *)buffer, count);
- break;
- }
-
- arm11_run_instr_data_finish(arm11);
-
- return ERROR_OK;
-}
-
-int arm11_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
-{
- FNC_INFO;
-
- DEBUG("ADDR %08x SIZE %08x COUNT %08x", address, size, count);
-
- arm11_common_t * arm11 = target->arch_info;
-
- arm11_run_instr_data_prepare(arm11);
-
- /* MRC p14,0,r0,c0,c5,0 */
- arm11_run_instr_data_to_core1(arm11, 0xee100e15, address);
-
- switch (size)
- {
- case 1:
- arm11->reg_list[ARM11_RC_R1].dirty = 1;
-
- while (count--)
- {
- /* MRC p14,0,r1,c0,c5,0 */
- arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buffer++);
-
- /* strb r1, [r0], #1 */
- arm11_run_instr_no_data1(arm11, 0xe4c01001);
- }
- break;
-
- case 2:
- {
- arm11->reg_list[ARM11_RC_R1].dirty = 1;
-
- u16 * buf16 = (u16*)buffer;
-
- while (count--)
- {
- /* MRC p14,0,r1,c0,c5,0 */
- arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buf16++);
-
- /* strh r1, [r0], #2 */
- arm11_run_instr_no_data1(arm11, 0xe0c010b2);
- }
- break;
- }
-
- case 4:
- /** \todo TODO: check if buffer cast to u32* might cause alignment problems */
-
- /* STC p14,c5,[R0],#4 */
- arm11_run_instr_data_to_core(arm11, 0xeca05e01, (u32 *)buffer, count);
- break;
- }
-
- arm11_run_instr_data_finish(arm11);
-
- return ERROR_OK;
-}
-
-
-/* write target memory in multiples of 4 byte, optimized for writing large quantities of data */
-int arm11_bulk_write_memory(struct target_s *target, u32 address, u32 count, u8 *buffer)
-{
- FNC_INFO;
-
- return arm11_write_memory(target, address, 4, count, buffer);
-}
-
-
-int arm11_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum)
-{
- FNC_INFO_NOTIMPLEMENTED;
-
- return ERROR_OK;
-}
-
-
-/* target break-/watchpoint control
-* rw: 0 = write, 1 = read, 2 = access
-*/
-int arm11_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
-{
- FNC_INFO_NOTIMPLEMENTED;
-
- return ERROR_OK;
-}
-
-int arm11_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
-{
- FNC_INFO_NOTIMPLEMENTED;
-
- return ERROR_OK;
-}
-
-int arm11_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
-{
- FNC_INFO_NOTIMPLEMENTED;
-
- return ERROR_OK;
-}
-
-int arm11_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
-{
- FNC_INFO_NOTIMPLEMENTED;
-
- return ERROR_OK;
-}
-
-
-/* target algorithm support */
-int arm11_run_algorithm(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_params, reg_param_t *reg_param, u32 entry_point, u32 exit_point, int timeout_ms, void *arch_info)
-{
- FNC_INFO_NOTIMPLEMENTED;
-
- return ERROR_OK;
-}
-
-
-int arm11_register_commands(struct command_context_s *cmd_ctx)
-{
- FNC_INFO;
-
- return ERROR_OK;
-}
-
-int arm11_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
-{
- FNC_INFO;
-
- if (argc < 4)
- {
- ERROR("'target arm11' 4th argument <jtag chain pos>");
- exit(-1);
- }
-
- int chain_pos = strtoul(args[3], NULL, 0);
-
- NEW(arm11_common_t, arm11, 1);
-
- arm11->target = target;
-
- /* prepare JTAG information for the new target */
- arm11->jtag_info.chain_pos = chain_pos;
- arm11->jtag_info.scann_size = 5;
-
- arm_jtag_setup_connection(&arm11->jtag_info);
-
- jtag_device_t *device = jtag_get_device(chain_pos);
-
- if (device->ir_length != 5)
- {
- ERROR("'target arm11' expects 'jtag_device 5 0x01 0x1F 0x1E'");
- exit(-1);
- }
-
- target->arch_info = arm11;
-
- return ERROR_OK;
-}
-
-int arm11_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
-{
- FNC_INFO;
-
- arm11_common_t * arm11 = target->arch_info;
-
- /* check IDCODE */
-
- arm11_add_IR(arm11, ARM11_IDCODE, -1);
-
- scan_field_t idcode_field;
-
- arm11_setup_field(arm11, 32, NULL, &arm11->device_id, &idcode_field);
-
- jtag_add_dr_scan_vc(1, &idcode_field, TAP_PD);
-
- /* check DIDR */
-
- arm11_add_debug_SCAN_N(arm11, 0x00, -1);
-
- arm11_add_IR(arm11, ARM11_INTEST, -1);
-
- scan_field_t chain0_fields[2];
-
- arm11_setup_field(arm11, 32, NULL, &arm11->didr, chain0_fields + 0);
- arm11_setup_field(arm11, 8, NULL, &arm11->implementor, chain0_fields + 1);
-
- jtag_add_dr_scan_vc(asizeof(chain0_fields), chain0_fields, TAP_RTI);
-
- jtag_execute_queue();
-
-
- switch (arm11->device_id & 0x0FFFF000)
- {
- case 0x07B36000: INFO("found ARM1136"); break;
- case 0x07B56000: INFO("found ARM1156"); break;
- case 0x07B76000: INFO("found ARM1176"); break;
- default:
- {
- ERROR("'target arm11' expects IDCODE 0x*7B*7****");
- exit(-1);
- }
- }
-
- arm11->brp = ((arm11->didr >> 24) & 0x0F) + 1;
- arm11->wrp = ((arm11->didr >> 28) & 0x0F) + 1;
-
-
- DEBUG("IDCODE %08x IMPLEMENTOR %02x DIDR %08x",
- arm11->device_id,
- arm11->implementor,
- arm11->didr);
-
- arm11_build_reg_cache(target);
-
-
- /* as a side-effect this reads DSCR and thus
- * clears the ARM11_DSCR_STICKY_PRECISE_DATA_ABORT / Sticky Precise Data Abort Flag
- * as suggested by the spec.
- */
-
- arm11_check_init(arm11, NULL);
-
- return ERROR_OK;
-}
-
-int arm11_quit(void)
-{
- FNC_INFO_NOTIMPLEMENTED;
-
- return ERROR_OK;
-}
-
-/** Load a register that is marked !valid in the register cache */
-int arm11_get_reg(reg_t *reg)
-{
- FNC_INFO;
-
- target_t * target = ((arm11_reg_state_t *)reg->arch_info)->target;
-
- if (target->state != TARGET_HALTED)
- {
- return ERROR_TARGET_NOT_HALTED;
- }
-
- /** \todo TODO: Check this. We assume that all registers are fetched debug entry. */
-
-#if 0
- arm11_common_t *arm11 = target->arch_info;
- const arm11_reg_defs_t * arm11_reg_info = arm11_reg_defs + ((arm11_reg_state_t *)reg->arch_info)->def_index;
-#endif
-
- return ERROR_OK;
-}
-
-/** Change a value in the register cache */
-int arm11_set_reg(reg_t *reg, u8 *buf)
-{
- FNC_INFO;
-
- target_t * target = ((arm11_reg_state_t *)reg->arch_info)->target;
- arm11_common_t *arm11 = target->arch_info;
-// const arm11_reg_defs_t * arm11_reg_info = arm11_reg_defs + ((arm11_reg_state_t *)reg->arch_info)->def_index;
-
- arm11->reg_values[((arm11_reg_state_t *)reg->arch_info)->def_index] = buf_get_u32(buf, 0, 32);
- reg->valid = 1;
- reg->dirty = 1;
-
- return ERROR_OK;
-}
-
-
-void arm11_build_reg_cache(target_t *target)
-{
- arm11_common_t *arm11 = target->arch_info;
-
- NEW(reg_cache_t, cache, 1);
- NEW(reg_t, reg_list, ARM11_REGCACHE_COUNT);
- NEW(arm11_reg_state_t, arm11_reg_states, ARM11_REGCACHE_COUNT);
-
- if (arm11_regs_arch_type == -1)
- arm11_regs_arch_type = register_reg_arch_type(arm11_get_reg, arm11_set_reg);
-
- arm11->reg_list = reg_list;
-
- /* Build the process context cache */
- cache->name = "arm11 registers";
- cache->next = NULL;
- cache->reg_list = reg_list;
- cache->num_regs = ARM11_REGCACHE_COUNT;
-
- reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache);
- (*cache_p) = cache;
-
-// armv7m->core_cache = cache;
-// armv7m->process_context = cache;
-
- size_t i;
-
- /* Not very elegant assertion */
- if (ARM11_REGCACHE_COUNT != asizeof(arm11->reg_values) ||
- ARM11_REGCACHE_COUNT != asizeof(arm11_reg_defs) ||
- ARM11_REGCACHE_COUNT != ARM11_RC_MAX)
- {
- ERROR("arm11->reg_values inconsistent (%d %d %d %d)", ARM11_REGCACHE_COUNT, asizeof(arm11->reg_values), asizeof(arm11_reg_defs), ARM11_RC_MAX);
- exit(-1);
- }
-
- for (i = 0; i < ARM11_REGCACHE_COUNT; i++)
- {
- reg_t * r = reg_list + i;
- const arm11_reg_defs_t * rd = arm11_reg_defs + i;
- arm11_reg_state_t * rs = arm11_reg_states + i;
-
- r->name = rd->name;
- r->size = 32;
- r->value = (u8 *)(arm11->reg_values + i);
- r->dirty = 0;
- r->valid = 0;
- r->bitfield_desc = NULL;
- r->num_bitfields = 0;
- r->arch_type = arm11_regs_arch_type;
- r->arch_info = rs;
-
- rs->def_index = i;
- rs->target = target;
- }
-}
-
-#if 0
- arm11_run_instr_data_prepare(arm11);
-
- /* MRC p14,0,r0,c0,c5,0 */
- arm11_run_instr_data_to_core(arm11, 0xee100e15, 0xCA00003C);
- /* MRC p14,0,r1,c0,c5,0 */
- arm11_run_instr_data_to_core(arm11, 0xee101e15, 0xFFFFFFFF);
-
- arm11_run_instr_data_finish(arm11);
-#endif
-
-
+/*************************************************************************** + * Copyright (C) 2008 digenius technology GmbH. * + * * + * 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 "arm11.h" +#include "jtag.h" +#include "log.h" + +#include <stdlib.h> +#include <string.h> + +#if 0 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + + +#if 0 +#define FNC_INFO DEBUG("-") +#else +#define FNC_INFO +#endif + +#if 1 +#define FNC_INFO_NOTIMPLEMENTED do { DEBUG("NOT IMPLEMENTED"); /*exit(-1);*/ } while (0) +#else +#define FNC_INFO_NOTIMPLEMENTED +#endif + +static void arm11_on_enter_debug_state(arm11_common_t * arm11); + + +#define ARM11_HANDLER(x) \ + .x = arm11_##x + +target_type_t arm11_target = +{ + .name = "arm11", + + ARM11_HANDLER(poll), + ARM11_HANDLER(arch_state), + + ARM11_HANDLER(target_request_data), + + ARM11_HANDLER(halt), + ARM11_HANDLER(resume), + ARM11_HANDLER(step), + + ARM11_HANDLER(assert_reset), + ARM11_HANDLER(deassert_reset), + ARM11_HANDLER(soft_reset_halt), + ARM11_HANDLER(prepare_reset_halt), + + ARM11_HANDLER(get_gdb_reg_list), + + ARM11_HANDLER(read_memory), + ARM11_HANDLER(write_memory), + + ARM11_HANDLER(bulk_write_memory), + + ARM11_HANDLER(checksum_memory), + + ARM11_HANDLER(add_breakpoint), + ARM11_HANDLER(remove_breakpoint), + ARM11_HANDLER(add_watchpoint), + ARM11_HANDLER(remove_watchpoint), + + ARM11_HANDLER(run_algorithm), + + ARM11_HANDLER(register_commands), + ARM11_HANDLER(target_command), + ARM11_HANDLER(init_target), + ARM11_HANDLER(quit), +}; + +int arm11_regs_arch_type = -1; + + +enum arm11_regtype +{ + ARM11_REGISTER_CORE, + ARM11_REGISTER_CPSR, + + ARM11_REGISTER_FX, + ARM11_REGISTER_FPS, + + ARM11_REGISTER_FIQ, + ARM11_REGISTER_SVC, + ARM11_REGISTER_ABT, + ARM11_REGISTER_IRQ, + ARM11_REGISTER_UND, + ARM11_REGISTER_MON, + + ARM11_REGISTER_SPSR_FIQ, + ARM11_REGISTER_SPSR_SVC, + ARM11_REGISTER_SPSR_ABT, + ARM11_REGISTER_SPSR_IRQ, + ARM11_REGISTER_SPSR_UND, + ARM11_REGISTER_SPSR_MON, + + /* debug regs */ + ARM11_REGISTER_DSCR, + ARM11_REGISTER_WDTR, + ARM11_REGISTER_RDTR, +}; + + +typedef struct arm11_reg_defs_s +{ + char * name; + u32 num; + int gdb_num; + enum arm11_regtype type; +} arm11_reg_defs_t; + +/* update arm11_regcache_ids when changing this */ +static const arm11_reg_defs_t arm11_reg_defs[] = +{ + {"r0", 0, 0, ARM11_REGISTER_CORE}, + {"r1", 1, 1, ARM11_REGISTER_CORE}, + {"r2", 2, 2, ARM11_REGISTER_CORE}, + {"r3", 3, 3, ARM11_REGISTER_CORE}, + {"r4", 4, 4, ARM11_REGISTER_CORE}, + {"r5", 5, 5, ARM11_REGISTER_CORE}, + {"r6", 6, 6, ARM11_REGISTER_CORE}, + {"r7", 7, 7, ARM11_REGISTER_CORE}, + {"r8", 8, 8, ARM11_REGISTER_CORE}, + {"r9", 9, 9, ARM11_REGISTER_CORE}, + {"r10", 10, 10, ARM11_REGISTER_CORE}, + {"r11", 11, 11, ARM11_REGISTER_CORE}, + {"r12", 12, 12, ARM11_REGISTER_CORE}, + {"sp", 13, 13, ARM11_REGISTER_CORE}, + {"lr", 14, 14, ARM11_REGISTER_CORE}, + {"pc", 15, 15, ARM11_REGISTER_CORE}, + +#if ARM11_REGCACHE_FREGS + {"f0", 0, 16, ARM11_REGISTER_FX}, + {"f1", 1, 17, ARM11_REGISTER_FX}, + {"f2", 2, 18, ARM11_REGISTER_FX}, + {"f3", 3, 19, ARM11_REGISTER_FX}, + {"f4", 4, 20, ARM11_REGISTER_FX}, + {"f5", 5, 21, ARM11_REGISTER_FX}, + {"f6", 6, 22, ARM11_REGISTER_FX}, + {"f7", 7, 23, ARM11_REGISTER_FX}, + {"fps", 0, 24, ARM11_REGISTER_FPS}, +#endif + + {"cpsr", 0, 25, ARM11_REGISTER_CPSR}, + +#if ARM11_REGCACHE_MODEREGS + {"r8_fiq", 8, -1, ARM11_REGISTER_FIQ}, + {"r9_fiq", 9, -1, ARM11_REGISTER_FIQ}, + {"r10_fiq", 10, -1, ARM11_REGISTER_FIQ}, + {"r11_fiq", 11, -1, ARM11_REGISTER_FIQ}, + {"r12_fiq", 12, -1, ARM11_REGISTER_FIQ}, + {"r13_fiq", 13, -1, ARM11_REGISTER_FIQ}, + {"r14_fiq", 14, -1, ARM11_REGISTER_FIQ}, + {"spsr_fiq", 0, -1, ARM11_REGISTER_SPSR_FIQ}, + + {"r13_svc", 13, -1, ARM11_REGISTER_SVC}, + {"r14_svc", 14, -1, ARM11_REGISTER_SVC}, + {"spsr_svc", 0, -1, ARM11_REGISTER_SPSR_SVC}, + + {"r13_abt", 13, -1, ARM11_REGISTER_ABT}, + {"r14_abt", 14, -1, ARM11_REGISTER_ABT}, + {"spsr_abt", 0, -1, ARM11_REGISTER_SPSR_ABT}, + + {"r13_irq", 13, -1, ARM11_REGISTER_IRQ}, + {"r14_irq", 14, -1, ARM11_REGISTER_IRQ}, + {"spsr_irq", 0, -1, ARM11_REGISTER_SPSR_IRQ}, + + {"r13_und", 13, -1, ARM11_REGISTER_UND}, + {"r14_und", 14, -1, ARM11_REGISTER_UND}, + {"spsr_und", 0, -1, ARM11_REGISTER_SPSR_UND}, + + /* ARM1176 only */ + {"r13_mon", 13, -1, ARM11_REGISTER_MON}, + {"r14_mon", 14, -1, ARM11_REGISTER_MON}, + {"spsr_mon", 0, -1, ARM11_REGISTER_SPSR_MON}, +#endif + + /* Debug Registers */ + {"dscr", 0, -1, ARM11_REGISTER_DSCR}, + {"wdtr", 0, -1, ARM11_REGISTER_WDTR}, + {"rdtr", 0, -1, ARM11_REGISTER_RDTR}, +}; + +enum arm11_regcache_ids +{ + ARM11_RC_R0, + ARM11_RC_RX = ARM11_RC_R0, + + ARM11_RC_R1, + ARM11_RC_R2, + ARM11_RC_R3, + ARM11_RC_R4, + ARM11_RC_R5, + ARM11_RC_R6, + ARM11_RC_R7, + ARM11_RC_R8, + ARM11_RC_R9, + ARM11_RC_R10, + ARM11_RC_R11, + ARM11_RC_R12, + ARM11_RC_R13, + ARM11_RC_SP = ARM11_RC_R13, + ARM11_RC_R14, + ARM11_RC_LR = ARM11_RC_R14, + ARM11_RC_R15, + ARM11_RC_PC = ARM11_RC_R15, + +#if ARM11_REGCACHE_FREGS + ARM11_RC_F0, + ARM11_RC_FX = ARM11_RC_F0, + ARM11_RC_F1, + ARM11_RC_F2, + ARM11_RC_F3, + ARM11_RC_F4, + ARM11_RC_F5, + ARM11_RC_F6, + ARM11_RC_F7, + ARM11_RC_FPS, +#endif + + ARM11_RC_CPSR, + +#if ARM11_REGCACHE_MODEREGS + ARM11_RC_R8_FIQ, + ARM11_RC_R9_FIQ, + ARM11_RC_R10_FIQ, + ARM11_RC_R11_FIQ, + ARM11_RC_R12_FIQ, + ARM11_RC_R13_FIQ, + ARM11_RC_R14_FIQ, + ARM11_RC_SPSR_FIQ, + + ARM11_RC_R13_SVC, + ARM11_RC_R14_SVC, + ARM11_RC_SPSR_SVC, + + ARM11_RC_R13_ABT, + ARM11_RC_R14_ABT, + ARM11_RC_SPSR_ABT, + + ARM11_RC_R13_IRQ, + ARM11_RC_R14_IRQ, + ARM11_RC_SPSR_IRQ, + + ARM11_RC_R13_UND, + ARM11_RC_R14_UND, + ARM11_RC_SPSR_UND, + + ARM11_RC_R13_MON, + ARM11_RC_R14_MON, + ARM11_RC_SPSR_MON, +#endif + + ARM11_RC_DSCR, + ARM11_RC_WDTR, + ARM11_RC_RDTR, + + + ARM11_RC_MAX, +}; + +#define ARM11_GDB_REGISTER_COUNT 26 + +u8 arm11_gdb_dummy_fp_value[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +reg_t arm11_gdb_dummy_fp_reg = +{ + "GDB dummy floating-point register", arm11_gdb_dummy_fp_value, 0, 1, 96, NULL, 0, NULL, 0 +}; + +u8 arm11_gdb_dummy_fps_value[] = {0, 0, 0, 0}; + +reg_t arm11_gdb_dummy_fps_reg = +{ + "GDB dummy floating-point status register", arm11_gdb_dummy_fps_value, 0, 1, 32, NULL, 0, NULL, 0 +}; + + + +/** Check and if necessary take control of the system + * + * \param arm11 Target state variable. + * \param dscr If the current DSCR content is + * available a pointer to a word holding the + * DSCR can be passed. Otherwise use NULL. + */ +void arm11_check_init(arm11_common_t * arm11, u32 * dscr) +{ + FNC_INFO; + + u32 dscr_local_tmp_copy; + + if (!dscr) + { + dscr = &dscr_local_tmp_copy; + *dscr = arm11_read_DSCR(arm11); + } + + if (!(*dscr & ARM11_DSCR_MODE_SELECT)) + { + DEBUG("Bringing target into debug mode"); + + *dscr |= ARM11_DSCR_MODE_SELECT; /* Halt debug-mode */ + arm11_write_DSCR(arm11, *dscr); + + /* add further reset initialization here */ + + if (*dscr & ARM11_DSCR_CORE_HALTED) + { + arm11->target->state = TARGET_HALTED; + arm11->target->debug_reason = arm11_get_DSCR_debug_reason(*dscr); + } + else + { + arm11->target->state = TARGET_RUNNING; + arm11->target->debug_reason = DBG_REASON_NOTHALTED; + } + + arm11_sc7_clear_bw(arm11); + } +} + + + +#define R(x) \ + (arm11->reg_values[ARM11_RC_##x]) + +/** Save processor state. + * + * This is called when the HALT instruction has succeeded + * or on other occasions that stop the processor. + * + */ +static void arm11_on_enter_debug_state(arm11_common_t * arm11) +{ + FNC_INFO; + + {size_t i; + for(i = 0; i < asizeof(arm11->reg_values); i++) + { + arm11->reg_list[i].valid = 1; + arm11->reg_list[i].dirty = 0; + }} + + /* Save DSCR */ + + R(DSCR) = arm11_read_DSCR(arm11); + + /* Save wDTR */ + + if (R(DSCR) & ARM11_DSCR_WDTR_FULL) + { + arm11_add_debug_SCAN_N(arm11, 0x05, -1); + + arm11_add_IR(arm11, ARM11_INTEST, -1); + + scan_field_t chain5_fields[3]; + + arm11_setup_field(arm11, 32, NULL, &R(WDTR), chain5_fields + 0); + arm11_setup_field(arm11, 1, NULL, NULL, chain5_fields + 1); + arm11_setup_field(arm11, 1, NULL, NULL, chain5_fields + 2); + + jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD); + } + else + { + arm11->reg_list[ARM11_RC_WDTR].valid = 0; + } + + + /* DSCR: set ARM11_DSCR_EXECUTE_ARM_INSTRUCTION_ENABLE */ + /* ARM1176 spec says this is needed only for wDTR/rDTR's "ITR mode", but not to issue ITRs + ARM1136 seems to require this to issue ITR's as well */ + + u32 new_dscr = R(DSCR) | ARM11_DSCR_EXECUTE_ARM_INSTRUCTION_ENABLE; + + /* this executes JTAG queue: */ + + arm11_write_DSCR(arm11, new_dscr); + +// jtag_execute_queue(); + + + +// DEBUG("SAVE DSCR %08x", R(DSCR)); + +// if (R(DSCR) & ARM11_DSCR_WDTR_FULL) +// DEBUG("SAVE wDTR %08x", R(WDTR)); + + + /* From the spec: + Before executing any instruction in debug state you have to drain the write buffer. + This ensures that no imprecise Data Aborts can return at a later point:*/ + + /** \todo TODO: Test drain write buffer. */ + +#if 0 + while (1) + { + /* MRC p14,0,R0,c5,c10,0 */ +// arm11_run_instr_no_data1(arm11, /*0xee150e1a*/0xe320f000); + + /* mcr 15, 0, r0, cr7, cr10, {4} */ + arm11_run_instr_no_data1(arm11, 0xee070f9a); + + u32 dscr = arm11_read_DSCR(arm11); + + DEBUG("DRAIN, DSCR %08x", dscr); + + if (dscr & ARM11_DSCR_STICKY_IMPRECISE_DATA_ABORT) + { + arm11_run_instr_no_data1(arm11, 0xe320f000); + + dscr = arm11_read_DSCR(arm11); + + DEBUG("DRAIN, DSCR %08x (DONE)", dscr); + + break; + } + } +#endif + + + arm11_run_instr_data_prepare(arm11); + + /* save r0 - r14 */ + + + /** \todo TODO: handle other mode registers */ + + {size_t i; + for (i = 0; i < 15; i++) + { + /* MCR p14,0,R?,c0,c5,0 */ + arm11_run_instr_data_from_core(arm11, 0xEE000E15 | (i << 12), &R(RX + i), 1); + }} + + + /* save rDTR */ + + /* check rDTRfull in DSCR */ + + if (R(DSCR) & ARM11_DSCR_RDTR_FULL) + { + /* MRC p14,0,R0,c0,c5,0 (move rDTR -> r0 (-> wDTR -> local var)) */ + arm11_run_instr_data_from_core_via_r0(arm11, 0xEE100E15, &R(RDTR)); + } + else + { + arm11->reg_list[ARM11_RC_RDTR].valid = 0; + } + + /* save CPSR */ + + /* MRS r0,CPSR (move CPSR -> r0 (-> wDTR -> local var)) */ + arm11_run_instr_data_from_core_via_r0(arm11, 0xE10F0000, &R(CPSR)); + + /* save PC */ + + /* MOV R0,PC (move PC -> r0 (-> wDTR -> local var)) */ + arm11_run_instr_data_from_core_via_r0(arm11, 0xE1A0000F, &R(PC)); + + /* adjust PC depending on ARM state */ + + if (R(CPSR) & ARM11_CPSR_J) /* Java state */ + { + arm11->reg_values[ARM11_RC_PC] -= 0; + } + else if (R(CPSR) & ARM11_CPSR_T) /* Thumb state */ + { + arm11->reg_values[ARM11_RC_PC] -= 4; + } + else /* ARM state */ + { + arm11->reg_values[ARM11_RC_PC] -= 8; + } + +// DEBUG("SAVE PC %08x", R(PC)); + + arm11_run_instr_data_finish(arm11); + + + {size_t i; + for(i = 0; i < ARM11_REGCACHE_COUNT; i++) + { + if (!arm11->reg_list[i].valid) + { + if (arm11->reg_history[i].valid) + INFO("%8s INVALID (%08x)", arm11_reg_defs[i].name, arm11->reg_history[i].value); + } + else + { + if (arm11->reg_history[i].valid) + { + if (arm11->reg_history[i].value != arm11->reg_values[i]) + INFO("%8s %08x (%08x)", arm11_reg_defs[i].name, arm11->reg_values[i], arm11->reg_history[i].value); + } + else + { + INFO("%8s %08x (INVALID)", arm11_reg_defs[i].name, arm11->reg_values[i]); + } + } + }} +} + + +/** Restore processor state + * + * This is called in preparation for the RESTART function. + * + */ +void arm11_leave_debug_state(arm11_common_t * arm11) +{ + FNC_INFO; + + arm11_run_instr_data_prepare(arm11); + + /** \todo TODO: handle other mode registers */ + + /* restore R1 - R14 */ + {size_t i; + for (i = 1; i < 15; i++) + { + if (!arm11->reg_list[ARM11_RC_RX + i].dirty) + continue; + + /* MRC p14,0,r?,c0,c5,0 */ + arm11_run_instr_data_to_core1(arm11, 0xee100e15 | (i << 12), R(RX + i)); + +// DEBUG("RESTORE R%d %08x", i, R(RX + i)); + }} + + arm11_run_instr_data_finish(arm11); + + + /* spec says clear wDTR and rDTR; we assume they are clear as + otherwide out programming would be sloppy */ + + { + u32 DSCR = arm11_read_DSCR(arm11); + + if (DSCR & (ARM11_DSCR_RDTR_FULL | ARM11_DSCR_WDTR_FULL)) + { + ERROR("wDTR/rDTR inconsistent (DSCR %08x)", DSCR); + } + } + + arm11_run_instr_data_prepare(arm11); + + /* restore original wDTR */ + + if ((R(DSCR) & ARM11_DSCR_WDTR_FULL) || arm11->reg_list[ARM11_RC_WDTR].dirty) + { + /* MCR p14,0,R0,c0,c5,0 */ + arm11_run_instr_data_to_core_via_r0(arm11, 0xee000e15, R(WDTR)); + } + + /* restore CPSR */ + + /* MSR CPSR,R0*/ + arm11_run_instr_data_to_core_via_r0(arm11, 0xe129f000, R(CPSR)); + + + /* restore PC */ + + /* MOV PC,R0 */ + arm11_run_instr_data_to_core_via_r0(arm11, 0xe1a0f000, R(PC)); + + + /* restore R0 */ + + /* MRC p14,0,r0,c0,c5,0 */ + arm11_run_instr_data_to_core1(arm11, 0xee100e15, R(R0)); + + arm11_run_instr_data_finish(arm11); + + + /* restore DSCR */ + + arm11_write_DSCR(arm11, R(DSCR)); + + + /* restore rDTR */ + + if (R(DSCR) & ARM11_DSCR_RDTR_FULL || arm11->reg_list[ARM11_RC_RDTR].dirty) + { + arm11_add_debug_SCAN_N(arm11, 0x05, -1); + + arm11_add_IR(arm11, ARM11_EXTEST, -1); + + scan_field_t chain5_fields[3]; + + u8 Ready = 0; /* ignored */ + u8 Valid = 0; /* ignored */ + + arm11_setup_field(arm11, 32, &R(RDTR), NULL, chain5_fields + 0); + arm11_setup_field(arm11, 1, &Ready, NULL, chain5_fields + 1); + arm11_setup_field(arm11, 1, &Valid, NULL, chain5_fields + 2); + + jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD); + } + + + {size_t i; + for(i = 0; i < ARM11_REGCACHE_COUNT; i++) + { + arm11->reg_history[i].value = arm11->reg_values[i]; + arm11->reg_history[i].valid = arm11->reg_list[i].valid; + + arm11->reg_list[i].valid = 0; + arm11->reg_list[i].dirty = 0; + }} +} + + +/* poll current target status */ +int arm11_poll(struct target_s *target) +{ + FNC_INFO; + + arm11_common_t * arm11 = target->arch_info; + + if (arm11->trst_active) + return ERROR_OK; + + u32 dscr = arm11_read_DSCR(arm11); + + DEBUG("DSCR %08x", dscr); + + arm11_check_init(arm11, &dscr); + + if (dscr & ARM11_DSCR_CORE_HALTED) + { +// DEBUG("CH %d", target->state); + + if (target->state != TARGET_HALTED) + { + DEBUG("enter TARGET_HALTED"); + target->state = TARGET_HALTED; + target->debug_reason = arm11_get_DSCR_debug_reason(dscr); + arm11_on_enter_debug_state(arm11); + } + } + else + { +// DEBUG("CR %d", target->state); + + if (target->state != TARGET_RUNNING) + { + DEBUG("enter TARGET_RUNNING"); + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + } + } + + return ERROR_OK; +} +/* architecture specific status reply */ +int arm11_arch_state(struct target_s *target) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + + +/* target request support */ +int arm11_target_request_data(struct target_s *target, u32 size, u8 *buffer) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + + + +/* target execution control */ +int arm11_halt(struct target_s *target) +{ + FNC_INFO; + + arm11_common_t * arm11 = target->arch_info; + + DEBUG("target->state: %s", target_state_strings[target->state]); + + if (target->state == TARGET_HALTED) + { + WARNING("target was already halted"); + return ERROR_TARGET_ALREADY_HALTED; + } + + if (arm11->trst_active) + { + arm11->halt_requested = true; + return ERROR_OK; + } + + arm11_add_IR(arm11, ARM11_HALT, TAP_RTI); + + jtag_execute_queue(); + + u32 dscr; + + while (1) + { + dscr = arm11_read_DSCR(arm11); + + if (dscr & ARM11_DSCR_CORE_HALTED) + break; + } + + arm11_on_enter_debug_state(arm11); + + target->state = TARGET_HALTED; + target->debug_reason = arm11_get_DSCR_debug_reason(dscr); + + return ERROR_OK; +} + + +int arm11_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution) +{ + FNC_INFO; + + arm11_common_t * arm11 = target->arch_info; + + DEBUG("target->state: %s", target_state_strings[target->state]); + + if (target->state != TARGET_HALTED) + { + WARNING("target was not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!current) + R(PC) = address; + + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + + arm11_leave_debug_state(arm11); + + arm11_add_IR(arm11, ARM11_RESTART, TAP_RTI); + + jtag_execute_queue(); + + while (1) + { + u32 dscr = arm11_read_DSCR(arm11); + + DEBUG("DSCR %08x", dscr); + + if (dscr & ARM11_DSCR_CORE_RESTARTED) + break; + } + + DEBUG("RES %d", target->state); + + return ERROR_OK; +} + +int arm11_step(struct target_s *target, int current, u32 address, int handle_breakpoints) +{ + FNC_INFO; + + DEBUG("target->state: %s", target_state_strings[target->state]); + + if (target->state != TARGET_HALTED) + { + WARNING("target was not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + arm11_common_t * arm11 = target->arch_info; + + /** \todo TODO: check if break-/watchpoints make any sense at all in combination + * with this. */ + + /** \todo TODO: check if disabling IRQs might be a good idea here. Alternatively + the VCR might be something worth looking into. */ + + /* Set up breakpoint for stepping */ + + arm11_sc7_action_t brp[2]; + + brp[0].write = 1; + brp[0].address = ARM11_SC7_BVR0; + brp[0].value = R(PC); + brp[1].write = 1; + brp[1].address = ARM11_SC7_BCR0; + brp[1].value = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (2 << 21); + + arm11_sc7_run(arm11, brp, asizeof(brp)); + + /* resume */ + + arm11_leave_debug_state(arm11); + + arm11_add_IR(arm11, ARM11_RESTART, TAP_RTI); + + jtag_execute_queue(); + + /** \todo TODO: add a timeout */ + + /* wait for halt */ + + while (1) + { + u32 dscr = arm11_read_DSCR(arm11); + + DEBUG("DSCR %08x", dscr); + + if ((dscr & (ARM11_DSCR_CORE_RESTARTED | ARM11_DSCR_CORE_HALTED)) == + (ARM11_DSCR_CORE_RESTARTED | ARM11_DSCR_CORE_HALTED)) + break; + } + + + /* clear breakpoint */ + + arm11_sc7_clear_bw(arm11); + + + /* save state */ + + arm11_on_enter_debug_state(arm11); + +// target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_SINGLESTEP; + + return ERROR_OK; +} + + +/* target reset control */ +int arm11_assert_reset(struct target_s *target) +{ + FNC_INFO; + +#if 0 + /* assert reset lines */ + /* resets only the DBGTAP, not the ARM */ + + jtag_add_reset(1, 0); + jtag_add_sleep(5000); + + arm11_common_t * arm11 = target->arch_info; + arm11->trst_active = true; +#endif + + return ERROR_OK; +} + +int arm11_deassert_reset(struct target_s *target) +{ + FNC_INFO; + +#if 0 + DEBUG("target->state: %s", target_state_strings[target->state]); + + /* deassert reset lines */ + jtag_add_reset(0, 0); + + arm11_common_t * arm11 = target->arch_info; + arm11->trst_active = false; + + if (arm11->halt_requested) + return arm11_halt(target); +#endif + + return ERROR_OK; +} + +int arm11_soft_reset_halt(struct target_s *target) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + +int arm11_prepare_reset_halt(struct target_s *target) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + + +/* target register access for gdb */ +int arm11_get_gdb_reg_list(struct target_s *target, struct reg_s **reg_list[], int *reg_list_size) +{ + FNC_INFO; + + arm11_common_t * arm11 = target->arch_info; + + if (target->state != TARGET_HALTED) + { + return ERROR_TARGET_NOT_HALTED; + } + + *reg_list_size = ARM11_GDB_REGISTER_COUNT; + *reg_list = malloc(sizeof(reg_t*) * ARM11_GDB_REGISTER_COUNT); + + {size_t i; + for (i = 16; i < 24; i++) + { + (*reg_list)[i] = &arm11_gdb_dummy_fp_reg; + }} + + (*reg_list)[24] = &arm11_gdb_dummy_fps_reg; + + + {size_t i; + for (i = 0; i < ARM11_REGCACHE_COUNT; i++) + { + if (arm11_reg_defs[i].gdb_num == -1) + continue; + + (*reg_list)[arm11_reg_defs[i].gdb_num] = arm11->reg_list + i; + }} + + return ERROR_OK; +} + + +/* target memory access +* size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit) +* count: number of items of <size> +*/ +int arm11_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + /** \todo TODO: check if buffer cast to u32* and u16* might cause alignment problems */ + + FNC_INFO; + + DEBUG("ADDR %08x SIZE %08x COUNT %08x", address, size, count); + + arm11_common_t * arm11 = target->arch_info; + + arm11_run_instr_data_prepare(arm11); + + /* MRC p14,0,r0,c0,c5,0 */ + arm11_run_instr_data_to_core1(arm11, 0xee100e15, address); + + switch (size) + { + case 1: + /** \todo TODO: check if dirty is the right choice to force a rewrite on arm11_resume() */ + arm11->reg_list[ARM11_RC_R1].dirty = 1; + + while (count--) + { + /* ldrb r1, [r0], #1 */ + arm11_run_instr_no_data1(arm11, 0xe4d01001); + + u32 res; + /* MCR p14,0,R1,c0,c5,0 */ + arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1); + + *buffer++ = res; + } + break; + + case 2: + { + arm11->reg_list[ARM11_RC_R1].dirty = 1; + + u16 * buf16 = (u16*)buffer; + + while (count--) + { + /* ldrh r1, [r0], #2 */ + arm11_run_instr_no_data1(arm11, 0xe0d010b2); + + u32 res; + + /* MCR p14,0,R1,c0,c5,0 */ + arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1); + + *buf16++ = res; + } + break; + } + + case 4: + + /* LDC p14,c5,[R0],#4 */ + arm11_run_instr_data_from_core(arm11, 0xecb05e01, (u32 *)buffer, count); + break; + } + + arm11_run_instr_data_finish(arm11); + + return ERROR_OK; +} + +int arm11_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + FNC_INFO; + + DEBUG("ADDR %08x SIZE %08x COUNT %08x", address, size, count); + + arm11_common_t * arm11 = target->arch_info; + + arm11_run_instr_data_prepare(arm11); + + /* MRC p14,0,r0,c0,c5,0 */ + arm11_run_instr_data_to_core1(arm11, 0xee100e15, address); + + switch (size) + { + case 1: + arm11->reg_list[ARM11_RC_R1].dirty = 1; + + while (count--) + { + /* MRC p14,0,r1,c0,c5,0 */ + arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buffer++); + + /* strb r1, [r0], #1 */ + arm11_run_instr_no_data1(arm11, 0xe4c01001); + } + break; + + case 2: + { + arm11->reg_list[ARM11_RC_R1].dirty = 1; + + u16 * buf16 = (u16*)buffer; + + while (count--) + { + /* MRC p14,0,r1,c0,c5,0 */ + arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buf16++); + + /* strh r1, [r0], #2 */ + arm11_run_instr_no_data1(arm11, 0xe0c010b2); + } + break; + } + + case 4: + /** \todo TODO: check if buffer cast to u32* might cause alignment problems */ + + /* STC p14,c5,[R0],#4 */ + arm11_run_instr_data_to_core(arm11, 0xeca05e01, (u32 *)buffer, count); + break; + } + + arm11_run_instr_data_finish(arm11); + + return ERROR_OK; +} + + +/* write target memory in multiples of 4 byte, optimized for writing large quantities of data */ +int arm11_bulk_write_memory(struct target_s *target, u32 address, u32 count, u8 *buffer) +{ + FNC_INFO; + + return arm11_write_memory(target, address, 4, count, buffer); +} + + +int arm11_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + + +/* target break-/watchpoint control +* rw: 0 = write, 1 = read, 2 = access +*/ +int arm11_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + +int arm11_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + +int arm11_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + +int arm11_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + + +/* target algorithm support */ +int arm11_run_algorithm(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_params, reg_param_t *reg_param, u32 entry_point, u32 exit_point, int timeout_ms, void *arch_info) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + + +int arm11_register_commands(struct command_context_s *cmd_ctx) +{ + FNC_INFO; + + return ERROR_OK; +} + +int arm11_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + FNC_INFO; + + if (argc < 4) + { + ERROR("'target arm11' 4th argument <jtag chain pos>"); + exit(-1); + } + + int chain_pos = strtoul(args[3], NULL, 0); + + NEW(arm11_common_t, arm11, 1); + + arm11->target = target; + + /* prepare JTAG information for the new target */ + arm11->jtag_info.chain_pos = chain_pos; + arm11->jtag_info.scann_size = 5; + + arm_jtag_setup_connection(&arm11->jtag_info); + + jtag_device_t *device = jtag_get_device(chain_pos); + + if (device->ir_length != 5) + { + ERROR("'target arm11' expects 'jtag_device 5 0x01 0x1F 0x1E'"); + exit(-1); + } + + target->arch_info = arm11; + + return ERROR_OK; +} + +int arm11_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + FNC_INFO; + + arm11_common_t * arm11 = target->arch_info; + + /* check IDCODE */ + + arm11_add_IR(arm11, ARM11_IDCODE, -1); + + scan_field_t idcode_field; + + arm11_setup_field(arm11, 32, NULL, &arm11->device_id, &idcode_field); + + jtag_add_dr_scan_vc(1, &idcode_field, TAP_PD); + + /* check DIDR */ + + arm11_add_debug_SCAN_N(arm11, 0x00, -1); + + arm11_add_IR(arm11, ARM11_INTEST, -1); + + scan_field_t chain0_fields[2]; + + arm11_setup_field(arm11, 32, NULL, &arm11->didr, chain0_fields + 0); + arm11_setup_field(arm11, 8, NULL, &arm11->implementor, chain0_fields + 1); + + jtag_add_dr_scan_vc(asizeof(chain0_fields), chain0_fields, TAP_RTI); + + jtag_execute_queue(); + + + switch (arm11->device_id & 0x0FFFF000) + { + case 0x07B36000: INFO("found ARM1136"); break; + case 0x07B56000: INFO("found ARM1156"); break; + case 0x07B76000: INFO("found ARM1176"); break; + default: + { + ERROR("'target arm11' expects IDCODE 0x*7B*7****"); + exit(-1); + } + } + + arm11->brp = ((arm11->didr >> 24) & 0x0F) + 1; + arm11->wrp = ((arm11->didr >> 28) & 0x0F) + 1; + + + DEBUG("IDCODE %08x IMPLEMENTOR %02x DIDR %08x", + arm11->device_id, + arm11->implementor, + arm11->didr); + + arm11_build_reg_cache(target); + + + /* as a side-effect this reads DSCR and thus + * clears the ARM11_DSCR_STICKY_PRECISE_DATA_ABORT / Sticky Precise Data Abort Flag + * as suggested by the spec. + */ + + arm11_check_init(arm11, NULL); + + return ERROR_OK; +} + +int arm11_quit(void) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + +/** Load a register that is marked !valid in the register cache */ +int arm11_get_reg(reg_t *reg) +{ + FNC_INFO; + + target_t * target = ((arm11_reg_state_t *)reg->arch_info)->target; + + if (target->state != TARGET_HALTED) + { + return ERROR_TARGET_NOT_HALTED; + } + + /** \todo TODO: Check this. We assume that all registers are fetched debug entry. */ + +#if 0 + arm11_common_t *arm11 = target->arch_info; + const arm11_reg_defs_t * arm11_reg_info = arm11_reg_defs + ((arm11_reg_state_t *)reg->arch_info)->def_index; +#endif + + return ERROR_OK; +} + +/** Change a value in the register cache */ +int arm11_set_reg(reg_t *reg, u8 *buf) +{ + FNC_INFO; + + target_t * target = ((arm11_reg_state_t *)reg->arch_info)->target; + arm11_common_t *arm11 = target->arch_info; +// const arm11_reg_defs_t * arm11_reg_info = arm11_reg_defs + ((arm11_reg_state_t *)reg->arch_info)->def_index; + + arm11->reg_values[((arm11_reg_state_t *)reg->arch_info)->def_index] = buf_get_u32(buf, 0, 32); + reg->valid = 1; + reg->dirty = 1; + + return ERROR_OK; +} + + +void arm11_build_reg_cache(target_t *target) +{ + arm11_common_t *arm11 = target->arch_info; + + NEW(reg_cache_t, cache, 1); + NEW(reg_t, reg_list, ARM11_REGCACHE_COUNT); + NEW(arm11_reg_state_t, arm11_reg_states, ARM11_REGCACHE_COUNT); + + if (arm11_regs_arch_type == -1) + arm11_regs_arch_type = register_reg_arch_type(arm11_get_reg, arm11_set_reg); + + arm11->reg_list = reg_list; + + /* Build the process context cache */ + cache->name = "arm11 registers"; + cache->next = NULL; + cache->reg_list = reg_list; + cache->num_regs = ARM11_REGCACHE_COUNT; + + reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache); + (*cache_p) = cache; + +// armv7m->core_cache = cache; +// armv7m->process_context = cache; + + size_t i; + + /* Not very elegant assertion */ + if (ARM11_REGCACHE_COUNT != asizeof(arm11->reg_values) || + ARM11_REGCACHE_COUNT != asizeof(arm11_reg_defs) || + ARM11_REGCACHE_COUNT != ARM11_RC_MAX) + { + ERROR("arm11->reg_values inconsistent (%d %d %d %d)", ARM11_REGCACHE_COUNT, asizeof(arm11->reg_values), asizeof(arm11_reg_defs), ARM11_RC_MAX); + exit(-1); + } + + for (i = 0; i < ARM11_REGCACHE_COUNT; i++) + { + reg_t * r = reg_list + i; + const arm11_reg_defs_t * rd = arm11_reg_defs + i; + arm11_reg_state_t * rs = arm11_reg_states + i; + + r->name = rd->name; + r->size = 32; + r->value = (u8 *)(arm11->reg_values + i); + r->dirty = 0; + r->valid = 0; + r->bitfield_desc = NULL; + r->num_bitfields = 0; + r->arch_type = arm11_regs_arch_type; + r->arch_info = rs; + + rs->def_index = i; + rs->target = target; + } +} + +#if 0 + arm11_run_instr_data_prepare(arm11); + + /* MRC p14,0,r0,c0,c5,0 */ + arm11_run_instr_data_to_core(arm11, 0xee100e15, 0xCA00003C); + /* MRC p14,0,r1,c0,c5,0 */ + arm11_run_instr_data_to_core(arm11, 0xee101e15, 0xFFFFFFFF); + + arm11_run_instr_data_finish(arm11); +#endif + + diff --git a/src/target/arm11.h b/src/target/arm11.h index 4e061ae..f2263b5 100644 --- a/src/target/arm11.h +++ b/src/target/arm11.h @@ -1,250 +1,250 @@ -/***************************************************************************
- * Copyright (C) 2008 digenius technology GmbH. *
- * *
- * 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 ARM11_H
-#define ARM11_H
-
-#include "target.h"
-#include "register.h"
-#include "embeddedice.h"
-#include "arm_jtag.h"
-
-
-#define bool int
-#define true 1
-#define false 0
-
-#define asizeof(x) (sizeof(x) / sizeof((x)[0]))
-
-#define NEW(type, variable, items) \
- type * variable = malloc(sizeof(type) * items)
-
-
-#define ARM11_REGCACHE_MODEREGS 0
-#define ARM11_REGCACHE_FREGS 0
-
-#define ARM11_REGCACHE_COUNT (20 + \
- 23 * ARM11_REGCACHE_MODEREGS + \
- 9 * ARM11_REGCACHE_FREGS)
-
-
-typedef struct arm11_register_history_s
-{
- u32 value;
- u8 valid;
-}arm11_register_history_t;
-
-
-
-typedef struct arm11_common_s
-{
- target_t * target;
-
- arm_jtag_t jtag_info;
-
- /** \name Processor type detection */
- /*@{*/
-
- u32 device_id; /**< IDCODE readout */
- u32 didr; /**< DIDR readout (debug capabilities) */
- u8 implementor; /**< DIDR Implementor readout */
-
- size_t brp; /**< Number of Breakpoint Register Pairs */
- size_t wrp; /**< Number of Watchpoint Register Pairs */
-
- /*@}*/
-
-
- u32 last_dscr; /**< Last retrieved DSCR value;
- * Can be used to detect changes */
-
- u8 trst_active;
- u8 halt_requested;
-
- /** \name Shadow registers to save processor state */
- /*@{*/
-
- reg_t * reg_list; /**< target register list */
- u32 reg_values[ARM11_REGCACHE_COUNT]; /**< data for registers */
-
- /*@}*/
-
- arm11_register_history_t
- reg_history[ARM11_REGCACHE_COUNT]; /**< register state before last resume */
-
-
-} arm11_common_t;
-
-
-/**
- * ARM11 DBGTAP instructions
- *
- * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301f/I1006229.html
- */
-enum arm11_instructions
-{
- ARM11_EXTEST = 0x00,
- ARM11_SCAN_N = 0x02,
- ARM11_RESTART = 0x04,
- ARM11_HALT = 0x08,
- ARM11_INTEST = 0x0C,
- ARM11_ITRSEL = 0x1D,
- ARM11_IDCODE = 0x1E,
- ARM11_BYPASS = 0x1F,
-};
-
-enum arm11_dscr
-{
- ARM11_DSCR_CORE_HALTED = 1 << 0,
- ARM11_DSCR_CORE_RESTARTED = 1 << 1,
-
- ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_MASK = 0x0F << 2,
- ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_HALT = 0x00 << 2,
- ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BREAKPOINT = 0x01 << 2,
- ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_WATCHPOINT = 0x02 << 2,
- ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BKPT_INSTRUCTION = 0x03 << 2,
- ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_EDBGRQ = 0x04 << 2,
- ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_VECTOR_CATCH = 0x05 << 2,
-
- ARM11_DSCR_STICKY_PRECISE_DATA_ABORT = 1 << 6,
- ARM11_DSCR_STICKY_IMPRECISE_DATA_ABORT = 1 << 7,
- ARM11_DSCR_EXECUTE_ARM_INSTRUCTION_ENABLE = 1 << 13,
- ARM11_DSCR_MODE_SELECT = 1 << 14,
- ARM11_DSCR_WDTR_FULL = 1 << 29,
- ARM11_DSCR_RDTR_FULL = 1 << 30,
-};
-
-enum arm11_cpsr
-{
- ARM11_CPSR_T = 1 << 5,
- ARM11_CPSR_J = 1 << 24,
-};
-
-enum arm11_sc7
-{
- ARM11_SC7_NULL = 0,
- ARM11_SC7_VCR = 7,
- ARM11_SC7_PC = 8,
- ARM11_SC7_BVR0 = 64,
- ARM11_SC7_BCR0 = 80,
- ARM11_SC7_WVR0 = 96,
- ARM11_SC7_WCR0 = 112,
-};
-
-
-
-typedef struct arm11_reg_state_s
-{
- u32 def_index;
- target_t * target;
-} arm11_reg_state_t;
-
-
-
-
-/* poll current target status */
-int arm11_poll(struct target_s *target);
-/* architecture specific status reply */
-int arm11_arch_state(struct target_s *target);
-
-/* target request support */
-int arm11_target_request_data(struct target_s *target, u32 size, u8 *buffer);
-
-/* target execution control */
-int arm11_halt(struct target_s *target);
-int arm11_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution);
-int arm11_step(struct target_s *target, int current, u32 address, int handle_breakpoints);
-
-/* target reset control */
-int arm11_assert_reset(struct target_s *target);
-int arm11_deassert_reset(struct target_s *target);
-int arm11_soft_reset_halt(struct target_s *target);
-int arm11_prepare_reset_halt(struct target_s *target);
-
-/* target register access for gdb */
-int arm11_get_gdb_reg_list(struct target_s *target, struct reg_s **reg_list[], int *reg_list_size);
-
-/* target memory access
-* size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit)
-* count: number of items of <size>
-*/
-int arm11_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
-int arm11_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
-
-/* write target memory in multiples of 4 byte, optimized for writing large quantities of data */
-int arm11_bulk_write_memory(struct target_s *target, u32 address, u32 count, u8 *buffer);
-
-int arm11_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum);
-
-/* target break-/watchpoint control
-* rw: 0 = write, 1 = read, 2 = access
-*/
-int arm11_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint);
-int arm11_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint);
-int arm11_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint);
-int arm11_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint);
-
-/* target algorithm support */
-int arm11_run_algorithm(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_params, reg_param_t *reg_param, u32 entry_point, u32 exit_point, int timeout_ms, void *arch_info);
-
-int arm11_register_commands(struct command_context_s *cmd_ctx);
-int arm11_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
-int arm11_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
-int arm11_quit(void);
-
-
-/* helpers */
-void arm11_build_reg_cache(target_t *target);
-
-
-/* internals */
-
-void arm11_setup_field (arm11_common_t * arm11, int num_bits, void * in_data, void * out_data, scan_field_t * field);
-void arm11_add_IR (arm11_common_t * arm11, u8 instr, enum tap_state state);
-void arm11_add_debug_SCAN_N (arm11_common_t * arm11, u8 chain, enum tap_state state);
-void arm11_add_debug_INST (arm11_common_t * arm11, u32 inst, u8 * flag, enum tap_state state);
-u32 arm11_read_DSCR (arm11_common_t * arm11);
-void arm11_write_DSCR (arm11_common_t * arm11, u32 dscr);
-
-enum target_debug_reason arm11_get_DSCR_debug_reason(u32 dscr);
-
-void arm11_run_instr_data_prepare (arm11_common_t * arm11);
-void arm11_run_instr_data_finish (arm11_common_t * arm11);
-void arm11_run_instr_no_data (arm11_common_t * arm11, u32 * opcode, size_t count);
-void arm11_run_instr_no_data1 (arm11_common_t * arm11, u32 opcode);
-void arm11_run_instr_data_to_core (arm11_common_t * arm11, u32 opcode, u32 * data, size_t count);
-void arm11_run_instr_data_to_core1 (arm11_common_t * arm11, u32 opcode, u32 data);
-void arm11_run_instr_data_from_core (arm11_common_t * arm11, u32 opcode, u32 * data, size_t count);
-void arm11_run_instr_data_from_core_via_r0 (arm11_common_t * arm11, u32 opcode, u32 * data);
-void arm11_run_instr_data_to_core_via_r0 (arm11_common_t * arm11, u32 opcode, u32 data);
-
-
-typedef struct arm11_sc7_action_s
-{
- bool write;
- u8 address;
- u32 value;
-} arm11_sc7_action_t;
-
-void arm11_sc7_run(arm11_common_t * arm11, arm11_sc7_action_t * actions, size_t count);
-void arm11_sc7_clear_bw(arm11_common_t * arm11);
-
-
-
-#endif /* ARM11_H */
+/*************************************************************************** + * Copyright (C) 2008 digenius technology GmbH. * + * * + * 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 ARM11_H +#define ARM11_H + +#include "target.h" +#include "register.h" +#include "embeddedice.h" +#include "arm_jtag.h" + + +#define bool int +#define true 1 +#define false 0 + +#define asizeof(x) (sizeof(x) / sizeof((x)[0])) + +#define NEW(type, variable, items) \ + type * variable = malloc(sizeof(type) * items) + + +#define ARM11_REGCACHE_MODEREGS 0 +#define ARM11_REGCACHE_FREGS 0 + +#define ARM11_REGCACHE_COUNT (20 + \ + 23 * ARM11_REGCACHE_MODEREGS + \ + 9 * ARM11_REGCACHE_FREGS) + + +typedef struct arm11_register_history_s +{ + u32 value; + u8 valid; +}arm11_register_history_t; + + + +typedef struct arm11_common_s +{ + target_t * target; + + arm_jtag_t jtag_info; + + /** \name Processor type detection */ + /*@{*/ + + u32 device_id; /**< IDCODE readout */ + u32 didr; /**< DIDR readout (debug capabilities) */ + u8 implementor; /**< DIDR Implementor readout */ + + size_t brp; /**< Number of Breakpoint Register Pairs */ + size_t wrp; /**< Number of Watchpoint Register Pairs */ + + /*@}*/ + + + u32 last_dscr; /**< Last retrieved DSCR value; + * Can be used to detect changes */ + + u8 trst_active; + u8 halt_requested; + + /** \name Shadow registers to save processor state */ + /*@{*/ + + reg_t * reg_list; /**< target register list */ + u32 reg_values[ARM11_REGCACHE_COUNT]; /**< data for registers */ + + /*@}*/ + + arm11_register_history_t + reg_history[ARM11_REGCACHE_COUNT]; /**< register state before last resume */ + + +} arm11_common_t; + + +/** + * ARM11 DBGTAP instructions + * + * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301f/I1006229.html + */ +enum arm11_instructions +{ + ARM11_EXTEST = 0x00, + ARM11_SCAN_N = 0x02, + ARM11_RESTART = 0x04, + ARM11_HALT = 0x08, + ARM11_INTEST = 0x0C, + ARM11_ITRSEL = 0x1D, + ARM11_IDCODE = 0x1E, + ARM11_BYPASS = 0x1F, +}; + +enum arm11_dscr +{ + ARM11_DSCR_CORE_HALTED = 1 << 0, + ARM11_DSCR_CORE_RESTARTED = 1 << 1, + + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_MASK = 0x0F << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_HALT = 0x00 << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BREAKPOINT = 0x01 << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_WATCHPOINT = 0x02 << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BKPT_INSTRUCTION = 0x03 << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_EDBGRQ = 0x04 << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_VECTOR_CATCH = 0x05 << 2, + + ARM11_DSCR_STICKY_PRECISE_DATA_ABORT = 1 << 6, + ARM11_DSCR_STICKY_IMPRECISE_DATA_ABORT = 1 << 7, + ARM11_DSCR_EXECUTE_ARM_INSTRUCTION_ENABLE = 1 << 13, + ARM11_DSCR_MODE_SELECT = 1 << 14, + ARM11_DSCR_WDTR_FULL = 1 << 29, + ARM11_DSCR_RDTR_FULL = 1 << 30, +}; + +enum arm11_cpsr +{ + ARM11_CPSR_T = 1 << 5, + ARM11_CPSR_J = 1 << 24, +}; + +enum arm11_sc7 +{ + ARM11_SC7_NULL = 0, + ARM11_SC7_VCR = 7, + ARM11_SC7_PC = 8, + ARM11_SC7_BVR0 = 64, + ARM11_SC7_BCR0 = 80, + ARM11_SC7_WVR0 = 96, + ARM11_SC7_WCR0 = 112, +}; + + + +typedef struct arm11_reg_state_s +{ + u32 def_index; + target_t * target; +} arm11_reg_state_t; + + + + +/* poll current target status */ +int arm11_poll(struct target_s *target); +/* architecture specific status reply */ +int arm11_arch_state(struct target_s *target); + +/* target request support */ +int arm11_target_request_data(struct target_s *target, u32 size, u8 *buffer); + +/* target execution control */ +int arm11_halt(struct target_s *target); +int arm11_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution); +int arm11_step(struct target_s *target, int current, u32 address, int handle_breakpoints); + +/* target reset control */ +int arm11_assert_reset(struct target_s *target); +int arm11_deassert_reset(struct target_s *target); +int arm11_soft_reset_halt(struct target_s *target); +int arm11_prepare_reset_halt(struct target_s *target); + +/* target register access for gdb */ +int arm11_get_gdb_reg_list(struct target_s *target, struct reg_s **reg_list[], int *reg_list_size); + +/* target memory access +* size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit) +* count: number of items of <size> +*/ +int arm11_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int arm11_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); + +/* write target memory in multiples of 4 byte, optimized for writing large quantities of data */ +int arm11_bulk_write_memory(struct target_s *target, u32 address, u32 count, u8 *buffer); + +int arm11_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum); + +/* target break-/watchpoint control +* rw: 0 = write, 1 = read, 2 = access +*/ +int arm11_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int arm11_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int arm11_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint); +int arm11_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint); + +/* target algorithm support */ +int arm11_run_algorithm(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_params, reg_param_t *reg_param, u32 entry_point, u32 exit_point, int timeout_ms, void *arch_info); + +int arm11_register_commands(struct command_context_s *cmd_ctx); +int arm11_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int arm11_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int arm11_quit(void); + + +/* helpers */ +void arm11_build_reg_cache(target_t *target); + + +/* internals */ + +void arm11_setup_field (arm11_common_t * arm11, int num_bits, void * in_data, void * out_data, scan_field_t * field); +void arm11_add_IR (arm11_common_t * arm11, u8 instr, enum tap_state state); +void arm11_add_debug_SCAN_N (arm11_common_t * arm11, u8 chain, enum tap_state state); +void arm11_add_debug_INST (arm11_common_t * arm11, u32 inst, u8 * flag, enum tap_state state); +u32 arm11_read_DSCR (arm11_common_t * arm11); +void arm11_write_DSCR (arm11_common_t * arm11, u32 dscr); + +enum target_debug_reason arm11_get_DSCR_debug_reason(u32 dscr); + +void arm11_run_instr_data_prepare (arm11_common_t * arm11); +void arm11_run_instr_data_finish (arm11_common_t * arm11); +void arm11_run_instr_no_data (arm11_common_t * arm11, u32 * opcode, size_t count); +void arm11_run_instr_no_data1 (arm11_common_t * arm11, u32 opcode); +void arm11_run_instr_data_to_core (arm11_common_t * arm11, u32 opcode, u32 * data, size_t count); +void arm11_run_instr_data_to_core1 (arm11_common_t * arm11, u32 opcode, u32 data); +void arm11_run_instr_data_from_core (arm11_common_t * arm11, u32 opcode, u32 * data, size_t count); +void arm11_run_instr_data_from_core_via_r0 (arm11_common_t * arm11, u32 opcode, u32 * data); +void arm11_run_instr_data_to_core_via_r0 (arm11_common_t * arm11, u32 opcode, u32 data); + + +typedef struct arm11_sc7_action_s +{ + bool write; + u8 address; + u32 value; +} arm11_sc7_action_t; + +void arm11_sc7_run(arm11_common_t * arm11, arm11_sc7_action_t * actions, size_t count); +void arm11_sc7_clear_bw(arm11_common_t * arm11); + + + +#endif /* ARM11_H */ diff --git a/src/target/arm11_dbgtap.c b/src/target/arm11_dbgtap.c index 13b412c..d77c953 100644 --- a/src/target/arm11_dbgtap.c +++ b/src/target/arm11_dbgtap.c @@ -1,611 +1,611 @@ -/***************************************************************************
- * Copyright (C) 2008 digenius technology GmbH. *
- * *
- * 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 "arm11.h"
-#include "jtag.h"
-#include "log.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#if 0
-#define JTAG_DEBUG(expr ...) \
- do { \
- log_printf (LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, expr); \
- } while(0)
-#else
-#define JTAG_DEBUG(expr ...) \
- do {} while(0)
-#endif
-
-/** Code de-clutter: Construct scan_field_t to write out a value
- *
- * \param arm11 Target state variable.
- * \param num_bits Length of the data field
- * \param out_data pointer to the data that will be sent out
- * <em>(data is read when it is added to the JTAG queue)</em>
- * \param in_data pointer to the memory that will receive data that was clocked in
- * <em>(data is written when the JTAG queue is executed)</em>
- * \param field target data structure that will be initialized
- */
-void arm11_setup_field(arm11_common_t * arm11, int num_bits, void * out_data, void * in_data, scan_field_t * field)
-{
- field->device = arm11->jtag_info.chain_pos;
- field->num_bits = num_bits;
- field->out_mask = NULL;
- field->in_check_mask = NULL;
- field->in_check_value = NULL;
- field->in_handler = NULL;
- field->in_handler_priv = NULL;
-
- field->out_value = out_data;
- field->in_value = in_data;
-}
-
-
-/** Write JTAG instruction register
- *
- * \param arm11 Target state variable.
- * \param instr An ARM11 DBGTAP instruction. Use enum #arm11_instructions.
- * \param state Pass the final TAP state or -1 for the default value (Pause-IR).
- *
- * \remarks This adds to the JTAG command queue but does \em not execute it.
- */
-void arm11_add_IR(arm11_common_t * arm11, u8 instr, enum tap_state state)
-{
- jtag_device_t *device = jtag_get_device(arm11->jtag_info.chain_pos);
-
- if (buf_get_u32(device->cur_instr, 0, 5) == instr)
- {
- JTAG_DEBUG("IR <= 0x%02x SKIPPED", instr);
- return;
- }
-
- JTAG_DEBUG("IR <= 0x%02x", instr);
-
- scan_field_t field;
-
- arm11_setup_field(arm11, 5, &instr, NULL, &field);
-
- jtag_add_ir_scan_vc(1, &field, state == -1 ? TAP_PI : state);
-}
-
-/** Verify shifted out data from Scan Chain Register (SCREG)
- * Used as parameter to scan_field_t::in_handler in
- * arm11_add_debug_SCAN_N().
- *
- */
-static int arm11_in_handler_SCAN_N(u8 *in_value, void *priv, struct scan_field_s *field)
-{
- /** \todo TODO: clarify why this isnt properly masked in jtag.c jtag_read_buffer() */
- u8 v = *in_value & 0x1F;
-
- if (v != 0x10)
- {
- ERROR("'arm11 target' JTAG communication error SCREG SCAN OUT 0x%02x (expected 0x10)", v);
- exit(-1);
- }
-
- JTAG_DEBUG("SCREG SCAN OUT 0x%02x", v);
- return ERROR_OK;
-}
-
-/** Select and write to Scan Chain Register (SCREG)
- *
- * This function sets the instruction register to SCAN_N and writes
- * the data register with the selected chain number.
- *
- * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301f/Cacbjhfg.html
- *
- * \param arm11 Target state variable.
- * \param chain Scan chain that will be selected.
- * \param state Pass the final TAP state or -1 for the default
- * value (Pause-DR).
- *
- * The chain takes effect when Update-DR is passed (usually when subsequently
- * the INTEXT/EXTEST instructions are written).
- *
- * \warning (Obsolete) Using this twice in a row will \em fail. The first call will end
- * in Pause-DR. The second call, due to the IR caching, will not
- * go through Capture-DR when shifting in the new scan chain number.
- * As a result the verification in arm11_in_handler_SCAN_N() must
- * fail.
- *
- * \remarks This adds to the JTAG command queue but does \em not execute it.
- */
-
-void arm11_add_debug_SCAN_N(arm11_common_t * arm11, u8 chain, enum tap_state state)
-{
- JTAG_DEBUG("SCREG <= 0x%02x", chain);
-
- arm11_add_IR(arm11, ARM11_SCAN_N, -1);
-
- scan_field_t field;
-
- arm11_setup_field(arm11, 5, &chain, NULL, &field);
-
- field.in_handler = arm11_in_handler_SCAN_N;
-
- jtag_add_dr_scan_vc(1, &field, state == -1 ? TAP_PD : state);
-}
-
-/** Write an instruction into the ITR register
- *
- * \param arm11 Target state variable.
- * \param inst An ARM11 processor instruction/opcode.
- * \param flag Optional parameter to retrieve the InstCompl flag
- * (this will be written when the JTAG chain is executed).
- * \param state Pass the final TAP state or -1 for the default
- * value (Run-Test/Idle).
- *
- * \remarks By default this ends with Run-Test/Idle state
- * and causes the instruction to be executed. If
- * a subsequent write to DTR is needed before
- * executing the instruction then TAP_PD should be
- * passed to \p state.
- *
- * \remarks This adds to the JTAG command queue but does \em not execute it.
- */
-void arm11_add_debug_INST(arm11_common_t * arm11, u32 inst, u8 * flag, enum tap_state state)
-{
- JTAG_DEBUG("INST <= 0x%08x", inst);
-
- scan_field_t itr[2];
-
- arm11_setup_field(arm11, 32, &inst, NULL, itr + 0);
- arm11_setup_field(arm11, 1, NULL, flag, itr + 1);
-
- jtag_add_dr_scan_vc(asizeof(itr), itr, state == -1 ? TAP_RTI : state);
-}
-
-/** Read the Debug Status and Control Register (DSCR)
- *
- * same as CP14 c1
- *
- * \param arm11 Target state variable.
- * \return DSCR content
- *
- * \remarks This is a stand-alone function that executes the JTAG command queue.
- */
-u32 arm11_read_DSCR(arm11_common_t * arm11)
-{
- arm11_add_debug_SCAN_N(arm11, 0x01, -1);
-
- arm11_add_IR(arm11, ARM11_INTEST, -1);
-
- u32 dscr;
- scan_field_t chain1_field;
-
- arm11_setup_field(arm11, 32, NULL, &dscr, &chain1_field);
-
- jtag_add_dr_scan_vc(1, &chain1_field, TAP_PD);
-
- jtag_execute_queue();
-
- if (arm11->last_dscr != dscr)
- JTAG_DEBUG("DSCR = %08x (OLD %08x)", dscr, arm11->last_dscr);
-
- arm11->last_dscr = dscr;
-
- return dscr;
-}
-
-/** Write the Debug Status and Control Register (DSCR)
- *
- * same as CP14 c1
- *
- * \param arm11 Target state variable.
- * \param dscr DSCR content
- *
- * \remarks This is a stand-alone function that executes the JTAG command queue.
- */
-void arm11_write_DSCR(arm11_common_t * arm11, u32 dscr)
-{
- arm11_add_debug_SCAN_N(arm11, 0x01, -1);
-
- arm11_add_IR(arm11, ARM11_EXTEST, -1);
-
- scan_field_t chain1_field;
-
- arm11_setup_field(arm11, 32, &dscr, NULL, &chain1_field);
-
- jtag_add_dr_scan_vc(1, &chain1_field, TAP_PD);
-
- jtag_execute_queue();
-
- JTAG_DEBUG("DSCR <= %08x (OLD %08x)", dscr, arm11->last_dscr);
-
- arm11->last_dscr = dscr;
-}
-
-
-
-/** Get the debug reason from Debug Status and Control Register (DSCR)
- *
- * \param dscr DSCR value to analyze
- * \return Debug reason
- *
- */
-enum target_debug_reason arm11_get_DSCR_debug_reason(u32 dscr)
-{
- switch (dscr & ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_MASK)
- {
- case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_HALT: return DBG_REASON_DBGRQ;
- case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BREAKPOINT: return DBG_REASON_BREAKPOINT;
- case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_WATCHPOINT: return DBG_REASON_WATCHPOINT;
- case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BKPT_INSTRUCTION: return DBG_REASON_BREAKPOINT;
- case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_EDBGRQ: return DBG_REASON_DBGRQ;
- case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_VECTOR_CATCH: return DBG_REASON_BREAKPOINT;
-
- default:
- return DBG_REASON_DBGRQ;
- }
-};
-
-
-
-/** Prepare the stage for ITR/DTR operations
- * from the arm11_run_instr... group of functions.
- *
- * Put arm11_run_instr_data_prepare() and arm11_run_instr_data_finish()
- * around a block of arm11_run_instr_... calls.
- *
- * Select scan chain 5 to allow quick access to DTR. When scan
- * chain 4 is needed to put in a register the ITRSel instruction
- * shortcut is used instead of actually changing the Scan_N
- * register.
- *
- * \param arm11 Target state variable.
- *
- */
-void arm11_run_instr_data_prepare(arm11_common_t * arm11)
-{
- arm11_add_debug_SCAN_N(arm11, 0x05, -1);
-}
-
-/** Cleanup after ITR/DTR operations
- * from the arm11_run_instr... group of functions
- *
- * Put arm11_run_instr_data_prepare() and arm11_run_instr_data_finish()
- * around a block of arm11_run_instr_... calls.
- *
- * Any RTI can lead to an instruction execution when
- * scan chains 4 or 5 are selected and the IR holds
- * INTEST or EXTEST. So we must disable that before
- * any following activities lead to an RTI.
- *
- * \param arm11 Target state variable.
- *
- */
-void arm11_run_instr_data_finish(arm11_common_t * arm11)
-{
- arm11_add_debug_SCAN_N(arm11, 0x00, -1);
-}
-
-
-/** Execute one or multiple instructions via ITR
- *
- * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block
- *
- * \param arm11 Target state variable.
- * \param opcode Pointer to sequence of ARM opcodes
- * \param count Number of opcodes to execute
- *
- */
-void arm11_run_instr_no_data(arm11_common_t * arm11, u32 * opcode, size_t count)
-{
- arm11_add_IR(arm11, ARM11_ITRSEL, -1);
-
- while (count--)
- {
- arm11_add_debug_INST(arm11, *opcode++, NULL, TAP_RTI);
-
- while (1)
- {
- u8 flag;
-
- arm11_add_debug_INST(arm11, 0, &flag, count ? TAP_RTI : TAP_PD);
-
- jtag_execute_queue();
-
- if (flag)
- break;
- }
- }
-}
-
-/** Execute one instruction via ITR
- *
- * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block
- *
- * \param arm11 Target state variable.
- * \param opcode ARM opcode
- *
- */
-void arm11_run_instr_no_data1(arm11_common_t * arm11, u32 opcode)
-{
- arm11_run_instr_no_data(arm11, &opcode, 1);
-}
-
-
-/** Execute one instruction via ITR repeatedly while
- * passing data to the core via DTR on each execution.
- *
- * The executed instruction \em must read data from DTR.
- *
- * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block
- *
- * \param arm11 Target state variable.
- * \param opcode ARM opcode
- * \param data Pointer to the data words to be passed to the core
- * \param count Number of data words and instruction repetitions
- *
- */
-void arm11_run_instr_data_to_core(arm11_common_t * arm11, u32 opcode, u32 * data, size_t count)
-{
- arm11_add_IR(arm11, ARM11_ITRSEL, -1);
-
- arm11_add_debug_INST(arm11, opcode, NULL, TAP_PD);
-
- arm11_add_IR(arm11, ARM11_EXTEST, -1);
-
- scan_field_t chain5_fields[3];
-
- u32 Data;
- u8 Ready;
- u8 nRetry;
-
- arm11_setup_field(arm11, 32, &Data, NULL, chain5_fields + 0);
- arm11_setup_field(arm11, 1, NULL, &Ready, chain5_fields + 1);
- arm11_setup_field(arm11, 1, NULL, &nRetry, chain5_fields + 2);
-
- while (count--)
- {
- do
- {
- Data = *data;
-
- jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_RTI);
- jtag_execute_queue();
-
- JTAG_DEBUG("DTR Ready %d nRetry %d", Ready, nRetry);
- }
- while (!Ready);
-
- data++;
- }
-
- arm11_add_IR(arm11, ARM11_INTEST, -1);
-
- do
- {
- Data = 0;
-
- jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD);
- jtag_execute_queue();
-
- JTAG_DEBUG("DTR Data %08x Ready %d nRetry %d", Data, Ready, nRetry);
- }
- while (!Ready);
-
-
-}
-
-/** Execute an instruction via ITR while handing data into the core via DTR.
- *
- * The executed instruction \em must read data from DTR.
- *
- * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block
- *
- * \param arm11 Target state variable.
- * \param opcode ARM opcode
- * \param data Data word to be passed to the core via DTR
- *
- */
-void arm11_run_instr_data_to_core1(arm11_common_t * arm11, u32 opcode, u32 data)
-{
- arm11_run_instr_data_to_core(arm11, opcode, &data, 1);
-}
-
-
-/** Execute one instruction via ITR repeatedly while
- * reading data from the core via DTR on each execution.
- *
- * The executed instruction \em must write data to DTR.
- *
- * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block
- *
- * \param arm11 Target state variable.
- * \param opcode ARM opcode
- * \param data Pointer to an array that receives the data words from the core
- * \param count Number of data words and instruction repetitions
- *
- */
-void arm11_run_instr_data_from_core(arm11_common_t * arm11, u32 opcode, u32 * data, size_t count)
-{
- arm11_add_IR(arm11, ARM11_ITRSEL, -1);
-
- arm11_add_debug_INST(arm11, opcode, NULL, TAP_RTI);
-
- arm11_add_IR(arm11, ARM11_INTEST, -1);
-
- scan_field_t chain5_fields[3];
-
- u32 Data;
- u8 Ready;
- u8 nRetry;
-
- arm11_setup_field(arm11, 32, NULL, &Data, chain5_fields + 0);
- arm11_setup_field(arm11, 1, NULL, &Ready, chain5_fields + 1);
- arm11_setup_field(arm11, 1, NULL, &nRetry, chain5_fields + 2);
-
- while (count--)
- {
- do
- {
- jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, count ? TAP_RTI : TAP_PD);
- jtag_execute_queue();
-
- JTAG_DEBUG("DTR Data %08x Ready %d nRetry %d", Data, Ready, nRetry);
- }
- while (!Ready);
-
- *data++ = Data;
- }
-}
-
-/** Execute one instruction via ITR
- * then load r0 into DTR and read DTR from core.
- *
- * The first executed instruction (\p opcode) should write data to r0.
- *
- * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block
- *
- * \param arm11 Target state variable.
- * \param opcode ARM opcode to write r0 with the value of interest
- * \param data Pointer to a data word that receives the value from r0 after \p opcode was executed.
- *
- */
-void arm11_run_instr_data_from_core_via_r0(arm11_common_t * arm11, u32 opcode, u32 * data)
-{
- arm11_run_instr_no_data1(arm11, opcode);
-
- /* MCR p14,0,R0,c0,c5,0 (move r0 -> wDTR -> local var) */
- arm11_run_instr_data_from_core(arm11, 0xEE000E15, data, 1);
-}
-
-/** Load data into core via DTR then move it to r0 then
- * execute one instruction via ITR
- *
- * The final executed instruction (\p opcode) should read data from r0.
- *
- * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block
- *
- * \param arm11 Target state variable.
- * \param opcode ARM opcode to read r0 act upon it
- * \param data Data word that will be written to r0 before \p opcode is executed
- *
- */
-void arm11_run_instr_data_to_core_via_r0(arm11_common_t * arm11, u32 opcode, u32 data)
-{
- /* MRC p14,0,r0,c0,c5,0 */
- arm11_run_instr_data_to_core1(arm11, 0xEE100E15, data);
-
- arm11_run_instr_no_data1(arm11, opcode);
-}
-
-
-void arm11_sc7_run(arm11_common_t * arm11, arm11_sc7_action_t * actions, size_t count)
-{
- arm11_add_debug_SCAN_N(arm11, 0x07, -1);
-
- arm11_add_IR(arm11, ARM11_EXTEST, -1);
-
- scan_field_t chain7_fields[3];
-
- u8 nRW;
- u32 DataOut;
- u8 AddressOut;
- u8 Ready;
- u32 DataIn;
- u8 AddressIn;
-
- arm11_setup_field(arm11, 1, &nRW, &Ready, chain7_fields + 0);
- arm11_setup_field(arm11, 32, &DataOut, &DataIn, chain7_fields + 1);
- arm11_setup_field(arm11, 7, &AddressOut, &AddressIn, chain7_fields + 2);
-
- {size_t i;
- for (i = 0; i < count + 1; i++)
- {
- if (i < count)
- {
- nRW = actions[i].write ? 1 : 0;
- DataOut = actions[i].value;
- AddressOut = actions[i].address;
- }
- else
- {
- nRW = 0;
- DataOut = 0;
- AddressOut = 0;
- }
-
- do
- {
- JTAG_DEBUG("SC7 <= Address %02x Data %08x nRW %d", AddressOut, DataOut, nRW);
-
- jtag_add_dr_scan_vc(asizeof(chain7_fields), chain7_fields, TAP_PD);
- jtag_execute_queue();
-
- JTAG_DEBUG("SC7 => Address %02x Data %08x Ready %d", AddressIn, DataIn, Ready);
- }
- while (!Ready); /* 'nRW' is 'Ready' on read out */
-
- if (i > 0)
- {
- if (actions[i - 1].address != AddressIn)
- {
- WARNING("Scan chain 7 shifted out unexpected address");
- }
-
- if (!actions[i - 1].write)
- {
- actions[i - 1].value = DataIn;
- }
- else
- {
- if (actions[i - 1].value != DataIn)
- {
- WARNING("Scan chain 7 shifted out unexpected data");
- }
- }
- }
- }}
-
- {size_t i;
- for (i = 0; i < count; i++)
- {
- JTAG_DEBUG("SC7 %02d: %02x %s %08x", i, actions[i].address, actions[i].write ? "<=" : "=>", actions[i].value);
- }}
-}
-
-void arm11_sc7_clear_bw(arm11_common_t * arm11)
-{
- size_t actions = arm11->brp + arm11->wrp;
-
- arm11_sc7_action_t clear_bw[actions];
-
- {size_t i;
- for (i = 0; i < actions; i++)
- {
- clear_bw[i].write = true;
- clear_bw[i].value = 0;
- clear_bw[i].address =
- i < arm11->brp ?
- ARM11_SC7_BCR0 + i :
- ARM11_SC7_WCR0 + i - arm11->brp;
- }}
-
- arm11_sc7_run(arm11, clear_bw, actions);
-}
-
+/*************************************************************************** + * Copyright (C) 2008 digenius technology GmbH. * + * * + * 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 "arm11.h" +#include "jtag.h" +#include "log.h" + +#include <stdlib.h> +#include <string.h> + +#if 0 +#define JTAG_DEBUG(expr ...) \ + do { \ + log_printf (LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, expr); \ + } while(0) +#else +#define JTAG_DEBUG(expr ...) \ + do {} while(0) +#endif + +/** Code de-clutter: Construct scan_field_t to write out a value + * + * \param arm11 Target state variable. + * \param num_bits Length of the data field + * \param out_data pointer to the data that will be sent out + * <em>(data is read when it is added to the JTAG queue)</em> + * \param in_data pointer to the memory that will receive data that was clocked in + * <em>(data is written when the JTAG queue is executed)</em> + * \param field target data structure that will be initialized + */ +void arm11_setup_field(arm11_common_t * arm11, int num_bits, void * out_data, void * in_data, scan_field_t * field) +{ + field->device = arm11->jtag_info.chain_pos; + field->num_bits = num_bits; + field->out_mask = NULL; + field->in_check_mask = NULL; + field->in_check_value = NULL; + field->in_handler = NULL; + field->in_handler_priv = NULL; + + field->out_value = out_data; + field->in_value = in_data; +} + + +/** Write JTAG instruction register + * + * \param arm11 Target state variable. + * \param instr An ARM11 DBGTAP instruction. Use enum #arm11_instructions. + * \param state Pass the final TAP state or -1 for the default value (Pause-IR). + * + * \remarks This adds to the JTAG command queue but does \em not execute it. + */ +void arm11_add_IR(arm11_common_t * arm11, u8 instr, enum tap_state state) +{ + jtag_device_t *device = jtag_get_device(arm11->jtag_info.chain_pos); + + if (buf_get_u32(device->cur_instr, 0, 5) == instr) + { + JTAG_DEBUG("IR <= 0x%02x SKIPPED", instr); + return; + } + + JTAG_DEBUG("IR <= 0x%02x", instr); + + scan_field_t field; + + arm11_setup_field(arm11, 5, &instr, NULL, &field); + + jtag_add_ir_scan_vc(1, &field, state == -1 ? TAP_PI : state); +} + +/** Verify shifted out data from Scan Chain Register (SCREG) + * Used as parameter to scan_field_t::in_handler in + * arm11_add_debug_SCAN_N(). + * + */ +static int arm11_in_handler_SCAN_N(u8 *in_value, void *priv, struct scan_field_s *field) +{ + /** \todo TODO: clarify why this isnt properly masked in jtag.c jtag_read_buffer() */ + u8 v = *in_value & 0x1F; + + if (v != 0x10) + { + ERROR("'arm11 target' JTAG communication error SCREG SCAN OUT 0x%02x (expected 0x10)", v); + exit(-1); + } + + JTAG_DEBUG("SCREG SCAN OUT 0x%02x", v); + return ERROR_OK; +} + +/** Select and write to Scan Chain Register (SCREG) + * + * This function sets the instruction register to SCAN_N and writes + * the data register with the selected chain number. + * + * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301f/Cacbjhfg.html + * + * \param arm11 Target state variable. + * \param chain Scan chain that will be selected. + * \param state Pass the final TAP state or -1 for the default + * value (Pause-DR). + * + * The chain takes effect when Update-DR is passed (usually when subsequently + * the INTEXT/EXTEST instructions are written). + * + * \warning (Obsolete) Using this twice in a row will \em fail. The first call will end + * in Pause-DR. The second call, due to the IR caching, will not + * go through Capture-DR when shifting in the new scan chain number. + * As a result the verification in arm11_in_handler_SCAN_N() must + * fail. + * + * \remarks This adds to the JTAG command queue but does \em not execute it. + */ + +void arm11_add_debug_SCAN_N(arm11_common_t * arm11, u8 chain, enum tap_state state) +{ + JTAG_DEBUG("SCREG <= 0x%02x", chain); + + arm11_add_IR(arm11, ARM11_SCAN_N, -1); + + scan_field_t field; + + arm11_setup_field(arm11, 5, &chain, NULL, &field); + + field.in_handler = arm11_in_handler_SCAN_N; + + jtag_add_dr_scan_vc(1, &field, state == -1 ? TAP_PD : state); +} + +/** Write an instruction into the ITR register + * + * \param arm11 Target state variable. + * \param inst An ARM11 processor instruction/opcode. + * \param flag Optional parameter to retrieve the InstCompl flag + * (this will be written when the JTAG chain is executed). + * \param state Pass the final TAP state or -1 for the default + * value (Run-Test/Idle). + * + * \remarks By default this ends with Run-Test/Idle state + * and causes the instruction to be executed. If + * a subsequent write to DTR is needed before + * executing the instruction then TAP_PD should be + * passed to \p state. + * + * \remarks This adds to the JTAG command queue but does \em not execute it. + */ +void arm11_add_debug_INST(arm11_common_t * arm11, u32 inst, u8 * flag, enum tap_state state) +{ + JTAG_DEBUG("INST <= 0x%08x", inst); + + scan_field_t itr[2]; + + arm11_setup_field(arm11, 32, &inst, NULL, itr + 0); + arm11_setup_field(arm11, 1, NULL, flag, itr + 1); + + jtag_add_dr_scan_vc(asizeof(itr), itr, state == -1 ? TAP_RTI : state); +} + +/** Read the Debug Status and Control Register (DSCR) + * + * same as CP14 c1 + * + * \param arm11 Target state variable. + * \return DSCR content + * + * \remarks This is a stand-alone function that executes the JTAG command queue. + */ +u32 arm11_read_DSCR(arm11_common_t * arm11) +{ + arm11_add_debug_SCAN_N(arm11, 0x01, -1); + + arm11_add_IR(arm11, ARM11_INTEST, -1); + + u32 dscr; + scan_field_t chain1_field; + + arm11_setup_field(arm11, 32, NULL, &dscr, &chain1_field); + + jtag_add_dr_scan_vc(1, &chain1_field, TAP_PD); + + jtag_execute_queue(); + + if (arm11->last_dscr != dscr) + JTAG_DEBUG("DSCR = %08x (OLD %08x)", dscr, arm11->last_dscr); + + arm11->last_dscr = dscr; + + return dscr; +} + +/** Write the Debug Status and Control Register (DSCR) + * + * same as CP14 c1 + * + * \param arm11 Target state variable. + * \param dscr DSCR content + * + * \remarks This is a stand-alone function that executes the JTAG command queue. + */ +void arm11_write_DSCR(arm11_common_t * arm11, u32 dscr) +{ + arm11_add_debug_SCAN_N(arm11, 0x01, -1); + + arm11_add_IR(arm11, ARM11_EXTEST, -1); + + scan_field_t chain1_field; + + arm11_setup_field(arm11, 32, &dscr, NULL, &chain1_field); + + jtag_add_dr_scan_vc(1, &chain1_field, TAP_PD); + + jtag_execute_queue(); + + JTAG_DEBUG("DSCR <= %08x (OLD %08x)", dscr, arm11->last_dscr); + + arm11->last_dscr = dscr; +} + + + +/** Get the debug reason from Debug Status and Control Register (DSCR) + * + * \param dscr DSCR value to analyze + * \return Debug reason + * + */ +enum target_debug_reason arm11_get_DSCR_debug_reason(u32 dscr) +{ + switch (dscr & ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_MASK) + { + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_HALT: return DBG_REASON_DBGRQ; + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BREAKPOINT: return DBG_REASON_BREAKPOINT; + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_WATCHPOINT: return DBG_REASON_WATCHPOINT; + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BKPT_INSTRUCTION: return DBG_REASON_BREAKPOINT; + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_EDBGRQ: return DBG_REASON_DBGRQ; + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_VECTOR_CATCH: return DBG_REASON_BREAKPOINT; + + default: + return DBG_REASON_DBGRQ; + } +}; + + + +/** Prepare the stage for ITR/DTR operations + * from the arm11_run_instr... group of functions. + * + * Put arm11_run_instr_data_prepare() and arm11_run_instr_data_finish() + * around a block of arm11_run_instr_... calls. + * + * Select scan chain 5 to allow quick access to DTR. When scan + * chain 4 is needed to put in a register the ITRSel instruction + * shortcut is used instead of actually changing the Scan_N + * register. + * + * \param arm11 Target state variable. + * + */ +void arm11_run_instr_data_prepare(arm11_common_t * arm11) +{ + arm11_add_debug_SCAN_N(arm11, 0x05, -1); +} + +/** Cleanup after ITR/DTR operations + * from the arm11_run_instr... group of functions + * + * Put arm11_run_instr_data_prepare() and arm11_run_instr_data_finish() + * around a block of arm11_run_instr_... calls. + * + * Any RTI can lead to an instruction execution when + * scan chains 4 or 5 are selected and the IR holds + * INTEST or EXTEST. So we must disable that before + * any following activities lead to an RTI. + * + * \param arm11 Target state variable. + * + */ +void arm11_run_instr_data_finish(arm11_common_t * arm11) +{ + arm11_add_debug_SCAN_N(arm11, 0x00, -1); +} + + +/** Execute one or multiple instructions via ITR + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode Pointer to sequence of ARM opcodes + * \param count Number of opcodes to execute + * + */ +void arm11_run_instr_no_data(arm11_common_t * arm11, u32 * opcode, size_t count) +{ + arm11_add_IR(arm11, ARM11_ITRSEL, -1); + + while (count--) + { + arm11_add_debug_INST(arm11, *opcode++, NULL, TAP_RTI); + + while (1) + { + u8 flag; + + arm11_add_debug_INST(arm11, 0, &flag, count ? TAP_RTI : TAP_PD); + + jtag_execute_queue(); + + if (flag) + break; + } + } +} + +/** Execute one instruction via ITR + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode + * + */ +void arm11_run_instr_no_data1(arm11_common_t * arm11, u32 opcode) +{ + arm11_run_instr_no_data(arm11, &opcode, 1); +} + + +/** Execute one instruction via ITR repeatedly while + * passing data to the core via DTR on each execution. + * + * The executed instruction \em must read data from DTR. + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode + * \param data Pointer to the data words to be passed to the core + * \param count Number of data words and instruction repetitions + * + */ +void arm11_run_instr_data_to_core(arm11_common_t * arm11, u32 opcode, u32 * data, size_t count) +{ + arm11_add_IR(arm11, ARM11_ITRSEL, -1); + + arm11_add_debug_INST(arm11, opcode, NULL, TAP_PD); + + arm11_add_IR(arm11, ARM11_EXTEST, -1); + + scan_field_t chain5_fields[3]; + + u32 Data; + u8 Ready; + u8 nRetry; + + arm11_setup_field(arm11, 32, &Data, NULL, chain5_fields + 0); + arm11_setup_field(arm11, 1, NULL, &Ready, chain5_fields + 1); + arm11_setup_field(arm11, 1, NULL, &nRetry, chain5_fields + 2); + + while (count--) + { + do + { + Data = *data; + + jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_RTI); + jtag_execute_queue(); + + JTAG_DEBUG("DTR Ready %d nRetry %d", Ready, nRetry); + } + while (!Ready); + + data++; + } + + arm11_add_IR(arm11, ARM11_INTEST, -1); + + do + { + Data = 0; + + jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD); + jtag_execute_queue(); + + JTAG_DEBUG("DTR Data %08x Ready %d nRetry %d", Data, Ready, nRetry); + } + while (!Ready); + + +} + +/** Execute an instruction via ITR while handing data into the core via DTR. + * + * The executed instruction \em must read data from DTR. + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode + * \param data Data word to be passed to the core via DTR + * + */ +void arm11_run_instr_data_to_core1(arm11_common_t * arm11, u32 opcode, u32 data) +{ + arm11_run_instr_data_to_core(arm11, opcode, &data, 1); +} + + +/** Execute one instruction via ITR repeatedly while + * reading data from the core via DTR on each execution. + * + * The executed instruction \em must write data to DTR. + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode + * \param data Pointer to an array that receives the data words from the core + * \param count Number of data words and instruction repetitions + * + */ +void arm11_run_instr_data_from_core(arm11_common_t * arm11, u32 opcode, u32 * data, size_t count) +{ + arm11_add_IR(arm11, ARM11_ITRSEL, -1); + + arm11_add_debug_INST(arm11, opcode, NULL, TAP_RTI); + + arm11_add_IR(arm11, ARM11_INTEST, -1); + + scan_field_t chain5_fields[3]; + + u32 Data; + u8 Ready; + u8 nRetry; + + arm11_setup_field(arm11, 32, NULL, &Data, chain5_fields + 0); + arm11_setup_field(arm11, 1, NULL, &Ready, chain5_fields + 1); + arm11_setup_field(arm11, 1, NULL, &nRetry, chain5_fields + 2); + + while (count--) + { + do + { + jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, count ? TAP_RTI : TAP_PD); + jtag_execute_queue(); + + JTAG_DEBUG("DTR Data %08x Ready %d nRetry %d", Data, Ready, nRetry); + } + while (!Ready); + + *data++ = Data; + } +} + +/** Execute one instruction via ITR + * then load r0 into DTR and read DTR from core. + * + * The first executed instruction (\p opcode) should write data to r0. + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode to write r0 with the value of interest + * \param data Pointer to a data word that receives the value from r0 after \p opcode was executed. + * + */ +void arm11_run_instr_data_from_core_via_r0(arm11_common_t * arm11, u32 opcode, u32 * data) +{ + arm11_run_instr_no_data1(arm11, opcode); + + /* MCR p14,0,R0,c0,c5,0 (move r0 -> wDTR -> local var) */ + arm11_run_instr_data_from_core(arm11, 0xEE000E15, data, 1); +} + +/** Load data into core via DTR then move it to r0 then + * execute one instruction via ITR + * + * The final executed instruction (\p opcode) should read data from r0. + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode to read r0 act upon it + * \param data Data word that will be written to r0 before \p opcode is executed + * + */ +void arm11_run_instr_data_to_core_via_r0(arm11_common_t * arm11, u32 opcode, u32 data) +{ + /* MRC p14,0,r0,c0,c5,0 */ + arm11_run_instr_data_to_core1(arm11, 0xEE100E15, data); + + arm11_run_instr_no_data1(arm11, opcode); +} + + +void arm11_sc7_run(arm11_common_t * arm11, arm11_sc7_action_t * actions, size_t count) +{ + arm11_add_debug_SCAN_N(arm11, 0x07, -1); + + arm11_add_IR(arm11, ARM11_EXTEST, -1); + + scan_field_t chain7_fields[3]; + + u8 nRW; + u32 DataOut; + u8 AddressOut; + u8 Ready; + u32 DataIn; + u8 AddressIn; + + arm11_setup_field(arm11, 1, &nRW, &Ready, chain7_fields + 0); + arm11_setup_field(arm11, 32, &DataOut, &DataIn, chain7_fields + 1); + arm11_setup_field(arm11, 7, &AddressOut, &AddressIn, chain7_fields + 2); + + {size_t i; + for (i = 0; i < count + 1; i++) + { + if (i < count) + { + nRW = actions[i].write ? 1 : 0; + DataOut = actions[i].value; + AddressOut = actions[i].address; + } + else + { + nRW = 0; + DataOut = 0; + AddressOut = 0; + } + + do + { + JTAG_DEBUG("SC7 <= Address %02x Data %08x nRW %d", AddressOut, DataOut, nRW); + + jtag_add_dr_scan_vc(asizeof(chain7_fields), chain7_fields, TAP_PD); + jtag_execute_queue(); + + JTAG_DEBUG("SC7 => Address %02x Data %08x Ready %d", AddressIn, DataIn, Ready); + } + while (!Ready); /* 'nRW' is 'Ready' on read out */ + + if (i > 0) + { + if (actions[i - 1].address != AddressIn) + { + WARNING("Scan chain 7 shifted out unexpected address"); + } + + if (!actions[i - 1].write) + { + actions[i - 1].value = DataIn; + } + else + { + if (actions[i - 1].value != DataIn) + { + WARNING("Scan chain 7 shifted out unexpected data"); + } + } + } + }} + + {size_t i; + for (i = 0; i < count; i++) + { + JTAG_DEBUG("SC7 %02d: %02x %s %08x", i, actions[i].address, actions[i].write ? "<=" : "=>", actions[i].value); + }} +} + +void arm11_sc7_clear_bw(arm11_common_t * arm11) +{ + size_t actions = arm11->brp + arm11->wrp; + + arm11_sc7_action_t clear_bw[actions]; + + {size_t i; + for (i = 0; i < actions; i++) + { + clear_bw[i].write = true; + clear_bw[i].value = 0; + clear_bw[i].address = + i < arm11->brp ? + ARM11_SC7_BCR0 + i : + ARM11_SC7_WCR0 + i - arm11->brp; + }} + + arm11_sc7_run(arm11, clear_bw, actions); +} + diff --git a/src/target/arm720t.c b/src/target/arm720t.c index 87a1afb..2c7e2ae 100644 --- a/src/target/arm720t.c +++ b/src/target/arm720t.c @@ -1,626 +1,626 @@ -/***************************************************************************
- * 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 "arm720t.h"
-#include "jtag.h"
-#include "log.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#if 0
-#define _DEBUG_INSTRUCTION_EXECUTION_
-#endif
-
-/* cli handling */
-int arm720t_register_commands(struct command_context_s *cmd_ctx);
-
-int arm720t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int arm720t_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int arm720t_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int arm720t_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-/* forward declarations */
-int arm720t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
-int arm720t_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
-int arm720t_quit();
-int arm720t_arch_state(struct target_s *target);
-int arm720t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
-int arm720t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
-int arm720t_soft_reset_halt(struct target_s *target);
-
-target_type_t arm720t_target =
-{
- .name = "arm720t",
-
- .poll = arm7_9_poll,
- .arch_state = arm720t_arch_state,
-
- .halt = arm7_9_halt,
- .resume = arm7_9_resume,
- .step = arm7_9_step,
-
- .assert_reset = arm7_9_assert_reset,
- .deassert_reset = arm7_9_deassert_reset,
- .soft_reset_halt = arm720t_soft_reset_halt,
- .prepare_reset_halt = arm7_9_prepare_reset_halt,
-
- .get_gdb_reg_list = armv4_5_get_gdb_reg_list,
-
- .read_memory = arm720t_read_memory,
- .write_memory = arm720t_write_memory,
- .bulk_write_memory = arm7_9_bulk_write_memory,
- .checksum_memory = arm7_9_checksum_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,
- .remove_watchpoint = arm7_9_remove_watchpoint,
-
- .register_commands = arm720t_register_commands,
- .target_command = arm720t_target_command,
- .init_target = arm720t_init_target,
- .quit = arm720t_quit
-};
-
-int arm720t_scan_cp15(target_t *target, u32 out, u32 *in, int instruction, int clock)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
- scan_field_t fields[2];
- u8 out_buf[4];
- u8 instruction_buf = instruction;
-
- buf_set_u32(out_buf, 0, 32, flip_u32(out, 32));
-
- jtag_add_end_state(TAP_PD);
- arm_jtag_scann(jtag_info, 0xf);
- arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 1;
- fields[0].out_value = &instruction_buf;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 32;
- fields[1].out_value = out_buf;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- if (in)
- {
- fields[1].in_handler = arm_jtag_buf_to_u32_flip;
- fields[1].in_handler_priv = in;
- } else
- {
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
- }
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
-
- jtag_add_dr_scan(2, fields, -1);
-
- if (clock)
- jtag_add_runtest(0, -1);
-
-#ifdef _DEBUG_INSTRUCTION_EXECUTION_
- jtag_execute_queue();
-
- if (in)
- DEBUG("out: %8.8x, in: %8.8x, instruction: %i, clock: %i", out, *in, instruction, clock);
- else
- DEBUG("out: %8.8x, instruction: %i, clock: %i", out, instruction, clock);
-#else
- DEBUG("out: %8.8x, instruction: %i, clock: %i", out, instruction, clock);
-#endif
-
- return ERROR_OK;
-}
-
-int arm720t_read_cp15(target_t *target, u32 opcode, u32 *value)
-{
- /* fetch CP15 opcode */
- arm720t_scan_cp15(target, opcode, NULL, 1, 1);
- /* "DECODE" stage */
- arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1);
- /* "EXECUTE" stage (1) */
- arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0);
- arm720t_scan_cp15(target, 0x0, NULL, 0, 1);
- /* "EXECUTE" stage (2) */
- arm720t_scan_cp15(target, 0x0, NULL, 0, 1);
- /* "EXECUTE" stage (3), CDATA is read */
- arm720t_scan_cp15(target, ARMV4_5_NOP, value, 1, 1);
-
- return ERROR_OK;
-}
-
-int arm720t_write_cp15(target_t *target, u32 opcode, u32 value)
-{
- /* fetch CP15 opcode */
- arm720t_scan_cp15(target, opcode, NULL, 1, 1);
- /* "DECODE" stage */
- arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1);
- /* "EXECUTE" stage (1) */
- arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0);
- arm720t_scan_cp15(target, 0x0, NULL, 0, 1);
- /* "EXECUTE" stage (2) */
- arm720t_scan_cp15(target, value, NULL, 0, 1);
- arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1);
-
- return ERROR_OK;
-}
-
-u32 arm720t_get_ttb(target_t *target)
-{
- u32 ttb = 0x0;
-
- arm720t_read_cp15(target, 0xee120f10, &ttb);
- jtag_execute_queue();
-
- ttb &= 0xffffc000;
-
- return ttb;
-}
-
-void arm720t_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
-{
- u32 cp15_control;
-
- /* read cp15 control register */
- arm720t_read_cp15(target, 0xee110f10, &cp15_control);
- jtag_execute_queue();
-
- if (mmu)
- cp15_control &= ~0x1U;
-
- if (d_u_cache || i_cache)
- cp15_control &= ~0x4U;
-
- arm720t_write_cp15(target, 0xee010f10, cp15_control);
-}
-
-void arm720t_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
-{
- u32 cp15_control;
-
- /* read cp15 control register */
- arm720t_read_cp15(target, 0xee110f10, &cp15_control);
- jtag_execute_queue();
-
- if (mmu)
- cp15_control |= 0x1U;
-
- if (d_u_cache || i_cache)
- cp15_control |= 0x4U;
-
- arm720t_write_cp15(target, 0xee010f10, cp15_control);
-}
-
-void arm720t_post_debug_entry(target_t *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
- arm720t_common_t *arm720t = arm7tdmi->arch_info;
-
- /* examine cp15 control reg */
- arm720t_read_cp15(target, 0xee110f10, &arm720t->cp15_control_reg);
- jtag_execute_queue();
- DEBUG("cp15_control_reg: %8.8x", arm720t->cp15_control_reg);
-
- arm720t->armv4_5_mmu.mmu_enabled = (arm720t->cp15_control_reg & 0x1U) ? 1 : 0;
- arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm720t->cp15_control_reg & 0x4U) ? 1 : 0;
- arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
-
- /* save i/d fault status and address register */
- arm720t_read_cp15(target, 0xee150f10, &arm720t->fsr_reg);
- arm720t_read_cp15(target, 0xee160f10, &arm720t->far_reg);
- jtag_execute_queue();
-}
-
-void arm720t_pre_restore_context(target_t *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
- arm720t_common_t *arm720t = arm7tdmi->arch_info;
-
- /* restore i/d fault status and address register */
- arm720t_write_cp15(target, 0xee050f10, arm720t->fsr_reg);
- arm720t_write_cp15(target, 0xee060f10, arm720t->far_reg);
-}
-
-int arm720t_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm7tdmi_common_t **arm7tdmi_p, arm720t_common_t **arm720t_p)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9;
- arm7tdmi_common_t *arm7tdmi;
- arm720t_common_t *arm720t;
-
- if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
- {
- return -1;
- }
-
- arm7_9 = armv4_5->arch_info;
- if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC)
- {
- return -1;
- }
-
- arm7tdmi = arm7_9->arch_info;
- if (arm7tdmi->common_magic != ARM7TDMI_COMMON_MAGIC)
- {
- return -1;
- }
-
- arm720t = arm7tdmi->arch_info;
- if (arm720t->common_magic != ARM720T_COMMON_MAGIC)
- {
- return -1;
- }
-
- *armv4_5_p = armv4_5;
- *arm7_9_p = arm7_9;
- *arm7tdmi_p = arm7tdmi;
- *arm720t_p = arm720t;
-
- return ERROR_OK;
-}
-
-int arm720t_arch_state(struct target_s *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
- arm720t_common_t *arm720t = arm7tdmi->arch_info;
-
- char *state[] =
- {
- "disabled", "enabled"
- };
-
- if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
- {
- ERROR("BUG: called for a non-ARMv4/5 target");
- exit(-1);
- }
-
- USER("target halted in %s state due to %s, current mode: %s\n"
- "cpsr: 0x%8.8x pc: 0x%8.8x\n"
- "MMU: %s, Cache: %s",
- armv4_5_state_strings[armv4_5->core_state],
- target_debug_reason_strings[target->debug_reason],
- armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)],
- buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
- buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32),
- state[arm720t->armv4_5_mmu.mmu_enabled],
- state[arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled]);
-
- return ERROR_OK;
-}
-
-int arm720t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
-{
- int retval;
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
- arm720t_common_t *arm720t = arm7tdmi->arch_info;
-
- /* disable cache, but leave MMU enabled */
- if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled)
- arm720t_disable_mmu_caches(target, 0, 1, 0);
-
- retval = arm7_9_read_memory(target, address, size, count, buffer);
-
- if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled)
- arm720t_enable_mmu_caches(target, 0, 1, 0);
-
- return retval;
-}
-
-int arm720t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
-{
- int retval;
-
- if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK)
- return retval;
-
- return retval;
-}
-
-int arm720t_soft_reset_halt(struct target_s *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info;
- arm720t_common_t *arm720t = arm7tdmi->arch_info;
- reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
-
- if (target->state == TARGET_RUNNING)
- {
- target->type->halt(target);
- }
-
- while (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0)
- {
- embeddedice_read_reg(dbg_stat);
- jtag_execute_queue();
- }
-
- target->state = TARGET_HALTED;
-
- /* SVC, ARM state, IRQ and FIQ disabled */
- buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3);
- armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
- armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
-
- /* start fetching from 0x0 */
- buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0);
- armv4_5->core_cache->reg_list[15].dirty = 1;
- armv4_5->core_cache->reg_list[15].valid = 1;
-
- armv4_5->core_mode = ARMV4_5_MODE_SVC;
- armv4_5->core_state = ARMV4_5_STATE_ARM;
-
- arm720t_disable_mmu_caches(target, 1, 1, 1);
- arm720t->armv4_5_mmu.mmu_enabled = 0;
- arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0;
- arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
-
- target_call_event_callbacks(target, TARGET_EVENT_HALTED);
-
- return ERROR_OK;
-}
-
-int arm720t_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
-{
- arm7tdmi_init_target(cmd_ctx, target);
-
- return ERROR_OK;
-
-}
-
-int arm720t_quit()
-{
-
- return ERROR_OK;
-}
-
-int arm720t_init_arch_info(target_t *target, arm720t_common_t *arm720t, int chain_pos, char *variant)
-{
- arm7tdmi_common_t *arm7tdmi = &arm720t->arm7tdmi_common;
- arm7_9_common_t *arm7_9 = &arm7tdmi->arm7_9_common;
-
- arm7tdmi_init_arch_info(target, arm7tdmi, chain_pos, variant);
-
- arm7tdmi->arch_info = arm720t;
- arm720t->common_magic = ARM720T_COMMON_MAGIC;
-
- arm7_9->post_debug_entry = arm720t_post_debug_entry;
- arm7_9->pre_restore_context = arm720t_pre_restore_context;
-
- arm720t->armv4_5_mmu.armv4_5_cache.ctype = -1;
- arm720t->armv4_5_mmu.get_ttb = arm720t_get_ttb;
- arm720t->armv4_5_mmu.read_memory = arm7_9_read_memory;
- arm720t->armv4_5_mmu.write_memory = arm7_9_write_memory;
- arm720t->armv4_5_mmu.disable_mmu_caches = arm720t_disable_mmu_caches;
- arm720t->armv4_5_mmu.enable_mmu_caches = arm720t_enable_mmu_caches;
- arm720t->armv4_5_mmu.has_tiny_pages = 0;
- arm720t->armv4_5_mmu.mmu_enabled = 0;
-
- return ERROR_OK;
-}
-
-int arm720t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
-{
- int chain_pos;
- char *variant = NULL;
- arm720t_common_t *arm720t = malloc(sizeof(arm720t_common_t));
-
- if (argc < 4)
- {
- ERROR("'target arm720t' requires at least one additional argument");
- exit(-1);
- }
-
- chain_pos = strtoul(args[3], NULL, 0);
-
- if (argc >= 5)
- variant = args[4];
-
- DEBUG("chain_pos: %i, variant: %s", chain_pos, variant);
-
- arm720t_init_arch_info(target, arm720t, chain_pos, variant);
-
- return ERROR_OK;
-}
-
-int arm720t_register_commands(struct command_context_s *cmd_ctx)
-{
- int retval;
- command_t *arm720t_cmd;
-
-
- retval = arm7tdmi_register_commands(cmd_ctx);
-
- arm720t_cmd = register_command(cmd_ctx, NULL, "arm720t", NULL, COMMAND_ANY, "arm720t specific commands");
-
- register_command(cmd_ctx, arm720t_cmd, "cp15", arm720t_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register <opcode> [value]");
- register_command(cmd_ctx, arm720t_cmd, "virt2phys", arm720t_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa <va>");
-
- register_command(cmd_ctx, arm720t_cmd, "mdw_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory words <physical addr> [count]");
- register_command(cmd_ctx, arm720t_cmd, "mdh_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words <physical addr> [count]");
- register_command(cmd_ctx, arm720t_cmd, "mdb_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes <physical addr> [count]");
-
- register_command(cmd_ctx, arm720t_cmd, "mww_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory word <physical addr> <value>");
- register_command(cmd_ctx, arm720t_cmd, "mwh_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word <physical addr> <value>");
- register_command(cmd_ctx, arm720t_cmd, "mwb_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte <physical addr> <value>");
-
- return ERROR_OK;
-}
-
-int arm720t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- int retval;
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm7tdmi_common_t *arm7tdmi;
- arm720t_common_t *arm720t;
- arm_jtag_t *jtag_info;
-
- if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM720t target");
- return ERROR_OK;
- }
-
- jtag_info = &arm7_9->jtag_info;
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- /* one or more argument, access a single register (write if second argument is given */
- if (argc >= 1)
- {
- u32 opcode = strtoul(args[0], NULL, 0);
-
- if (argc == 1)
- {
- u32 value;
- if ((retval = arm720t_read_cp15(target, opcode, &value)) != ERROR_OK)
- {
- command_print(cmd_ctx, "couldn't access cp15 with opcode 0x%8.8x", opcode);
- return ERROR_OK;
- }
- jtag_execute_queue();
-
- command_print(cmd_ctx, "0x%8.8x: 0x%8.8x", opcode, value);
- }
- else if (argc == 2)
- {
- u32 value = strtoul(args[1], NULL, 0);
- if ((retval = arm720t_write_cp15(target, opcode, value)) != ERROR_OK)
- {
- command_print(cmd_ctx, "couldn't access cp15 with opcode 0x%8.8x", opcode);
- return ERROR_OK;
- }
- command_print(cmd_ctx, "0x%8.8x: 0x%8.8x", opcode, value);
- }
- }
-
- return ERROR_OK;
-}
-
-int arm720t_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm7tdmi_common_t *arm7tdmi;
- arm720t_common_t *arm720t;
- arm_jtag_t *jtag_info;
-
- if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM720t target");
- return ERROR_OK;
- }
-
- jtag_info = &arm7_9->jtag_info;
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu);
-}
-
-int arm720t_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm7tdmi_common_t *arm7tdmi;
- arm720t_common_t *arm720t;
- arm_jtag_t *jtag_info;
-
- if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM720t target");
- return ERROR_OK;
- }
-
- jtag_info = &arm7_9->jtag_info;
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu);
-}
-
-int arm720t_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm7tdmi_common_t *arm7tdmi;
- arm720t_common_t *arm720t;
- arm_jtag_t *jtag_info;
-
- if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM720t target");
- return ERROR_OK;
- }
-
- jtag_info = &arm7_9->jtag_info;
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu);
-}
-
+/*************************************************************************** + * 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 "arm720t.h" +#include "jtag.h" +#include "log.h" + +#include <stdlib.h> +#include <string.h> + +#if 0 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + +/* cli handling */ +int arm720t_register_commands(struct command_context_s *cmd_ctx); + +int arm720t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm720t_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm720t_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm720t_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +/* forward declarations */ +int arm720t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int arm720t_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int arm720t_quit(); +int arm720t_arch_state(struct target_s *target); +int arm720t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int arm720t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int arm720t_soft_reset_halt(struct target_s *target); + +target_type_t arm720t_target = +{ + .name = "arm720t", + + .poll = arm7_9_poll, + .arch_state = arm720t_arch_state, + + .halt = arm7_9_halt, + .resume = arm7_9_resume, + .step = arm7_9_step, + + .assert_reset = arm7_9_assert_reset, + .deassert_reset = arm7_9_deassert_reset, + .soft_reset_halt = arm720t_soft_reset_halt, + .prepare_reset_halt = arm7_9_prepare_reset_halt, + + .get_gdb_reg_list = armv4_5_get_gdb_reg_list, + + .read_memory = arm720t_read_memory, + .write_memory = arm720t_write_memory, + .bulk_write_memory = arm7_9_bulk_write_memory, + .checksum_memory = arm7_9_checksum_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, + .remove_watchpoint = arm7_9_remove_watchpoint, + + .register_commands = arm720t_register_commands, + .target_command = arm720t_target_command, + .init_target = arm720t_init_target, + .quit = arm720t_quit +}; + +int arm720t_scan_cp15(target_t *target, u32 out, u32 *in, int instruction, int clock) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + scan_field_t fields[2]; + u8 out_buf[4]; + u8 instruction_buf = instruction; + + buf_set_u32(out_buf, 0, 32, flip_u32(out, 32)); + + jtag_add_end_state(TAP_PD); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 1; + fields[0].out_value = &instruction_buf; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = out_buf; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + if (in) + { + fields[1].in_handler = arm_jtag_buf_to_u32_flip; + fields[1].in_handler_priv = in; + } else + { + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + } + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + jtag_add_dr_scan(2, fields, -1); + + if (clock) + jtag_add_runtest(0, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + jtag_execute_queue(); + + if (in) + DEBUG("out: %8.8x, in: %8.8x, instruction: %i, clock: %i", out, *in, instruction, clock); + else + DEBUG("out: %8.8x, instruction: %i, clock: %i", out, instruction, clock); +#else + DEBUG("out: %8.8x, instruction: %i, clock: %i", out, instruction, clock); +#endif + + return ERROR_OK; +} + +int arm720t_read_cp15(target_t *target, u32 opcode, u32 *value) +{ + /* fetch CP15 opcode */ + arm720t_scan_cp15(target, opcode, NULL, 1, 1); + /* "DECODE" stage */ + arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1); + /* "EXECUTE" stage (1) */ + arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0); + arm720t_scan_cp15(target, 0x0, NULL, 0, 1); + /* "EXECUTE" stage (2) */ + arm720t_scan_cp15(target, 0x0, NULL, 0, 1); + /* "EXECUTE" stage (3), CDATA is read */ + arm720t_scan_cp15(target, ARMV4_5_NOP, value, 1, 1); + + return ERROR_OK; +} + +int arm720t_write_cp15(target_t *target, u32 opcode, u32 value) +{ + /* fetch CP15 opcode */ + arm720t_scan_cp15(target, opcode, NULL, 1, 1); + /* "DECODE" stage */ + arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1); + /* "EXECUTE" stage (1) */ + arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0); + arm720t_scan_cp15(target, 0x0, NULL, 0, 1); + /* "EXECUTE" stage (2) */ + arm720t_scan_cp15(target, value, NULL, 0, 1); + arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1); + + return ERROR_OK; +} + +u32 arm720t_get_ttb(target_t *target) +{ + u32 ttb = 0x0; + + arm720t_read_cp15(target, 0xee120f10, &ttb); + jtag_execute_queue(); + + ttb &= 0xffffc000; + + return ttb; +} + +void arm720t_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + u32 cp15_control; + + /* read cp15 control register */ + arm720t_read_cp15(target, 0xee110f10, &cp15_control); + jtag_execute_queue(); + + if (mmu) + cp15_control &= ~0x1U; + + if (d_u_cache || i_cache) + cp15_control &= ~0x4U; + + arm720t_write_cp15(target, 0xee010f10, cp15_control); +} + +void arm720t_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + u32 cp15_control; + + /* read cp15 control register */ + arm720t_read_cp15(target, 0xee110f10, &cp15_control); + jtag_execute_queue(); + + if (mmu) + cp15_control |= 0x1U; + + if (d_u_cache || i_cache) + cp15_control |= 0x4U; + + arm720t_write_cp15(target, 0xee010f10, cp15_control); +} + +void arm720t_post_debug_entry(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info; + arm720t_common_t *arm720t = arm7tdmi->arch_info; + + /* examine cp15 control reg */ + arm720t_read_cp15(target, 0xee110f10, &arm720t->cp15_control_reg); + jtag_execute_queue(); + DEBUG("cp15_control_reg: %8.8x", arm720t->cp15_control_reg); + + arm720t->armv4_5_mmu.mmu_enabled = (arm720t->cp15_control_reg & 0x1U) ? 1 : 0; + arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm720t->cp15_control_reg & 0x4U) ? 1 : 0; + arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + + /* save i/d fault status and address register */ + arm720t_read_cp15(target, 0xee150f10, &arm720t->fsr_reg); + arm720t_read_cp15(target, 0xee160f10, &arm720t->far_reg); + jtag_execute_queue(); +} + +void arm720t_pre_restore_context(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info; + arm720t_common_t *arm720t = arm7tdmi->arch_info; + + /* restore i/d fault status and address register */ + arm720t_write_cp15(target, 0xee050f10, arm720t->fsr_reg); + arm720t_write_cp15(target, 0xee060f10, arm720t->far_reg); +} + +int arm720t_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm7tdmi_common_t **arm7tdmi_p, arm720t_common_t **arm720t_p) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9; + arm7tdmi_common_t *arm7tdmi; + arm720t_common_t *arm720t; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + return -1; + } + + arm7_9 = armv4_5->arch_info; + if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC) + { + return -1; + } + + arm7tdmi = arm7_9->arch_info; + if (arm7tdmi->common_magic != ARM7TDMI_COMMON_MAGIC) + { + return -1; + } + + arm720t = arm7tdmi->arch_info; + if (arm720t->common_magic != ARM720T_COMMON_MAGIC) + { + return -1; + } + + *armv4_5_p = armv4_5; + *arm7_9_p = arm7_9; + *arm7tdmi_p = arm7tdmi; + *arm720t_p = arm720t; + + return ERROR_OK; +} + +int arm720t_arch_state(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info; + arm720t_common_t *arm720t = arm7tdmi->arch_info; + + char *state[] = + { + "disabled", "enabled" + }; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + ERROR("BUG: called for a non-ARMv4/5 target"); + exit(-1); + } + + USER("target halted in %s state due to %s, current mode: %s\n" + "cpsr: 0x%8.8x pc: 0x%8.8x\n" + "MMU: %s, Cache: %s", + armv4_5_state_strings[armv4_5->core_state], + target_debug_reason_strings[target->debug_reason], + armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)], + buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), + buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32), + state[arm720t->armv4_5_mmu.mmu_enabled], + state[arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled]); + + return ERROR_OK; +} + +int arm720t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + int retval; + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info; + arm720t_common_t *arm720t = arm7tdmi->arch_info; + + /* disable cache, but leave MMU enabled */ + if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) + arm720t_disable_mmu_caches(target, 0, 1, 0); + + retval = arm7_9_read_memory(target, address, size, count, buffer); + + if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) + arm720t_enable_mmu_caches(target, 0, 1, 0); + + return retval; +} + +int arm720t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + int retval; + + if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK) + return retval; + + return retval; +} + +int arm720t_soft_reset_halt(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info; + arm720t_common_t *arm720t = arm7tdmi->arch_info; + reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; + + if (target->state == TARGET_RUNNING) + { + target->type->halt(target); + } + + while (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) + { + embeddedice_read_reg(dbg_stat); + jtag_execute_queue(); + } + + target->state = TARGET_HALTED; + + /* SVC, ARM state, IRQ and FIQ disabled */ + buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3); + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1; + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1; + + /* start fetching from 0x0 */ + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0); + armv4_5->core_cache->reg_list[15].dirty = 1; + armv4_5->core_cache->reg_list[15].valid = 1; + + armv4_5->core_mode = ARMV4_5_MODE_SVC; + armv4_5->core_state = ARMV4_5_STATE_ARM; + + arm720t_disable_mmu_caches(target, 1, 1, 1); + arm720t->armv4_5_mmu.mmu_enabled = 0; + arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; + arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + + return ERROR_OK; +} + +int arm720t_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + arm7tdmi_init_target(cmd_ctx, target); + + return ERROR_OK; + +} + +int arm720t_quit() +{ + + return ERROR_OK; +} + +int arm720t_init_arch_info(target_t *target, arm720t_common_t *arm720t, int chain_pos, char *variant) +{ + arm7tdmi_common_t *arm7tdmi = &arm720t->arm7tdmi_common; + arm7_9_common_t *arm7_9 = &arm7tdmi->arm7_9_common; + + arm7tdmi_init_arch_info(target, arm7tdmi, chain_pos, variant); + + arm7tdmi->arch_info = arm720t; + arm720t->common_magic = ARM720T_COMMON_MAGIC; + + arm7_9->post_debug_entry = arm720t_post_debug_entry; + arm7_9->pre_restore_context = arm720t_pre_restore_context; + + arm720t->armv4_5_mmu.armv4_5_cache.ctype = -1; + arm720t->armv4_5_mmu.get_ttb = arm720t_get_ttb; + arm720t->armv4_5_mmu.read_memory = arm7_9_read_memory; + arm720t->armv4_5_mmu.write_memory = arm7_9_write_memory; + arm720t->armv4_5_mmu.disable_mmu_caches = arm720t_disable_mmu_caches; + arm720t->armv4_5_mmu.enable_mmu_caches = arm720t_enable_mmu_caches; + arm720t->armv4_5_mmu.has_tiny_pages = 0; + arm720t->armv4_5_mmu.mmu_enabled = 0; + + return ERROR_OK; +} + +int arm720t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + int chain_pos; + char *variant = NULL; + arm720t_common_t *arm720t = malloc(sizeof(arm720t_common_t)); + + if (argc < 4) + { + ERROR("'target arm720t' requires at least one additional argument"); + exit(-1); + } + + chain_pos = strtoul(args[3], NULL, 0); + + if (argc >= 5) + variant = args[4]; + + DEBUG("chain_pos: %i, variant: %s", chain_pos, variant); + + arm720t_init_arch_info(target, arm720t, chain_pos, variant); + + return ERROR_OK; +} + +int arm720t_register_commands(struct command_context_s *cmd_ctx) +{ + int retval; + command_t *arm720t_cmd; + + + retval = arm7tdmi_register_commands(cmd_ctx); + + arm720t_cmd = register_command(cmd_ctx, NULL, "arm720t", NULL, COMMAND_ANY, "arm720t specific commands"); + + register_command(cmd_ctx, arm720t_cmd, "cp15", arm720t_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register <opcode> [value]"); + register_command(cmd_ctx, arm720t_cmd, "virt2phys", arm720t_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa <va>"); + + register_command(cmd_ctx, arm720t_cmd, "mdw_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory words <physical addr> [count]"); + register_command(cmd_ctx, arm720t_cmd, "mdh_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words <physical addr> [count]"); + register_command(cmd_ctx, arm720t_cmd, "mdb_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes <physical addr> [count]"); + + register_command(cmd_ctx, arm720t_cmd, "mww_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory word <physical addr> <value>"); + register_command(cmd_ctx, arm720t_cmd, "mwh_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word <physical addr> <value>"); + register_command(cmd_ctx, arm720t_cmd, "mwb_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte <physical addr> <value>"); + + return ERROR_OK; +} + +int arm720t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm7tdmi_common_t *arm7tdmi; + arm720t_common_t *arm720t; + arm_jtag_t *jtag_info; + + if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM720t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + /* one or more argument, access a single register (write if second argument is given */ + if (argc >= 1) + { + u32 opcode = strtoul(args[0], NULL, 0); + + if (argc == 1) + { + u32 value; + if ((retval = arm720t_read_cp15(target, opcode, &value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access cp15 with opcode 0x%8.8x", opcode); + return ERROR_OK; + } + jtag_execute_queue(); + + command_print(cmd_ctx, "0x%8.8x: 0x%8.8x", opcode, value); + } + else if (argc == 2) + { + u32 value = strtoul(args[1], NULL, 0); + if ((retval = arm720t_write_cp15(target, opcode, value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access cp15 with opcode 0x%8.8x", opcode); + return ERROR_OK; + } + command_print(cmd_ctx, "0x%8.8x: 0x%8.8x", opcode, value); + } + } + + return ERROR_OK; +} + +int arm720t_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm7tdmi_common_t *arm7tdmi; + arm720t_common_t *arm720t; + arm_jtag_t *jtag_info; + + if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM720t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu); +} + +int arm720t_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm7tdmi_common_t *arm7tdmi; + arm720t_common_t *arm720t; + arm_jtag_t *jtag_info; + + if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM720t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu); +} + +int arm720t_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm7tdmi_common_t *arm7tdmi; + arm720t_common_t *arm720t; + arm_jtag_t *jtag_info; + + if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM720t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu); +} + diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index 2a14942..af0205d 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -676,7 +676,7 @@ int arm7_9_handle_target_request(void *priv) return ERROR_OK; } -int arm7_9_poll(target_t *target)
+int arm7_9_poll(target_t *target) { int retval; armv4_5_common_t *armv4_5 = target->arch_info; @@ -692,15 +692,15 @@ int arm7_9_poll(target_t *target) embeddedice_read_reg(dbg_stat); if ((retval = jtag_execute_queue()) != ERROR_OK) { - return retval;
+ return retval; } if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1)) { DEBUG("DBGACK set, dbg_state->value: 0x%x", buf_get_u32(dbg_stat->value, 0, 32)); - if (target->state == TARGET_UNKNOWN)
+ if (target->state == TARGET_UNKNOWN) { - WARNING("DBGACK set while target was in unknown state. Reset or initialize target.");
+ WARNING("DBGACK set while target was in unknown state. Reset or initialize target."); } if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) { @@ -718,18 +718,18 @@ int arm7_9_poll(target_t *target) target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } - if (target->state != TARGET_HALTED)
- {
- WARNING("DBGACK set, but the target did not end up in the halted stated %d", target->state);
+ if (target->state != TARGET_HALTED) + { + WARNING("DBGACK set, but the target did not end up in the halted stated %d", target->state); } - }
+ } else { if (target->state != TARGET_DEBUG_RUNNING) target->state = TARGET_RUNNING; } - return ERROR_OK;
+ return ERROR_OK; } int arm7_9_assert_reset(target_t *target) diff --git a/src/target/arm7tdmi.c b/src/target/arm7tdmi.c index 5679bbc..d8d5e57 100644 --- a/src/target/arm7tdmi.c +++ b/src/target/arm7tdmi.c @@ -1,874 +1,874 @@ -/***************************************************************************
- * 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 "arm7tdmi.h"
-
-#include "arm7_9_common.h"
-#include "register.h"
-#include "target.h"
-#include "armv4_5.h"
-#include "embeddedice.h"
-#include "etm.h"
-#include "log.h"
-#include "jtag.h"
-#include "arm_jtag.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#if 0
-#define _DEBUG_INSTRUCTION_EXECUTION_
-#endif
-
-/* cli handling */
-int arm7tdmi_register_commands(struct command_context_s *cmd_ctx);
-
-/* forward declarations */
-int arm7tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
-int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
-int arm7tdmi_quit();
-
-/* target function declarations */
-int arm7tdmi_poll(struct target_s *target);
-int arm7tdmi_halt(target_t *target);
-
-target_type_t arm7tdmi_target =
-{
- .name = "arm7tdmi",
-
- .poll = arm7_9_poll,
- .arch_state = armv4_5_arch_state,
-
- .target_request_data = arm7_9_target_request_data,
-
- .halt = arm7_9_halt,
- .resume = arm7_9_resume,
- .step = arm7_9_step,
-
- .assert_reset = arm7_9_assert_reset,
- .deassert_reset = arm7_9_deassert_reset,
- .soft_reset_halt = arm7_9_soft_reset_halt,
- .prepare_reset_halt = arm7_9_prepare_reset_halt,
-
- .get_gdb_reg_list = armv4_5_get_gdb_reg_list,
-
- .read_memory = arm7_9_read_memory,
- .write_memory = arm7_9_write_memory,
- .bulk_write_memory = arm7_9_bulk_write_memory,
- .checksum_memory = arm7_9_checksum_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,
- .remove_watchpoint = arm7_9_remove_watchpoint,
-
- .register_commands = arm7tdmi_register_commands,
- .target_command = arm7tdmi_target_command,
- .init_target = arm7tdmi_init_target,
- .quit = arm7tdmi_quit
-};
-
-int arm7tdmi_examine_debug_reason(target_t *target)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
-
- /* only check the debug reason if we don't know it already */
- if ((target->debug_reason != DBG_REASON_DBGRQ)
- && (target->debug_reason != DBG_REASON_SINGLESTEP))
- {
- scan_field_t fields[2];
- u8 databus[4];
- u8 breakpoint;
-
- jtag_add_end_state(TAP_PD);
-
- fields[0].device = arm7_9->jtag_info.chain_pos;
- fields[0].num_bits = 1;
- fields[0].out_value = NULL;
- fields[0].out_mask = NULL;
- fields[0].in_value = &breakpoint;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = arm7_9->jtag_info.chain_pos;
- fields[1].num_bits = 32;
- fields[1].out_value = NULL;
- fields[1].out_mask = NULL;
- fields[1].in_value = databus;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- arm_jtag_scann(&arm7_9->jtag_info, 0x1);
- arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr, NULL);
-
- jtag_add_dr_scan(2, fields, TAP_PD);
- jtag_execute_queue();
-
- fields[0].in_value = NULL;
- fields[0].out_value = &breakpoint;
- fields[1].in_value = NULL;
- fields[1].out_value = databus;
-
- jtag_add_dr_scan(2, fields, TAP_PD);
-
- if (breakpoint & 1)
- target->debug_reason = DBG_REASON_WATCHPOINT;
- else
- target->debug_reason = DBG_REASON_BREAKPOINT;
- }
-
- return ERROR_OK;
-}
-
-/* put an instruction in the ARM7TDMI pipeline or write the data bus, and optionally read data */
-int arm7tdmi_clock_out(arm_jtag_t *jtag_info, u32 out, u32 *in, int breakpoint)
-{
- scan_field_t fields[2];
- u8 out_buf[4];
- u8 breakpoint_buf;
-
- buf_set_u32(out_buf, 0, 32, flip_u32(out, 32));
- buf_set_u32(&breakpoint_buf, 0, 1, breakpoint);
-
- jtag_add_end_state(TAP_PD);
- arm_jtag_scann(jtag_info, 0x1);
- arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 1;
- fields[0].out_value = &breakpoint_buf;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 32;
- fields[1].out_value = out_buf;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- if (in)
- {
- fields[1].in_handler = arm_jtag_buf_to_u32_flip;
- fields[1].in_handler_priv = in;
- }
- else
- {
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
- }
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
-
- jtag_add_dr_scan(2, fields, -1);
-
- jtag_add_runtest(0, -1);
-
-#ifdef _DEBUG_INSTRUCTION_EXECUTION_
-{
- jtag_execute_queue();
-
- if (in)
- {
- DEBUG("out: 0x%8.8x, in: 0x%8.8x", out, *in);
- }
- else
- DEBUG("out: 0x%8.8x", out);
-}
-#endif
-
- return ERROR_OK;
-}
-
-/* clock the target, reading the databus */
-int arm7tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in)
-{
- scan_field_t fields[2];
-
- jtag_add_end_state(TAP_PD);
- arm_jtag_scann(jtag_info, 0x1);
- arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 1;
- fields[0].out_value = NULL;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 32;
- fields[1].out_value = NULL;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_handler = arm_jtag_buf_to_u32_flip;
- fields[1].in_handler_priv = in;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
-
- jtag_add_dr_scan(2, fields, -1);
-
- jtag_add_runtest(0, -1);
-
-#ifdef _DEBUG_INSTRUCTION_EXECUTION_
-{
- jtag_execute_queue();
-
- if (in)
- {
- DEBUG("in: 0x%8.8x", *in);
- }
- else
- {
- ERROR("BUG: called with in == NULL");
- }
-}
-#endif
-
- return ERROR_OK;
-}
-
-/* clock the target, and read the databus
- * the *in pointer points to a buffer where elements of 'size' bytes
- * are stored in big (be==1) or little (be==0) endianness
- */
-int arm7tdmi_clock_data_in_endianness(arm_jtag_t *jtag_info, void *in, int size, int be)
-{
- scan_field_t fields[2];
-
- jtag_add_end_state(TAP_PD);
- arm_jtag_scann(jtag_info, 0x1);
- arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 1;
- fields[0].out_value = NULL;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 32;
- fields[1].out_value = NULL;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- switch (size)
- {
- case 4:
- fields[1].in_handler = (be) ? arm_jtag_buf_to_be32_flip : arm_jtag_buf_to_le32_flip;
- break;
- case 2:
- fields[1].in_handler = (be) ? arm_jtag_buf_to_be16_flip : arm_jtag_buf_to_le16_flip;
- break;
- case 1:
- fields[1].in_handler = arm_jtag_buf_to_8_flip;
- break;
- }
- fields[1].in_handler_priv = in;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
-
- jtag_add_dr_scan(2, fields, -1);
-
- jtag_add_runtest(0, -1);
-
-#ifdef _DEBUG_INSTRUCTION_EXECUTION_
-{
- jtag_execute_queue();
-
- if (in)
- {
- DEBUG("in: 0x%8.8x", *in);
- }
- else
- {
- ERROR("BUG: called with in == NULL");
- }
-}
-#endif
-
- return ERROR_OK;
-}
-
-void arm7tdmi_change_to_arm(target_t *target, u32 *r0, u32 *pc)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* save r0 before using it and put system in ARM state
- * to allow common handling of ARM and THUMB debugging */
-
- /* fetch STR r0, [r0] */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
- /* nothing fetched, STR r0, [r0] in Execute (2) */
- arm7tdmi_clock_data_in(jtag_info, r0);
-
- /* MOV r0, r15 fetched, STR in Decode */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), NULL, 0);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
- /* nothing fetched, STR r0, [r0] in Execute (2) */
- arm7tdmi_clock_data_in(jtag_info, pc);
-
- /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
- /* nothing fetched, data for LDR r0, [PC, #0] */
- arm7tdmi_clock_out(jtag_info, 0x0, NULL, 0);
- /* nothing fetched, data from previous cycle is written to register */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
-
- /* fetch BX */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), NULL, 0);
- /* NOP fetched, BX in Decode, MOV in Execute */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
- /* NOP fetched, BX in Execute (1) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
-
- jtag_execute_queue();
-
- /* fix program counter:
- * MOV r0, r15 was the 4th instruction (+6)
- * reading PC in Thumb state gives address of instruction + 4
- */
- *pc -= 0xa;
-
-}
-
-void arm7tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16])
-{
- int i;
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* STMIA r0-15, [r0] at debug speed
- * register values will start to appear on 4th DCLK
- */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0);
-
- /* fetch NOP, STM in DECODE stage */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* fetch NOP, STM in EXECUTE stage (1st cycle) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
-
- for (i = 0; i <= 15; i++)
- {
- if (mask & (1 << i))
- /* nothing fetched, STM still in EXECUTE (1+i cycle) */
- arm7tdmi_clock_data_in(jtag_info, core_regs[i]);
- }
-
-}
-
-void arm7tdmi_read_core_regs_target_buffer(target_t *target, u32 mask, void* buffer, int size)
-{
- int i;
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
- int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0;
- u32 *buf_u32 = buffer;
- u16 *buf_u16 = buffer;
- u8 *buf_u8 = buffer;
-
- /* STMIA r0-15, [r0] at debug speed
- * register values will start to appear on 4th DCLK
- */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0);
-
- /* fetch NOP, STM in DECODE stage */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* fetch NOP, STM in EXECUTE stage (1st cycle) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
-
- for (i = 0; i <= 15; i++)
- {
- /* nothing fetched, STM still in EXECUTE (1+i cycle), read databus */
- if (mask & (1 << i))
- {
- switch (size)
- {
- case 4:
- arm7tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be);
- break;
- case 2:
- arm7tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be);
- break;
- case 1:
- arm7tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be);
- break;
- }
- }
- }
-
-}
-
-void arm7tdmi_read_xpsr(target_t *target, u32 *xpsr, int spsr)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* MRS r0, cpsr */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), NULL, 0);
-
- /* STR r0, [r15] */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), NULL, 0);
- /* fetch NOP, STR in DECODE stage */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* fetch NOP, STR in EXECUTE stage (1st cycle) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* nothing fetched, STR still in EXECUTE (2nd cycle) */
- arm7tdmi_clock_data_in(jtag_info, xpsr);
-
-}
-
-void arm7tdmi_write_xpsr(target_t *target, u32 xpsr, int spsr)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- DEBUG("xpsr: %8.8x, spsr: %i", xpsr, spsr);
-
- /* MSR1 fetched */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), NULL, 0);
- /* MSR2 fetched, MSR1 in DECODE */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), NULL, 0);
- /* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), NULL, 0);
- /* nothing fetched, MSR1 in EXECUTE (2) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), NULL, 0);
- /* nothing fetched, MSR2 in EXECUTE (2) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* nothing fetched, MSR3 in EXECUTE (2) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* NOP fetched, MSR4 in EXECUTE (1) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* nothing fetched, MSR4 in EXECUTE (2) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
-}
-
-void arm7tdmi_write_xpsr_im8(target_t *target, u8 xpsr_im, int rot, int spsr)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr);
-
- /* MSR fetched */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), NULL, 0);
- /* NOP fetched, MSR in DECODE */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* NOP fetched, MSR in EXECUTE (1) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* nothing fetched, MSR in EXECUTE (2) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
-
-}
-
-void arm7tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16])
-{
- int i;
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* LDMIA r0-15, [r0] at debug speed
- * register values will start to appear on 4th DCLK
- */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), NULL, 0);
-
- /* fetch NOP, LDM in DECODE stage */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* fetch NOP, LDM in EXECUTE stage (1st cycle) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
-
- for (i = 0; i <= 15; i++)
- {
- if (mask & (1 << i))
- /* nothing fetched, LDM still in EXECUTE (1+i cycle) */
- arm7tdmi_clock_out(jtag_info, core_regs[i], NULL, 0);
- }
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
-
-}
-
-void arm7tdmi_load_word_regs(target_t *target, u32 mask)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* put system-speed load-multiple into the pipeline */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), NULL, 0);
-
-}
-
-void arm7tdmi_load_hword_reg(target_t *target, int num)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* put system-speed load half-word into the pipeline */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), NULL, 0);
-
-}
-
-void arm7tdmi_load_byte_reg(target_t *target, int num)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* put system-speed load byte into the pipeline */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), NULL, 0);
-
-}
-
-void arm7tdmi_store_word_regs(target_t *target, u32 mask)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* put system-speed store-multiple into the pipeline */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), NULL, 0);
-
-}
-
-void arm7tdmi_store_hword_reg(target_t *target, int num)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* put system-speed store half-word into the pipeline */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), NULL, 0);
-
-}
-
-void arm7tdmi_store_byte_reg(target_t *target, int num)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* put system-speed store byte into the pipeline */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), NULL, 0);
-
-}
-
-void arm7tdmi_write_pc(target_t *target, u32 pc)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* LDMIA r0-15, [r0] at debug speed
- * register values will start to appear on 4th DCLK
- */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), NULL, 0);
- /* fetch NOP, LDM in DECODE stage */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* fetch NOP, LDM in EXECUTE stage (1st cycle) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* nothing fetched, LDM in EXECUTE stage (1st cycle) load register */
- arm7tdmi_clock_out(jtag_info, pc, NULL, 0);
- /* nothing fetched, LDM in EXECUTE stage (2nd cycle) load register */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* nothing fetched, LDM in EXECUTE stage (3rd cycle) load register */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* fetch NOP, LDM in EXECUTE stage (4th cycle) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* fetch NOP, LDM in EXECUTE stage (5th cycle) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
-}
-
-void arm7tdmi_branch_resume(target_t *target)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffffa, 0), NULL, 0);
-
-}
-
-void arm7tdmi_branch_resume_thumb(target_t *target)
-{
- DEBUG("-");
-
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
- reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
-
- /* LDMIA r0, [r0] at debug speed
- * register values will start to appear on 4th DCLK
- */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), NULL, 0);
-
- /* fetch NOP, LDM in DECODE stage */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* fetch NOP, LDM in EXECUTE stage (1st cycle) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
- /* nothing fetched, LDM in EXECUTE stage (2nd cycle) */
- arm7tdmi_clock_out(jtag_info, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) | 1, NULL, 0);
- /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
-
- /* Branch and eXchange */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_BX(0), NULL, 0);
-
- embeddedice_read_reg(dbg_stat);
-
- /* fetch NOP, BX in DECODE stage */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
-
- /* target is now in Thumb state */
- embeddedice_read_reg(dbg_stat);
-
- /* fetch NOP, BX in EXECUTE stage (1st cycle) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0);
-
- /* target is now in Thumb state */
- embeddedice_read_reg(dbg_stat);
-
- /* load r0 value */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0);
- /* fetch NOP, LDR in Decode */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
- /* fetch NOP, LDR in Execute */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
- /* nothing fetched, LDR in EXECUTE stage (2nd cycle) */
- arm7tdmi_clock_out(jtag_info, buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32), NULL, 0);
- /* nothing fetched, LDR in EXECUTE stage (3rd cycle) */
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
-
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0);
-
- embeddedice_read_reg(dbg_stat);
-
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 1);
- arm7tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f8), NULL, 0);
-
-}
-
-void arm7tdmi_build_reg_cache(target_t *target)
-{
- reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache);
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- (*cache_p) = armv4_5_build_reg_cache(target, armv4_5);
- armv4_5->core_cache = (*cache_p);
-
- (*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9);
- arm7_9->eice_cache = (*cache_p)->next;
-
- if (arm7_9->etm_ctx)
- {
- (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx);
- arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next;
- }
-}
-
-int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
-{
-
- arm7tdmi_build_reg_cache(target);
-
- return ERROR_OK;
-
-}
-
-int arm7tdmi_quit()
-{
-
- return ERROR_OK;
-}
-
-int arm7tdmi_init_arch_info(target_t *target, arm7tdmi_common_t *arm7tdmi, int chain_pos, char *variant)
-{
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
-
- arm7_9 = &arm7tdmi->arm7_9_common;
- armv4_5 = &arm7_9->armv4_5_common;
-
- /* prepare JTAG information for the new target */
- arm7_9->jtag_info.chain_pos = chain_pos;
- arm7_9->jtag_info.scann_size = 4;
-
- /* register arch-specific functions */
- arm7_9->examine_debug_reason = arm7tdmi_examine_debug_reason;
- arm7_9->change_to_arm = arm7tdmi_change_to_arm;
- arm7_9->read_core_regs = arm7tdmi_read_core_regs;
- arm7_9->read_core_regs_target_buffer = arm7tdmi_read_core_regs_target_buffer;
- arm7_9->read_xpsr = arm7tdmi_read_xpsr;
-
- arm7_9->write_xpsr = arm7tdmi_write_xpsr;
- arm7_9->write_xpsr_im8 = arm7tdmi_write_xpsr_im8;
- arm7_9->write_core_regs = arm7tdmi_write_core_regs;
-
- arm7_9->load_word_regs = arm7tdmi_load_word_regs;
- arm7_9->load_hword_reg = arm7tdmi_load_hword_reg;
- arm7_9->load_byte_reg = arm7tdmi_load_byte_reg;
-
- arm7_9->store_word_regs = arm7tdmi_store_word_regs;
- arm7_9->store_hword_reg = arm7tdmi_store_hword_reg;
- arm7_9->store_byte_reg = arm7tdmi_store_byte_reg;
-
- arm7_9->write_pc = arm7tdmi_write_pc;
- arm7_9->branch_resume = arm7tdmi_branch_resume;
- arm7_9->branch_resume_thumb = arm7tdmi_branch_resume_thumb;
-
- arm7_9->enable_single_step = arm7_9_enable_eice_step;
- arm7_9->disable_single_step = arm7_9_disable_eice_step;
-
- arm7_9->pre_debug_entry = NULL;
- arm7_9->post_debug_entry = NULL;
-
- arm7_9->pre_restore_context = NULL;
- arm7_9->post_restore_context = NULL;
-
- /* initialize arch-specific breakpoint handling */
- arm7_9->arm_bkpt = 0xdeeedeee;
- arm7_9->thumb_bkpt = 0xdeee;
-
- arm7_9->sw_bkpts_use_wp = 1;
- arm7_9->sw_bkpts_enabled = 0;
- arm7_9->dbgreq_adjust_pc = 2;
- arm7_9->arch_info = arm7tdmi;
-
- arm7tdmi->arch_info = NULL;
- arm7tdmi->common_magic = ARM7TDMI_COMMON_MAGIC;
-
- if (variant)
- {
- arm7tdmi->variant = strdup(variant);
- }
- else
- {
- arm7tdmi->variant = strdup("");
- }
-
- arm7_9_init_arch_info(target, arm7_9);
-
- return ERROR_OK;
-}
-
-/* target arm7tdmi <endianess> <startup_mode> <chain_pos> <variant> */
-int arm7tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
-{
- int chain_pos;
- char *variant = NULL;
- arm7tdmi_common_t *arm7tdmi = malloc(sizeof(arm7tdmi_common_t));
-
- if (argc < 4)
- {
- ERROR("'target arm7tdmi' requires at least one additional argument");
- exit(-1);
- }
-
- chain_pos = strtoul(args[3], NULL, 0);
-
- if (argc >= 5)
- variant = args[4];
-
- arm7tdmi_init_arch_info(target, arm7tdmi, chain_pos, variant);
-
- return ERROR_OK;
-}
-
-int arm7tdmi_register_commands(struct command_context_s *cmd_ctx)
-{
- int retval;
-
- retval = arm7_9_register_commands(cmd_ctx);
-
- return ERROR_OK;
-
-}
-
+/*************************************************************************** + * 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 "arm7tdmi.h" + +#include "arm7_9_common.h" +#include "register.h" +#include "target.h" +#include "armv4_5.h" +#include "embeddedice.h" +#include "etm.h" +#include "log.h" +#include "jtag.h" +#include "arm_jtag.h" + +#include <stdlib.h> +#include <string.h> + +#if 0 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + +/* cli handling */ +int arm7tdmi_register_commands(struct command_context_s *cmd_ctx); + +/* forward declarations */ +int arm7tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int arm7tdmi_quit(); + +/* target function declarations */ +int arm7tdmi_poll(struct target_s *target); +int arm7tdmi_halt(target_t *target); + +target_type_t arm7tdmi_target = +{ + .name = "arm7tdmi", + + .poll = arm7_9_poll, + .arch_state = armv4_5_arch_state, + + .target_request_data = arm7_9_target_request_data, + + .halt = arm7_9_halt, + .resume = arm7_9_resume, + .step = arm7_9_step, + + .assert_reset = arm7_9_assert_reset, + .deassert_reset = arm7_9_deassert_reset, + .soft_reset_halt = arm7_9_soft_reset_halt, + .prepare_reset_halt = arm7_9_prepare_reset_halt, + + .get_gdb_reg_list = armv4_5_get_gdb_reg_list, + + .read_memory = arm7_9_read_memory, + .write_memory = arm7_9_write_memory, + .bulk_write_memory = arm7_9_bulk_write_memory, + .checksum_memory = arm7_9_checksum_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, + .remove_watchpoint = arm7_9_remove_watchpoint, + + .register_commands = arm7tdmi_register_commands, + .target_command = arm7tdmi_target_command, + .init_target = arm7tdmi_init_target, + .quit = arm7tdmi_quit +}; + +int arm7tdmi_examine_debug_reason(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + + /* only check the debug reason if we don't know it already */ + if ((target->debug_reason != DBG_REASON_DBGRQ) + && (target->debug_reason != DBG_REASON_SINGLESTEP)) + { + scan_field_t fields[2]; + u8 databus[4]; + u8 breakpoint; + + jtag_add_end_state(TAP_PD); + + fields[0].device = arm7_9->jtag_info.chain_pos; + fields[0].num_bits = 1; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = &breakpoint; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = arm7_9->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = databus; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + arm_jtag_scann(&arm7_9->jtag_info, 0x1); + arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr, NULL); + + jtag_add_dr_scan(2, fields, TAP_PD); + jtag_execute_queue(); + + fields[0].in_value = NULL; + fields[0].out_value = &breakpoint; + fields[1].in_value = NULL; + fields[1].out_value = databus; + + jtag_add_dr_scan(2, fields, TAP_PD); + + if (breakpoint & 1) + target->debug_reason = DBG_REASON_WATCHPOINT; + else + target->debug_reason = DBG_REASON_BREAKPOINT; + } + + return ERROR_OK; +} + +/* put an instruction in the ARM7TDMI pipeline or write the data bus, and optionally read data */ +int arm7tdmi_clock_out(arm_jtag_t *jtag_info, u32 out, u32 *in, int breakpoint) +{ + scan_field_t fields[2]; + u8 out_buf[4]; + u8 breakpoint_buf; + + buf_set_u32(out_buf, 0, 32, flip_u32(out, 32)); + buf_set_u32(&breakpoint_buf, 0, 1, breakpoint); + + jtag_add_end_state(TAP_PD); + arm_jtag_scann(jtag_info, 0x1); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 1; + fields[0].out_value = &breakpoint_buf; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = out_buf; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + if (in) + { + fields[1].in_handler = arm_jtag_buf_to_u32_flip; + fields[1].in_handler_priv = in; + } + else + { + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + } + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + jtag_add_dr_scan(2, fields, -1); + + jtag_add_runtest(0, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ +{ + jtag_execute_queue(); + + if (in) + { + DEBUG("out: 0x%8.8x, in: 0x%8.8x", out, *in); + } + else + DEBUG("out: 0x%8.8x", out); +} +#endif + + return ERROR_OK; +} + +/* clock the target, reading the databus */ +int arm7tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in) +{ + scan_field_t fields[2]; + + jtag_add_end_state(TAP_PD); + arm_jtag_scann(jtag_info, 0x1); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 1; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_handler = arm_jtag_buf_to_u32_flip; + fields[1].in_handler_priv = in; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + jtag_add_dr_scan(2, fields, -1); + + jtag_add_runtest(0, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ +{ + jtag_execute_queue(); + + if (in) + { + DEBUG("in: 0x%8.8x", *in); + } + else + { + ERROR("BUG: called with in == NULL"); + } +} +#endif + + return ERROR_OK; +} + +/* clock the target, and read the databus + * the *in pointer points to a buffer where elements of 'size' bytes + * are stored in big (be==1) or little (be==0) endianness + */ +int arm7tdmi_clock_data_in_endianness(arm_jtag_t *jtag_info, void *in, int size, int be) +{ + scan_field_t fields[2]; + + jtag_add_end_state(TAP_PD); + arm_jtag_scann(jtag_info, 0x1); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 1; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + switch (size) + { + case 4: + fields[1].in_handler = (be) ? arm_jtag_buf_to_be32_flip : arm_jtag_buf_to_le32_flip; + break; + case 2: + fields[1].in_handler = (be) ? arm_jtag_buf_to_be16_flip : arm_jtag_buf_to_le16_flip; + break; + case 1: + fields[1].in_handler = arm_jtag_buf_to_8_flip; + break; + } + fields[1].in_handler_priv = in; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + jtag_add_dr_scan(2, fields, -1); + + jtag_add_runtest(0, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ +{ + jtag_execute_queue(); + + if (in) + { + DEBUG("in: 0x%8.8x", *in); + } + else + { + ERROR("BUG: called with in == NULL"); + } +} +#endif + + return ERROR_OK; +} + +void arm7tdmi_change_to_arm(target_t *target, u32 *r0, u32 *pc) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* save r0 before using it and put system in ARM state + * to allow common handling of ARM and THUMB debugging */ + + /* fetch STR r0, [r0] */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + /* nothing fetched, STR r0, [r0] in Execute (2) */ + arm7tdmi_clock_data_in(jtag_info, r0); + + /* MOV r0, r15 fetched, STR in Decode */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + /* nothing fetched, STR r0, [r0] in Execute (2) */ + arm7tdmi_clock_data_in(jtag_info, pc); + + /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + /* nothing fetched, data for LDR r0, [PC, #0] */ + arm7tdmi_clock_out(jtag_info, 0x0, NULL, 0); + /* nothing fetched, data from previous cycle is written to register */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + + /* fetch BX */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), NULL, 0); + /* NOP fetched, BX in Decode, MOV in Execute */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + /* NOP fetched, BX in Execute (1) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + + jtag_execute_queue(); + + /* fix program counter: + * MOV r0, r15 was the 4th instruction (+6) + * reading PC in Thumb state gives address of instruction + 4 + */ + *pc -= 0xa; + +} + +void arm7tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16]) +{ + int i; + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* STMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0); + + /* fetch NOP, STM in DECODE stage */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* fetch NOP, STM in EXECUTE stage (1st cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + + for (i = 0; i <= 15; i++) + { + if (mask & (1 << i)) + /* nothing fetched, STM still in EXECUTE (1+i cycle) */ + arm7tdmi_clock_data_in(jtag_info, core_regs[i]); + } + +} + +void arm7tdmi_read_core_regs_target_buffer(target_t *target, u32 mask, void* buffer, int size) +{ + int i; + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; + u32 *buf_u32 = buffer; + u16 *buf_u16 = buffer; + u8 *buf_u8 = buffer; + + /* STMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0); + + /* fetch NOP, STM in DECODE stage */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* fetch NOP, STM in EXECUTE stage (1st cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + + for (i = 0; i <= 15; i++) + { + /* nothing fetched, STM still in EXECUTE (1+i cycle), read databus */ + if (mask & (1 << i)) + { + switch (size) + { + case 4: + arm7tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); + break; + case 2: + arm7tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); + break; + case 1: + arm7tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); + break; + } + } + } + +} + +void arm7tdmi_read_xpsr(target_t *target, u32 *xpsr, int spsr) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* MRS r0, cpsr */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), NULL, 0); + + /* STR r0, [r15] */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), NULL, 0); + /* fetch NOP, STR in DECODE stage */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* fetch NOP, STR in EXECUTE stage (1st cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* nothing fetched, STR still in EXECUTE (2nd cycle) */ + arm7tdmi_clock_data_in(jtag_info, xpsr); + +} + +void arm7tdmi_write_xpsr(target_t *target, u32 xpsr, int spsr) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + DEBUG("xpsr: %8.8x, spsr: %i", xpsr, spsr); + + /* MSR1 fetched */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), NULL, 0); + /* MSR2 fetched, MSR1 in DECODE */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), NULL, 0); + /* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), NULL, 0); + /* nothing fetched, MSR1 in EXECUTE (2) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), NULL, 0); + /* nothing fetched, MSR2 in EXECUTE (2) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* nothing fetched, MSR3 in EXECUTE (2) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* NOP fetched, MSR4 in EXECUTE (1) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* nothing fetched, MSR4 in EXECUTE (2) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); +} + +void arm7tdmi_write_xpsr_im8(target_t *target, u8 xpsr_im, int rot, int spsr) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr); + + /* MSR fetched */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), NULL, 0); + /* NOP fetched, MSR in DECODE */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* NOP fetched, MSR in EXECUTE (1) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* nothing fetched, MSR in EXECUTE (2) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + +} + +void arm7tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16]) +{ + int i; + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* LDMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), NULL, 0); + + /* fetch NOP, LDM in DECODE stage */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + + for (i = 0; i <= 15; i++) + { + if (mask & (1 << i)) + /* nothing fetched, LDM still in EXECUTE (1+i cycle) */ + arm7tdmi_clock_out(jtag_info, core_regs[i], NULL, 0); + } + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + +} + +void arm7tdmi_load_word_regs(target_t *target, u32 mask) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed load-multiple into the pipeline */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), NULL, 0); + +} + +void arm7tdmi_load_hword_reg(target_t *target, int num) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed load half-word into the pipeline */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), NULL, 0); + +} + +void arm7tdmi_load_byte_reg(target_t *target, int num) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed load byte into the pipeline */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), NULL, 0); + +} + +void arm7tdmi_store_word_regs(target_t *target, u32 mask) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed store-multiple into the pipeline */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), NULL, 0); + +} + +void arm7tdmi_store_hword_reg(target_t *target, int num) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed store half-word into the pipeline */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), NULL, 0); + +} + +void arm7tdmi_store_byte_reg(target_t *target, int num) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed store byte into the pipeline */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), NULL, 0); + +} + +void arm7tdmi_write_pc(target_t *target, u32 pc) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* LDMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), NULL, 0); + /* fetch NOP, LDM in DECODE stage */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (1st cycle) load register */ + arm7tdmi_clock_out(jtag_info, pc, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (2nd cycle) load register */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (3rd cycle) load register */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (4th cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (5th cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); +} + +void arm7tdmi_branch_resume(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffffa, 0), NULL, 0); + +} + +void arm7tdmi_branch_resume_thumb(target_t *target) +{ + DEBUG("-"); + + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; + + /* LDMIA r0, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), NULL, 0); + + /* fetch NOP, LDM in DECODE stage */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (2nd cycle) */ + arm7tdmi_clock_out(jtag_info, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) | 1, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + + /* Branch and eXchange */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_BX(0), NULL, 0); + + embeddedice_read_reg(dbg_stat); + + /* fetch NOP, BX in DECODE stage */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + + /* target is now in Thumb state */ + embeddedice_read_reg(dbg_stat); + + /* fetch NOP, BX in EXECUTE stage (1st cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + + /* target is now in Thumb state */ + embeddedice_read_reg(dbg_stat); + + /* load r0 value */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0); + /* fetch NOP, LDR in Decode */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + /* fetch NOP, LDR in Execute */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + /* nothing fetched, LDR in EXECUTE stage (2nd cycle) */ + arm7tdmi_clock_out(jtag_info, buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32), NULL, 0); + /* nothing fetched, LDR in EXECUTE stage (3rd cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + + embeddedice_read_reg(dbg_stat); + + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f8), NULL, 0); + +} + +void arm7tdmi_build_reg_cache(target_t *target) +{ + reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache); + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + (*cache_p) = armv4_5_build_reg_cache(target, armv4_5); + armv4_5->core_cache = (*cache_p); + + (*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9); + arm7_9->eice_cache = (*cache_p)->next; + + if (arm7_9->etm_ctx) + { + (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx); + arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next; + } +} + +int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + + arm7tdmi_build_reg_cache(target); + + return ERROR_OK; + +} + +int arm7tdmi_quit() +{ + + return ERROR_OK; +} + +int arm7tdmi_init_arch_info(target_t *target, arm7tdmi_common_t *arm7tdmi, int chain_pos, char *variant) +{ + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + + arm7_9 = &arm7tdmi->arm7_9_common; + armv4_5 = &arm7_9->armv4_5_common; + + /* prepare JTAG information for the new target */ + arm7_9->jtag_info.chain_pos = chain_pos; + arm7_9->jtag_info.scann_size = 4; + + /* register arch-specific functions */ + arm7_9->examine_debug_reason = arm7tdmi_examine_debug_reason; + arm7_9->change_to_arm = arm7tdmi_change_to_arm; + arm7_9->read_core_regs = arm7tdmi_read_core_regs; + arm7_9->read_core_regs_target_buffer = arm7tdmi_read_core_regs_target_buffer; + arm7_9->read_xpsr = arm7tdmi_read_xpsr; + + arm7_9->write_xpsr = arm7tdmi_write_xpsr; + arm7_9->write_xpsr_im8 = arm7tdmi_write_xpsr_im8; + arm7_9->write_core_regs = arm7tdmi_write_core_regs; + + arm7_9->load_word_regs = arm7tdmi_load_word_regs; + arm7_9->load_hword_reg = arm7tdmi_load_hword_reg; + arm7_9->load_byte_reg = arm7tdmi_load_byte_reg; + + arm7_9->store_word_regs = arm7tdmi_store_word_regs; + arm7_9->store_hword_reg = arm7tdmi_store_hword_reg; + arm7_9->store_byte_reg = arm7tdmi_store_byte_reg; + + arm7_9->write_pc = arm7tdmi_write_pc; + arm7_9->branch_resume = arm7tdmi_branch_resume; + arm7_9->branch_resume_thumb = arm7tdmi_branch_resume_thumb; + + arm7_9->enable_single_step = arm7_9_enable_eice_step; + arm7_9->disable_single_step = arm7_9_disable_eice_step; + + arm7_9->pre_debug_entry = NULL; + arm7_9->post_debug_entry = NULL; + + arm7_9->pre_restore_context = NULL; + arm7_9->post_restore_context = NULL; + + /* initialize arch-specific breakpoint handling */ + arm7_9->arm_bkpt = 0xdeeedeee; + arm7_9->thumb_bkpt = 0xdeee; + + arm7_9->sw_bkpts_use_wp = 1; + arm7_9->sw_bkpts_enabled = 0; + arm7_9->dbgreq_adjust_pc = 2; + arm7_9->arch_info = arm7tdmi; + + arm7tdmi->arch_info = NULL; + arm7tdmi->common_magic = ARM7TDMI_COMMON_MAGIC; + + if (variant) + { + arm7tdmi->variant = strdup(variant); + } + else + { + arm7tdmi->variant = strdup(""); + } + + arm7_9_init_arch_info(target, arm7_9); + + return ERROR_OK; +} + +/* target arm7tdmi <endianess> <startup_mode> <chain_pos> <variant> */ +int arm7tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + int chain_pos; + char *variant = NULL; + arm7tdmi_common_t *arm7tdmi = malloc(sizeof(arm7tdmi_common_t)); + + if (argc < 4) + { + ERROR("'target arm7tdmi' requires at least one additional argument"); + exit(-1); + } + + chain_pos = strtoul(args[3], NULL, 0); + + if (argc >= 5) + variant = args[4]; + + arm7tdmi_init_arch_info(target, arm7tdmi, chain_pos, variant); + + return ERROR_OK; +} + +int arm7tdmi_register_commands(struct command_context_s *cmd_ctx) +{ + int retval; + + retval = arm7_9_register_commands(cmd_ctx); + + return ERROR_OK; + +} + diff --git a/src/target/arm920t.c b/src/target/arm920t.c index 17c5397..e9a109a 100644 --- a/src/target/arm920t.c +++ b/src/target/arm920t.c @@ -1,1485 +1,1485 @@ -/***************************************************************************
- * 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 "arm920t.h"
-#include "jtag.h"
-#include "log.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#if 0
-#define _DEBUG_INSTRUCTION_EXECUTION_
-#endif
-
-/* cli handling */
-int arm920t_register_commands(struct command_context_s *cmd_ctx);
-
-int arm920t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int arm920t_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int arm920t_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int arm920t_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int arm920t_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int arm920t_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-int arm920t_handle_read_cache_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int arm920t_handle_read_mmu_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-/* forward declarations */
-int arm920t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
-int arm920t_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
-int arm920t_quit();
-int arm920t_arch_state(struct target_s *target);
-int arm920t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
-int arm920t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
-int arm920t_soft_reset_halt(struct target_s *target);
-
-#define ARM920T_CP15_PHYS_ADDR(x, y, z) ((x << 5) | (y << 1) << (z))
-
-target_type_t arm920t_target =
-{
- .name = "arm920t",
-
- .poll = arm7_9_poll,
- .arch_state = arm920t_arch_state,
-
- .target_request_data = arm7_9_target_request_data,
-
- .halt = arm7_9_halt,
- .resume = arm7_9_resume,
- .step = arm7_9_step,
-
- .assert_reset = arm7_9_assert_reset,
- .deassert_reset = arm7_9_deassert_reset,
- .soft_reset_halt = arm920t_soft_reset_halt,
- .prepare_reset_halt = arm7_9_prepare_reset_halt,
-
- .get_gdb_reg_list = armv4_5_get_gdb_reg_list,
-
- .read_memory = arm920t_read_memory,
- .write_memory = arm920t_write_memory,
- .bulk_write_memory = arm7_9_bulk_write_memory,
- .checksum_memory = arm7_9_checksum_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,
- .remove_watchpoint = arm7_9_remove_watchpoint,
-
- .register_commands = arm920t_register_commands,
- .target_command = arm920t_target_command,
- .init_target = arm920t_init_target,
- .quit = arm920t_quit
-};
-
-int arm920t_read_cp15_physical(target_t *target, int reg_addr, u32 *value)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
- scan_field_t fields[4];
- u8 access_type_buf = 1;
- u8 reg_addr_buf = reg_addr & 0x3f;
- u8 nr_w_buf = 0;
-
- jtag_add_end_state(TAP_RTI);
- arm_jtag_scann(jtag_info, 0xf);
- arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 1;
- fields[0].out_value = &access_type_buf;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 32;
- fields[1].out_value = NULL;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = jtag_info->chain_pos;
- fields[2].num_bits = 6;
- fields[2].out_value = ®_addr_buf;
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- fields[3].device = jtag_info->chain_pos;
- fields[3].num_bits = 1;
- fields[3].out_value = &nr_w_buf;
- fields[3].out_mask = NULL;
- fields[3].in_value = NULL;
- fields[3].in_check_value = NULL;
- fields[3].in_check_mask = NULL;
- fields[3].in_handler = NULL;
- fields[3].in_handler_priv = NULL;
-
- jtag_add_dr_scan(4, fields, -1);
-
- fields[1].in_handler_priv = value;
- fields[1].in_handler = arm_jtag_buf_to_u32;
-
- jtag_add_dr_scan(4, fields, -1);
-
-#ifdef _DEBUG_INSTRUCTION_EXECUTION_
- jtag_execute_queue();
- DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value);
-#endif
-
- return ERROR_OK;
-}
-
-int arm920t_write_cp15_physical(target_t *target, int reg_addr, u32 value)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
- scan_field_t fields[4];
- u8 access_type_buf = 1;
- u8 reg_addr_buf = reg_addr & 0x3f;
- u8 nr_w_buf = 1;
- u8 value_buf[4];
-
- buf_set_u32(value_buf, 0, 32, value);
-
- jtag_add_end_state(TAP_RTI);
- arm_jtag_scann(jtag_info, 0xf);
- arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 1;
- fields[0].out_value = &access_type_buf;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 32;
- fields[1].out_value = value_buf;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = jtag_info->chain_pos;
- fields[2].num_bits = 6;
- fields[2].out_value = ®_addr_buf;
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- fields[3].device = jtag_info->chain_pos;
- fields[3].num_bits = 1;
- fields[3].out_value = &nr_w_buf;
- fields[3].out_mask = NULL;
- fields[3].in_value = NULL;
- fields[3].in_check_value = NULL;
- fields[3].in_check_mask = NULL;
- fields[3].in_handler = NULL;
- fields[3].in_handler_priv = NULL;
-
- jtag_add_dr_scan(4, fields, -1);
-
-#ifdef _DEBUG_INSTRUCTION_EXECUTION_
- DEBUG("addr: 0x%x value: %8.8x", reg_addr, value);
-#endif
-
- return ERROR_OK;
-}
-
-int arm920t_execute_cp15(target_t *target, u32 cp15_opcode, u32 arm_opcode)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
- scan_field_t fields[4];
- u8 access_type_buf = 0; /* interpreted access */
- u8 reg_addr_buf = 0x0;
- u8 nr_w_buf = 0;
- u8 cp15_opcode_buf[4];
-
- jtag_add_end_state(TAP_RTI);
- arm_jtag_scann(jtag_info, 0xf);
- arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
-
- buf_set_u32(cp15_opcode_buf, 0, 32, cp15_opcode);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 1;
- fields[0].out_value = &access_type_buf;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 32;
- fields[1].out_value = cp15_opcode_buf;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = jtag_info->chain_pos;
- fields[2].num_bits = 6;
- fields[2].out_value = ®_addr_buf;
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- fields[3].device = jtag_info->chain_pos;
- fields[3].num_bits = 1;
- fields[3].out_value = &nr_w_buf;
- fields[3].out_mask = NULL;
- fields[3].in_value = NULL;
- fields[3].in_check_value = NULL;
- fields[3].in_check_mask = NULL;
- fields[3].in_handler = NULL;
- fields[3].in_handler_priv = NULL;
-
- jtag_add_dr_scan(4, fields, -1);
-
- arm9tdmi_clock_out(jtag_info, arm_opcode, 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
- arm7_9_execute_sys_speed(target);
-
- if (jtag_execute_queue() != ERROR_OK)
- {
- ERROR("failed executing JTAG queue, exiting");
- exit(-1);
- }
-
- return ERROR_OK;
-}
-
-int arm920t_read_cp15_interpreted(target_t *target, u32 cp15_opcode, u32 address, u32 *value)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- u32* regs_p[1];
- u32 regs[2];
- u32 cp15c15 = 0x0;
-
- /* load address into R1 */
- regs[1] = address;
- arm9tdmi_write_core_regs(target, 0x2, regs);
-
- /* read-modify-write CP15 test state register
- * to enable interpreted access mode */
- arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
- jtag_execute_queue();
- cp15c15 |= 1; /* set interpret mode */
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
-
- /* execute CP15 instruction and ARM load (reading from coprocessor) */
- arm920t_execute_cp15(target, cp15_opcode, ARMV4_5_LDR(0, 1));
-
- /* disable interpreted access mode */
- cp15c15 &= ~1U; /* clear interpret mode */
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
-
- /* retrieve value from R0 */
- regs_p[0] = value;
- arm9tdmi_read_core_regs(target, 0x1, regs_p);
- jtag_execute_queue();
-
-#ifdef _DEBUG_INSTRUCTION_EXECUTION_
- DEBUG("cp15_opcode: %8.8x, address: %8.8x, value: %8.8x", cp15_opcode, address, *value);
-#endif
-
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = 1;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = 1;
-
- return ERROR_OK;
-}
-
-int arm920t_write_cp15_interpreted(target_t *target, u32 cp15_opcode, u32 value, u32 address)
-{
- u32 cp15c15 = 0x0;
- armv4_5_common_t *armv4_5 = target->arch_info;
- u32 regs[2];
-
- /* load value, address into R0, R1 */
- regs[0] = value;
- regs[1] = address;
- arm9tdmi_write_core_regs(target, 0x3, regs);
-
- /* read-modify-write CP15 test state register
- * to enable interpreted access mode */
- arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
- jtag_execute_queue();
- cp15c15 |= 1; /* set interpret mode */
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
-
- /* execute CP15 instruction and ARM store (writing to coprocessor) */
- arm920t_execute_cp15(target, cp15_opcode, ARMV4_5_STR(0, 1));
-
- /* disable interpreted access mode */
- cp15c15 &= ~1U; /* set interpret mode */
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
-
-#ifdef _DEBUG_INSTRUCTION_EXECUTION_
- DEBUG("cp15_opcode: %8.8x, value: %8.8x, address: %8.8x", cp15_opcode, value, address);
-#endif
-
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = 1;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = 1;
-
- return ERROR_OK;
-}
-
-u32 arm920t_get_ttb(target_t *target)
-{
- int retval;
- u32 ttb = 0x0;
-
- if ((retval = arm920t_read_cp15_interpreted(target, 0xeebf0f51, 0x0, &ttb)) != ERROR_OK)
- return retval;
-
- return ttb;
-}
-
-void arm920t_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
-{
- u32 cp15_control;
-
- /* read cp15 control register */
- arm920t_read_cp15_physical(target, 0x2, &cp15_control);
- jtag_execute_queue();
-
- if (mmu)
- cp15_control &= ~0x1U;
-
- if (d_u_cache)
- cp15_control &= ~0x4U;
-
- if (i_cache)
- cp15_control &= ~0x1000U;
-
- arm920t_write_cp15_physical(target, 0x2, cp15_control);
-}
-
-void arm920t_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
-{
- u32 cp15_control;
-
- /* read cp15 control register */
- arm920t_read_cp15_physical(target, 0x2, &cp15_control);
- jtag_execute_queue();
-
- if (mmu)
- cp15_control |= 0x1U;
-
- if (d_u_cache)
- cp15_control |= 0x4U;
-
- if (i_cache)
- cp15_control |= 0x1000U;
-
- arm920t_write_cp15_physical(target, 0x2, cp15_control);
-}
-
-void arm920t_post_debug_entry(target_t *target)
-{
- u32 cp15c15;
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
- arm920t_common_t *arm920t = arm9tdmi->arch_info;
-
- /* examine cp15 control reg */
- arm920t_read_cp15_physical(target, 0x2, &arm920t->cp15_control_reg);
- jtag_execute_queue();
- DEBUG("cp15_control_reg: %8.8x", arm920t->cp15_control_reg);
-
- if (arm920t->armv4_5_mmu.armv4_5_cache.ctype == -1)
- {
- u32 cache_type_reg;
- /* identify caches */
- arm920t_read_cp15_physical(target, 0x1, &cache_type_reg);
- jtag_execute_queue();
- armv4_5_identify_cache(cache_type_reg, &arm920t->armv4_5_mmu.armv4_5_cache);
- }
-
- arm920t->armv4_5_mmu.mmu_enabled = (arm920t->cp15_control_reg & 0x1U) ? 1 : 0;
- arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm920t->cp15_control_reg & 0x4U) ? 1 : 0;
- arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm920t->cp15_control_reg & 0x1000U) ? 1 : 0;
-
- /* save i/d fault status and address register */
- arm920t_read_cp15_interpreted(target, 0xee150f10, 0x0, &arm920t->d_fsr);
- arm920t_read_cp15_interpreted(target, 0xee150f30, 0x0, &arm920t->i_fsr);
- arm920t_read_cp15_interpreted(target, 0xee160f10, 0x0, &arm920t->d_far);
- arm920t_read_cp15_interpreted(target, 0xee160f30, 0x0, &arm920t->i_far);
-
- DEBUG("D FSR: 0x%8.8x, D FAR: 0x%8.8x, I FSR: 0x%8.8x, I FAR: 0x%8.8x",
- arm920t->d_fsr, arm920t->d_far, arm920t->i_fsr, arm920t->i_far);
-
- if (arm920t->preserve_cache)
- {
- /* read-modify-write CP15 test state register
- * to disable I/D-cache linefills */
- arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
- jtag_execute_queue();
- cp15c15 |= 0x600;
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
- }
-}
-
-void arm920t_pre_restore_context(target_t *target)
-{
- u32 cp15c15;
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
- arm920t_common_t *arm920t = arm9tdmi->arch_info;
-
- /* restore i/d fault status and address register */
- arm920t_write_cp15_interpreted(target, 0xee050f10, arm920t->d_fsr, 0x0);
- arm920t_write_cp15_interpreted(target, 0xee050f30, arm920t->i_fsr, 0x0);
- arm920t_write_cp15_interpreted(target, 0xee060f10, arm920t->d_far, 0x0);
- arm920t_write_cp15_interpreted(target, 0xee060f30, arm920t->i_far, 0x0);
-
- /* read-modify-write CP15 test state register
- * to reenable I/D-cache linefills */
- if (arm920t->preserve_cache)
- {
- arm920t_read_cp15_physical(target, 0x1e, &cp15c15);
- jtag_execute_queue();
- cp15c15 &= ~0x600U;
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
- }
-}
-
-int arm920t_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p, arm920t_common_t **arm920t_p)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm920t_common_t *arm920t;
-
- if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
- {
- return -1;
- }
-
- arm7_9 = armv4_5->arch_info;
- if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC)
- {
- return -1;
- }
-
- arm9tdmi = arm7_9->arch_info;
- if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC)
- {
- return -1;
- }
-
- arm920t = arm9tdmi->arch_info;
- if (arm920t->common_magic != ARM920T_COMMON_MAGIC)
- {
- return -1;
- }
-
- *armv4_5_p = armv4_5;
- *arm7_9_p = arm7_9;
- *arm9tdmi_p = arm9tdmi;
- *arm920t_p = arm920t;
-
- return ERROR_OK;
-}
-
-int arm920t_arch_state(struct target_s *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
- arm920t_common_t *arm920t = arm9tdmi->arch_info;
-
- char *state[] =
- {
- "disabled", "enabled"
- };
-
- if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
- {
- ERROR("BUG: called for a non-ARMv4/5 target");
- exit(-1);
- }
-
- USER( "target halted in %s state due to %s, current mode: %s\n"
- "cpsr: 0x%8.8x pc: 0x%8.8x\n"
- "MMU: %s, D-Cache: %s, I-Cache: %s",
- armv4_5_state_strings[armv4_5->core_state],
- target_debug_reason_strings[target->debug_reason],
- armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)],
- buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
- buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32),
- state[arm920t->armv4_5_mmu.mmu_enabled],
- state[arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled],
- state[arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled]);
-
- return ERROR_OK;
-}
-
-int arm920t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
-{
- int retval;
-
- retval = arm7_9_read_memory(target, address, size, count, buffer);
-
- return retval;
-}
-
-int arm920t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
-{
- int retval;
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
- arm920t_common_t *arm920t = arm9tdmi->arch_info;
-
- if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK)
- return retval;
-
- if (((size == 4) || (size == 2)) && (count == 1))
- {
- if (arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled)
- {
- DEBUG("D-Cache enabled, writing through to main memory");
- u32 pa, cb, ap;
- int type, domain;
-
- pa = armv4_5_mmu_translate_va(target, &arm920t->armv4_5_mmu, address, &type, &cb, &domain, &ap);
- if (type == -1)
- return ERROR_OK;
- /* cacheable & bufferable means write-back region */
- if (cb == 3)
- armv4_5_mmu_write_physical(target, &arm920t->armv4_5_mmu, pa, size, count, buffer);
- }
-
- if (arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled)
- {
- DEBUG("I-Cache enabled, invalidating affected I-Cache line");
- arm920t_write_cp15_interpreted(target, 0xee070f35, 0x0, address);
- }
- }
-
- return retval;
-}
-
-int arm920t_soft_reset_halt(struct target_s *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
- arm920t_common_t *arm920t = arm9tdmi->arch_info;
- reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
-
- if (target->state == TARGET_RUNNING)
- {
- target->type->halt(target);
- }
-
- while (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0)
- {
- embeddedice_read_reg(dbg_stat);
- jtag_execute_queue();
- }
-
- target->state = TARGET_HALTED;
-
- /* SVC, ARM state, IRQ and FIQ disabled */
- buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3);
- armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
- armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
-
- /* start fetching from 0x0 */
- buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0);
- armv4_5->core_cache->reg_list[15].dirty = 1;
- armv4_5->core_cache->reg_list[15].valid = 1;
-
- armv4_5->core_mode = ARMV4_5_MODE_SVC;
- armv4_5->core_state = ARMV4_5_STATE_ARM;
-
- arm920t_disable_mmu_caches(target, 1, 1, 1);
- arm920t->armv4_5_mmu.mmu_enabled = 0;
- arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0;
- arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
-
- target_call_event_callbacks(target, TARGET_EVENT_HALTED);
-
- return ERROR_OK;
-}
-
-int arm920t_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
-{
- arm9tdmi_init_target(cmd_ctx, target);
-
- return ERROR_OK;
-
-}
-
-int arm920t_quit()
-{
-
- return ERROR_OK;
-}
-
-int arm920t_init_arch_info(target_t *target, arm920t_common_t *arm920t, int chain_pos, char *variant)
-{
- arm9tdmi_common_t *arm9tdmi = &arm920t->arm9tdmi_common;
- arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common;
-
- /* initialize arm9tdmi specific info (including arm7_9 and armv4_5)
- */
- arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant);
-
- arm9tdmi->arch_info = arm920t;
- arm920t->common_magic = ARM920T_COMMON_MAGIC;
-
- arm7_9->post_debug_entry = arm920t_post_debug_entry;
- arm7_9->pre_restore_context = arm920t_pre_restore_context;
-
- arm920t->armv4_5_mmu.armv4_5_cache.ctype = -1;
- arm920t->armv4_5_mmu.get_ttb = arm920t_get_ttb;
- arm920t->armv4_5_mmu.read_memory = arm7_9_read_memory;
- arm920t->armv4_5_mmu.write_memory = arm7_9_write_memory;
- arm920t->armv4_5_mmu.disable_mmu_caches = arm920t_disable_mmu_caches;
- arm920t->armv4_5_mmu.enable_mmu_caches = arm920t_enable_mmu_caches;
- arm920t->armv4_5_mmu.has_tiny_pages = 1;
- arm920t->armv4_5_mmu.mmu_enabled = 0;
-
- /* disabling linefills leads to lockups, so keep them enabled for now
- * this doesn't affect correctness, but might affect timing issues, if
- * important data is evicted from the cache during the debug session
- * */
- arm920t->preserve_cache = 0;
-
- /* override hw single-step capability from ARM9TDMI */
- arm7_9->has_single_step = 1;
-
- return ERROR_OK;
-}
-
-int arm920t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
-{
- int chain_pos;
- char *variant = NULL;
- arm920t_common_t *arm920t = malloc(sizeof(arm920t_common_t));
-
- if (argc < 4)
- {
- ERROR("'target arm920t' requires at least one additional argument");
- exit(-1);
- }
-
- chain_pos = strtoul(args[3], NULL, 0);
-
- if (argc >= 5)
- variant = args[4];
-
- DEBUG("chain_pos: %i, variant: %s", chain_pos, variant);
-
- arm920t_init_arch_info(target, arm920t, chain_pos, variant);
-
- return ERROR_OK;
-}
-
-int arm920t_register_commands(struct command_context_s *cmd_ctx)
-{
- int retval;
- command_t *arm920t_cmd;
-
-
- retval = arm9tdmi_register_commands(cmd_ctx);
-
- arm920t_cmd = register_command(cmd_ctx, NULL, "arm920t", NULL, COMMAND_ANY, "arm920t specific commands");
-
- register_command(cmd_ctx, arm920t_cmd, "cp15", arm920t_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register <num> [value]");
- register_command(cmd_ctx, arm920t_cmd, "cp15i", arm920t_handle_cp15i_command, COMMAND_EXEC, "display/modify cp15 (interpreted access) <opcode> [value] [address]");
- register_command(cmd_ctx, arm920t_cmd, "cache_info", arm920t_handle_cache_info_command, COMMAND_EXEC, "display information about target caches");
- register_command(cmd_ctx, arm920t_cmd, "virt2phys", arm920t_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa <va>");
-
- register_command(cmd_ctx, arm920t_cmd, "mdw_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory words <physical addr> [count]");
- register_command(cmd_ctx, arm920t_cmd, "mdh_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words <physical addr> [count]");
- register_command(cmd_ctx, arm920t_cmd, "mdb_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes <physical addr> [count]");
-
- register_command(cmd_ctx, arm920t_cmd, "mww_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory word <physical addr> <value>");
- register_command(cmd_ctx, arm920t_cmd, "mwh_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word <physical addr> <value>");
- register_command(cmd_ctx, arm920t_cmd, "mwb_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte <physical addr> <value>");
-
- register_command(cmd_ctx, arm920t_cmd, "read_cache", arm920t_handle_read_cache_command, COMMAND_EXEC, "display I/D cache content");
- register_command(cmd_ctx, arm920t_cmd, "read_mmu", arm920t_handle_read_mmu_command, COMMAND_EXEC, "display I/D mmu content");
-
- return ERROR_OK;
-}
-
-int arm920t_handle_read_cache_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm920t_common_t *arm920t;
- arm_jtag_t *jtag_info;
- u32 cp15c15;
- u32 cp15_ctrl, cp15_ctrl_saved;
- u32 regs[16];
- u32 *regs_p[16];
- u32 C15_C_D_Ind, C15_C_I_Ind;
- int i;
- FILE *output;
- arm920t_cache_line_t d_cache[8][64], i_cache[8][64];
- int segment, index;
-
- if (argc != 1)
- {
- command_print(cmd_ctx, "usage: arm920t read_cache <filename>");
- return ERROR_OK;
- }
-
- if ((output = fopen(args[0], "w")) == NULL)
- {
- DEBUG("error opening cache content file");
- return ERROR_OK;
- }
-
- for (i = 0; i < 16; i++)
- regs_p[i] = ®s[i];
-
- if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM920t target");
- return ERROR_OK;
- }
-
- jtag_info = &arm7_9->jtag_info;
-
- /* disable MMU and Caches */
- arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), &cp15_ctrl);
- jtag_execute_queue();
- cp15_ctrl_saved = cp15_ctrl;
- cp15_ctrl &= ~(ARMV4_5_MMU_ENABLED | ARMV4_5_D_U_CACHE_ENABLED | ARMV4_5_I_CACHE_ENABLED);
- arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl);
-
- /* read CP15 test state register */
- arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), &cp15c15);
- jtag_execute_queue();
-
- /* read DCache content */
- fprintf(output, "DCache:\n");
-
- /* go through segments 0 to nsets (8 on ARM920T, 4 on ARM922T) */
- for (segment = 0; segment < arm920t->armv4_5_mmu.armv4_5_cache.d_u_size.nsets; segment++)
- {
- fprintf(output, "\nsegment: %i\n----------", segment);
-
- /* Ra: r0 = SBZ(31:8):segment(7:5):SBZ(4:0) */
- regs[0] = 0x0 | (segment << 5);
- arm9tdmi_write_core_regs(target, 0x1, regs);
-
- /* set interpret mode */
- cp15c15 |= 0x1;
- arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15);
-
- /* D CAM Read, loads current victim into C15.C.D.Ind */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,6,2), ARMV4_5_LDR(1, 0));
-
- /* read current victim */
- arm920t_read_cp15_physical(target, 0x3d, &C15_C_D_Ind);
-
- /* clear interpret mode */
- cp15c15 &= ~0x1;
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
-
- for (index = 0; index < 64; index++)
- {
- /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */
- regs[0] = 0x0 | (segment << 5) | (index << 26);
- arm9tdmi_write_core_regs(target, 0x1, regs);
-
- /* set interpret mode */
- cp15c15 |= 0x1;
- arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15);
-
- /* Write DCache victim */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,0), ARMV4_5_LDR(1, 0));
-
- /* Read D RAM */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,10,2), ARMV4_5_LDMIA(0, 0x1fe, 0, 0));
-
- /* Read D CAM */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,6,2), ARMV4_5_LDR(9, 0));
-
- /* clear interpret mode */
- cp15c15 &= ~0x1;
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
-
- /* read D RAM and CAM content */
- arm9tdmi_read_core_regs(target, 0x3fe, regs_p);
- jtag_execute_queue();
-
- d_cache[segment][index].cam = regs[9];
-
- /* mask LFSR[6] */
- regs[9] &= 0xfffffffe;
- fprintf(output, "\nsegment: %i, index: %i, CAM: 0x%8.8x, content (%s):\n", segment, index, regs[9], (regs[9] & 0x10) ? "valid" : "invalid");
-
- for (i = 1; i < 9; i++)
- {
- d_cache[segment][index].data[i] = regs[i];
- fprintf(output, "%i: 0x%8.8x\n", i-1, regs[i]);
- }
-
- }
-
- /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */
- regs[0] = 0x0 | (segment << 5) | (C15_C_D_Ind << 26);
- arm9tdmi_write_core_regs(target, 0x1, regs);
-
- /* set interpret mode */
- cp15c15 |= 0x1;
- arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15);
-
- /* Write DCache victim */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,0), ARMV4_5_LDR(1, 0));
-
- /* clear interpret mode */
- cp15c15 &= ~0x1;
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
- }
-
- /* read ICache content */
- fprintf(output, "ICache:\n");
-
- /* go through segments 0 to nsets (8 on ARM920T, 4 on ARM922T) */
- for (segment = 0; segment < arm920t->armv4_5_mmu.armv4_5_cache.d_u_size.nsets; segment++)
- {
- fprintf(output, "segment: %i\n----------", segment);
-
- /* Ra: r0 = SBZ(31:8):segment(7:5):SBZ(4:0) */
- regs[0] = 0x0 | (segment << 5);
- arm9tdmi_write_core_regs(target, 0x1, regs);
-
- /* set interpret mode */
- cp15c15 |= 0x1;
- arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15);
-
- /* I CAM Read, loads current victim into C15.C.I.Ind */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,5,2), ARMV4_5_LDR(1, 0));
-
- /* read current victim */
- arm920t_read_cp15_physical(target, 0x3b, &C15_C_I_Ind);
-
- /* clear interpret mode */
- cp15c15 &= ~0x1;
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
-
- for (index = 0; index < 64; index++)
- {
- /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */
- regs[0] = 0x0 | (segment << 5) | (index << 26);
- arm9tdmi_write_core_regs(target, 0x1, regs);
-
- /* set interpret mode */
- cp15c15 |= 0x1;
- arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15);
-
- /* Write ICache victim */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,1), ARMV4_5_LDR(1, 0));
-
- /* Read I RAM */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,9,2), ARMV4_5_LDMIA(0, 0x1fe, 0, 0));
-
- /* Read I CAM */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,5,2), ARMV4_5_LDR(9, 0));
-
- /* clear interpret mode */
- cp15c15 &= ~0x1;
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
-
- /* read I RAM and CAM content */
- arm9tdmi_read_core_regs(target, 0x3fe, regs_p);
- jtag_execute_queue();
-
- i_cache[segment][index].cam = regs[9];
-
- /* mask LFSR[6] */
- regs[9] &= 0xfffffffe;
- fprintf(output, "\nsegment: %i, index: %i, CAM: 0x%8.8x, content (%s):\n", segment, index, regs[9], (regs[9] & 0x10) ? "valid" : "invalid");
-
- for (i = 1; i < 9; i++)
- {
- i_cache[segment][index].data[i] = regs[i];
- fprintf(output, "%i: 0x%8.8x\n", i-1, regs[i]);
- }
-
- }
-
-
- /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */
- regs[0] = 0x0 | (segment << 5) | (C15_C_D_Ind << 26);
- arm9tdmi_write_core_regs(target, 0x1, regs);
-
- /* set interpret mode */
- cp15c15 |= 0x1;
- arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15);
-
- /* Write ICache victim */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,1), ARMV4_5_LDR(1, 0));
-
- /* clear interpret mode */
- cp15c15 &= ~0x1;
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
- }
-
- /* restore CP15 MMU and Cache settings */
- arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl_saved);
-
- command_print(cmd_ctx, "cache content successfully output to %s", args[0]);
-
- fclose(output);
-
- /* mark registers dirty. */
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).valid;
-
- return ERROR_OK;
-}
-
-int arm920t_handle_read_mmu_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm920t_common_t *arm920t;
- arm_jtag_t *jtag_info;
- u32 cp15c15;
- u32 cp15_ctrl, cp15_ctrl_saved;
- u32 regs[16];
- u32 *regs_p[16];
- int i;
- FILE *output;
- u32 Dlockdown, Ilockdown;
- arm920t_tlb_entry_t d_tlb[64], i_tlb[64];
- int victim;
-
- if (argc != 1)
- {
- command_print(cmd_ctx, "usage: arm920t read_mmu <filename>");
- return ERROR_OK;
- }
-
- if ((output = fopen(args[0], "w")) == NULL)
- {
- DEBUG("error opening mmu content file");
- return ERROR_OK;
- }
-
- for (i = 0; i < 16; i++)
- regs_p[i] = ®s[i];
-
- if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM920t target");
- return ERROR_OK;
- }
-
- jtag_info = &arm7_9->jtag_info;
-
- /* disable MMU and Caches */
- arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), &cp15_ctrl);
- jtag_execute_queue();
- cp15_ctrl_saved = cp15_ctrl;
- cp15_ctrl &= ~(ARMV4_5_MMU_ENABLED | ARMV4_5_D_U_CACHE_ENABLED | ARMV4_5_I_CACHE_ENABLED);
- arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl);
-
- /* read CP15 test state register */
- arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), &cp15c15);
- jtag_execute_queue();
-
- /* prepare reading D TLB content
- * */
-
- /* set interpret mode */
- cp15c15 |= 0x1;
- arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15);
-
- /* Read D TLB lockdown */
- arm920t_execute_cp15(target, ARMV4_5_MRC(15,0,0,10,0,0), ARMV4_5_LDR(1, 0));
-
- /* clear interpret mode */
- cp15c15 &= ~0x1;
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
-
- /* read D TLB lockdown stored to r1 */
- arm9tdmi_read_core_regs(target, 0x2, regs_p);
- jtag_execute_queue();
- Dlockdown = regs[1];
-
- for (victim = 0; victim < 64; victim += 8)
- {
- /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0]
- * base remains unchanged, victim goes through entries 0 to 63 */
- regs[1] = (Dlockdown & 0xfc000000) | (victim << 20);
- arm9tdmi_write_core_regs(target, 0x2, regs);
-
- /* set interpret mode */
- cp15c15 |= 0x1;
- arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15);
-
- /* Write D TLB lockdown */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0));
-
- /* Read D TLB CAM */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,6,4), ARMV4_5_LDMIA(0, 0x3fc, 0, 0));
-
- /* clear interpret mode */
- cp15c15 &= ~0x1;
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
-
- /* read D TLB CAM content stored to r2-r9 */
- arm9tdmi_read_core_regs(target, 0x3fc, regs_p);
- jtag_execute_queue();
-
- for (i = 0; i < 8; i++)
- d_tlb[victim + i].cam = regs[i + 2];
- }
-
- for (victim = 0; victim < 64; victim++)
- {
- /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0]
- * base remains unchanged, victim goes through entries 0 to 63 */
- regs[1] = (Dlockdown & 0xfc000000) | (victim << 20);
- arm9tdmi_write_core_regs(target, 0x2, regs);
-
- /* set interpret mode */
- cp15c15 |= 0x1;
- arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15);
-
- /* Write D TLB lockdown */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0));
-
- /* Read D TLB RAM1 */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,10,4), ARMV4_5_LDR(2,0));
-
- /* Read D TLB RAM2 */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,2,5), ARMV4_5_LDR(3,0));
-
- /* clear interpret mode */
- cp15c15 &= ~0x1;
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
-
- /* read D TLB RAM content stored to r2 and r3 */
- arm9tdmi_read_core_regs(target, 0xc, regs_p);
- jtag_execute_queue();
-
- d_tlb[victim].ram1 = regs[2];
- d_tlb[victim].ram2 = regs[3];
- }
-
- /* restore D TLB lockdown */
- regs[1] = Dlockdown;
- arm9tdmi_write_core_regs(target, 0x2, regs);
-
- /* Write D TLB lockdown */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0));
-
- /* prepare reading I TLB content
- * */
-
- /* set interpret mode */
- cp15c15 |= 0x1;
- arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15);
-
- /* Read I TLB lockdown */
- arm920t_execute_cp15(target, ARMV4_5_MRC(15,0,0,10,0,1), ARMV4_5_LDR(1, 0));
-
- /* clear interpret mode */
- cp15c15 &= ~0x1;
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
-
- /* read I TLB lockdown stored to r1 */
- arm9tdmi_read_core_regs(target, 0x2, regs_p);
- jtag_execute_queue();
- Ilockdown = regs[1];
-
- for (victim = 0; victim < 64; victim += 8)
- {
- /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0]
- * base remains unchanged, victim goes through entries 0 to 63 */
- regs[1] = (Ilockdown & 0xfc000000) | (victim << 20);
- arm9tdmi_write_core_regs(target, 0x2, regs);
-
- /* set interpret mode */
- cp15c15 |= 0x1;
- arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15);
-
- /* Write I TLB lockdown */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0));
-
- /* Read I TLB CAM */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,5,4), ARMV4_5_LDMIA(0, 0x3fc, 0, 0));
-
- /* clear interpret mode */
- cp15c15 &= ~0x1;
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
-
- /* read I TLB CAM content stored to r2-r9 */
- arm9tdmi_read_core_regs(target, 0x3fc, regs_p);
- jtag_execute_queue();
-
- for (i = 0; i < 8; i++)
- i_tlb[i + victim].cam = regs[i + 2];
- }
-
- for (victim = 0; victim < 64; victim++)
- {
- /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0]
- * base remains unchanged, victim goes through entries 0 to 63 */
- regs[1] = (Dlockdown & 0xfc000000) | (victim << 20);
- arm9tdmi_write_core_regs(target, 0x2, regs);
-
- /* set interpret mode */
- cp15c15 |= 0x1;
- arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15);
-
- /* Write I TLB lockdown */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0));
-
- /* Read I TLB RAM1 */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,9,4), ARMV4_5_LDR(2,0));
-
- /* Read I TLB RAM2 */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,1,5), ARMV4_5_LDR(3,0));
-
- /* clear interpret mode */
- cp15c15 &= ~0x1;
- arm920t_write_cp15_physical(target, 0x1e, cp15c15);
-
- /* read I TLB RAM content stored to r2 and r3 */
- arm9tdmi_read_core_regs(target, 0xc, regs_p);
- jtag_execute_queue();
-
- i_tlb[victim].ram1 = regs[2];
- i_tlb[victim].ram2 = regs[3];
- }
-
- /* restore I TLB lockdown */
- regs[1] = Ilockdown;
- arm9tdmi_write_core_regs(target, 0x2, regs);
-
- /* Write I TLB lockdown */
- arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0));
-
- /* restore CP15 MMU and Cache settings */
- arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl_saved);
-
- /* output data to file */
- fprintf(output, "D TLB content:\n");
- for (i = 0; i < 64; i++)
- {
- fprintf(output, "%i: 0x%8.8x 0x%8.8x 0x%8.8x %s\n", i, d_tlb[i].cam, d_tlb[i].ram1, d_tlb[i].ram2, (d_tlb[i].cam & 0x20) ? "(valid)" : "(invalid)");
- }
-
- fprintf(output, "\n\nI TLB content:\n");
- for (i = 0; i < 64; i++)
- {
- fprintf(output, "%i: 0x%8.8x 0x%8.8x 0x%8.8x %s\n", i, i_tlb[i].cam, i_tlb[i].ram1, i_tlb[i].ram2, (i_tlb[i].cam & 0x20) ? "(valid)" : "(invalid)");
- }
-
- command_print(cmd_ctx, "mmu content successfully output to %s", args[0]);
-
- fclose(output);
-
- /* mark registers dirty */
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).valid;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).valid;
-
- return ERROR_OK;
-}
-int arm920t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- int retval;
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm920t_common_t *arm920t;
- arm_jtag_t *jtag_info;
-
- if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM920t target");
- return ERROR_OK;
- }
-
- jtag_info = &arm7_9->jtag_info;
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- /* one or more argument, access a single register (write if second argument is given */
- if (argc >= 1)
- {
- int address = strtoul(args[0], NULL, 0);
-
- if (argc == 1)
- {
- u32 value;
- if ((retval = arm920t_read_cp15_physical(target, address, &value)) != ERROR_OK)
- {
- command_print(cmd_ctx, "couldn't access reg %i", address);
- return ERROR_OK;
- }
- jtag_execute_queue();
-
- command_print(cmd_ctx, "%i: %8.8x", address, value);
- }
- else if (argc == 2)
- {
- u32 value = strtoul(args[1], NULL, 0);
- if ((retval = arm920t_write_cp15_physical(target, address, value)) != ERROR_OK)
- {
- command_print(cmd_ctx, "couldn't access reg %i", address);
- return ERROR_OK;
- }
- command_print(cmd_ctx, "%i: %8.8x", address, value);
- }
- }
-
- return ERROR_OK;
-}
-
-int arm920t_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- int retval;
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm920t_common_t *arm920t;
- arm_jtag_t *jtag_info;
-
- if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM920t target");
- return ERROR_OK;
- }
-
- jtag_info = &arm7_9->jtag_info;
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- /* one or more argument, access a single register (write if second argument is given */
- if (argc >= 1)
- {
- u32 opcode = strtoul(args[0], NULL, 0);
-
- if (argc == 1)
- {
- u32 value;
- if ((retval = arm920t_read_cp15_interpreted(target, opcode, 0x0, &value)) != ERROR_OK)
- {
- command_print(cmd_ctx, "couldn't execute %8.8x", opcode);
- return ERROR_OK;
- }
-
- command_print(cmd_ctx, "%8.8x: %8.8x", opcode, value);
- }
- else if (argc == 2)
- {
- u32 value = strtoul(args[1], NULL, 0);
- if ((retval = arm920t_write_cp15_interpreted(target, opcode, value, 0)) != ERROR_OK)
- {
- command_print(cmd_ctx, "couldn't execute %8.8x", opcode);
- return ERROR_OK;
- }
- command_print(cmd_ctx, "%8.8x: %8.8x", opcode, value);
- }
- else if (argc == 3)
- {
- u32 value = strtoul(args[1], NULL, 0);
- u32 address = strtoul(args[2], NULL, 0);
- if ((retval = arm920t_write_cp15_interpreted(target, opcode, value, address)) != ERROR_OK)
- {
- command_print(cmd_ctx, "couldn't execute %8.8x", opcode);
- return ERROR_OK;
- }
- command_print(cmd_ctx, "%8.8x: %8.8x %8.8x", opcode, value, address);
- }
- }
- else
- {
- command_print(cmd_ctx, "usage: arm920t cp15i <opcode> [value] [address]");
- }
-
- return ERROR_OK;
-}
-
-int arm920t_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm920t_common_t *arm920t;
-
- if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM920t target");
- return ERROR_OK;
- }
-
- return armv4_5_handle_cache_info_command(cmd_ctx, &arm920t->armv4_5_mmu.armv4_5_cache);
-}
-
-int arm920t_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm920t_common_t *arm920t;
- arm_jtag_t *jtag_info;
-
- if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM920t target");
- return ERROR_OK;
- }
-
- jtag_info = &arm7_9->jtag_info;
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu);
-}
-
-int arm920t_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm920t_common_t *arm920t;
- arm_jtag_t *jtag_info;
-
- if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM920t target");
- return ERROR_OK;
- }
-
- jtag_info = &arm7_9->jtag_info;
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu);
-}
-
-int arm920t_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm920t_common_t *arm920t;
- arm_jtag_t *jtag_info;
-
- if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM920t target");
- return ERROR_OK;
- }
-
- jtag_info = &arm7_9->jtag_info;
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu);
-}
+/*************************************************************************** + * 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 "arm920t.h" +#include "jtag.h" +#include "log.h" + +#include <stdlib.h> +#include <string.h> + +#if 0 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + +/* cli handling */ +int arm920t_register_commands(struct command_context_s *cmd_ctx); + +int arm920t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm920t_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm920t_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm920t_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm920t_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm920t_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int arm920t_handle_read_cache_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm920t_handle_read_mmu_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +/* forward declarations */ +int arm920t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int arm920t_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int arm920t_quit(); +int arm920t_arch_state(struct target_s *target); +int arm920t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int arm920t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int arm920t_soft_reset_halt(struct target_s *target); + +#define ARM920T_CP15_PHYS_ADDR(x, y, z) ((x << 5) | (y << 1) << (z)) + +target_type_t arm920t_target = +{ + .name = "arm920t", + + .poll = arm7_9_poll, + .arch_state = arm920t_arch_state, + + .target_request_data = arm7_9_target_request_data, + + .halt = arm7_9_halt, + .resume = arm7_9_resume, + .step = arm7_9_step, + + .assert_reset = arm7_9_assert_reset, + .deassert_reset = arm7_9_deassert_reset, + .soft_reset_halt = arm920t_soft_reset_halt, + .prepare_reset_halt = arm7_9_prepare_reset_halt, + + .get_gdb_reg_list = armv4_5_get_gdb_reg_list, + + .read_memory = arm920t_read_memory, + .write_memory = arm920t_write_memory, + .bulk_write_memory = arm7_9_bulk_write_memory, + .checksum_memory = arm7_9_checksum_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, + .remove_watchpoint = arm7_9_remove_watchpoint, + + .register_commands = arm920t_register_commands, + .target_command = arm920t_target_command, + .init_target = arm920t_init_target, + .quit = arm920t_quit +}; + +int arm920t_read_cp15_physical(target_t *target, int reg_addr, u32 *value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + scan_field_t fields[4]; + u8 access_type_buf = 1; + u8 reg_addr_buf = reg_addr & 0x3f; + u8 nr_w_buf = 0; + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 1; + fields[0].out_value = &access_type_buf; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 6; + fields[2].out_value = ®_addr_buf; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + fields[3].device = jtag_info->chain_pos; + fields[3].num_bits = 1; + fields[3].out_value = &nr_w_buf; + fields[3].out_mask = NULL; + fields[3].in_value = NULL; + fields[3].in_check_value = NULL; + fields[3].in_check_mask = NULL; + fields[3].in_handler = NULL; + fields[3].in_handler_priv = NULL; + + jtag_add_dr_scan(4, fields, -1); + + fields[1].in_handler_priv = value; + fields[1].in_handler = arm_jtag_buf_to_u32; + + jtag_add_dr_scan(4, fields, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + jtag_execute_queue(); + DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value); +#endif + + return ERROR_OK; +} + +int arm920t_write_cp15_physical(target_t *target, int reg_addr, u32 value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + scan_field_t fields[4]; + u8 access_type_buf = 1; + u8 reg_addr_buf = reg_addr & 0x3f; + u8 nr_w_buf = 1; + u8 value_buf[4]; + + buf_set_u32(value_buf, 0, 32, value); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 1; + fields[0].out_value = &access_type_buf; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = value_buf; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 6; + fields[2].out_value = ®_addr_buf; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + fields[3].device = jtag_info->chain_pos; + fields[3].num_bits = 1; + fields[3].out_value = &nr_w_buf; + fields[3].out_mask = NULL; + fields[3].in_value = NULL; + fields[3].in_check_value = NULL; + fields[3].in_check_mask = NULL; + fields[3].in_handler = NULL; + fields[3].in_handler_priv = NULL; + + jtag_add_dr_scan(4, fields, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); +#endif + + return ERROR_OK; +} + +int arm920t_execute_cp15(target_t *target, u32 cp15_opcode, u32 arm_opcode) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + scan_field_t fields[4]; + u8 access_type_buf = 0; /* interpreted access */ + u8 reg_addr_buf = 0x0; + u8 nr_w_buf = 0; + u8 cp15_opcode_buf[4]; + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + buf_set_u32(cp15_opcode_buf, 0, 32, cp15_opcode); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 1; + fields[0].out_value = &access_type_buf; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = cp15_opcode_buf; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 6; + fields[2].out_value = ®_addr_buf; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + fields[3].device = jtag_info->chain_pos; + fields[3].num_bits = 1; + fields[3].out_value = &nr_w_buf; + fields[3].out_mask = NULL; + fields[3].in_value = NULL; + fields[3].in_check_value = NULL; + fields[3].in_check_mask = NULL; + fields[3].in_handler = NULL; + fields[3].in_handler_priv = NULL; + + jtag_add_dr_scan(4, fields, -1); + + arm9tdmi_clock_out(jtag_info, arm_opcode, 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); + arm7_9_execute_sys_speed(target); + + if (jtag_execute_queue() != ERROR_OK) + { + ERROR("failed executing JTAG queue, exiting"); + exit(-1); + } + + return ERROR_OK; +} + +int arm920t_read_cp15_interpreted(target_t *target, u32 cp15_opcode, u32 address, u32 *value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + u32* regs_p[1]; + u32 regs[2]; + u32 cp15c15 = 0x0; + + /* load address into R1 */ + regs[1] = address; + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* read-modify-write CP15 test state register + * to enable interpreted access mode */ + arm920t_read_cp15_physical(target, 0x1e, &cp15c15); + jtag_execute_queue(); + cp15c15 |= 1; /* set interpret mode */ + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* execute CP15 instruction and ARM load (reading from coprocessor) */ + arm920t_execute_cp15(target, cp15_opcode, ARMV4_5_LDR(0, 1)); + + /* disable interpreted access mode */ + cp15c15 &= ~1U; /* clear interpret mode */ + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* retrieve value from R0 */ + regs_p[0] = value; + arm9tdmi_read_core_regs(target, 0x1, regs_p); + jtag_execute_queue(); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("cp15_opcode: %8.8x, address: %8.8x, value: %8.8x", cp15_opcode, address, *value); +#endif + + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = 1; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = 1; + + return ERROR_OK; +} + +int arm920t_write_cp15_interpreted(target_t *target, u32 cp15_opcode, u32 value, u32 address) +{ + u32 cp15c15 = 0x0; + armv4_5_common_t *armv4_5 = target->arch_info; + u32 regs[2]; + + /* load value, address into R0, R1 */ + regs[0] = value; + regs[1] = address; + arm9tdmi_write_core_regs(target, 0x3, regs); + + /* read-modify-write CP15 test state register + * to enable interpreted access mode */ + arm920t_read_cp15_physical(target, 0x1e, &cp15c15); + jtag_execute_queue(); + cp15c15 |= 1; /* set interpret mode */ + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* execute CP15 instruction and ARM store (writing to coprocessor) */ + arm920t_execute_cp15(target, cp15_opcode, ARMV4_5_STR(0, 1)); + + /* disable interpreted access mode */ + cp15c15 &= ~1U; /* set interpret mode */ + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("cp15_opcode: %8.8x, value: %8.8x, address: %8.8x", cp15_opcode, value, address); +#endif + + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = 1; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = 1; + + return ERROR_OK; +} + +u32 arm920t_get_ttb(target_t *target) +{ + int retval; + u32 ttb = 0x0; + + if ((retval = arm920t_read_cp15_interpreted(target, 0xeebf0f51, 0x0, &ttb)) != ERROR_OK) + return retval; + + return ttb; +} + +void arm920t_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + u32 cp15_control; + + /* read cp15 control register */ + arm920t_read_cp15_physical(target, 0x2, &cp15_control); + jtag_execute_queue(); + + if (mmu) + cp15_control &= ~0x1U; + + if (d_u_cache) + cp15_control &= ~0x4U; + + if (i_cache) + cp15_control &= ~0x1000U; + + arm920t_write_cp15_physical(target, 0x2, cp15_control); +} + +void arm920t_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + u32 cp15_control; + + /* read cp15 control register */ + arm920t_read_cp15_physical(target, 0x2, &cp15_control); + jtag_execute_queue(); + + if (mmu) + cp15_control |= 0x1U; + + if (d_u_cache) + cp15_control |= 0x4U; + + if (i_cache) + cp15_control |= 0x1000U; + + arm920t_write_cp15_physical(target, 0x2, cp15_control); +} + +void arm920t_post_debug_entry(target_t *target) +{ + u32 cp15c15; + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm920t_common_t *arm920t = arm9tdmi->arch_info; + + /* examine cp15 control reg */ + arm920t_read_cp15_physical(target, 0x2, &arm920t->cp15_control_reg); + jtag_execute_queue(); + DEBUG("cp15_control_reg: %8.8x", arm920t->cp15_control_reg); + + if (arm920t->armv4_5_mmu.armv4_5_cache.ctype == -1) + { + u32 cache_type_reg; + /* identify caches */ + arm920t_read_cp15_physical(target, 0x1, &cache_type_reg); + jtag_execute_queue(); + armv4_5_identify_cache(cache_type_reg, &arm920t->armv4_5_mmu.armv4_5_cache); + } + + arm920t->armv4_5_mmu.mmu_enabled = (arm920t->cp15_control_reg & 0x1U) ? 1 : 0; + arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm920t->cp15_control_reg & 0x4U) ? 1 : 0; + arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm920t->cp15_control_reg & 0x1000U) ? 1 : 0; + + /* save i/d fault status and address register */ + arm920t_read_cp15_interpreted(target, 0xee150f10, 0x0, &arm920t->d_fsr); + arm920t_read_cp15_interpreted(target, 0xee150f30, 0x0, &arm920t->i_fsr); + arm920t_read_cp15_interpreted(target, 0xee160f10, 0x0, &arm920t->d_far); + arm920t_read_cp15_interpreted(target, 0xee160f30, 0x0, &arm920t->i_far); + + DEBUG("D FSR: 0x%8.8x, D FAR: 0x%8.8x, I FSR: 0x%8.8x, I FAR: 0x%8.8x", + arm920t->d_fsr, arm920t->d_far, arm920t->i_fsr, arm920t->i_far); + + if (arm920t->preserve_cache) + { + /* read-modify-write CP15 test state register + * to disable I/D-cache linefills */ + arm920t_read_cp15_physical(target, 0x1e, &cp15c15); + jtag_execute_queue(); + cp15c15 |= 0x600; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + } +} + +void arm920t_pre_restore_context(target_t *target) +{ + u32 cp15c15; + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm920t_common_t *arm920t = arm9tdmi->arch_info; + + /* restore i/d fault status and address register */ + arm920t_write_cp15_interpreted(target, 0xee050f10, arm920t->d_fsr, 0x0); + arm920t_write_cp15_interpreted(target, 0xee050f30, arm920t->i_fsr, 0x0); + arm920t_write_cp15_interpreted(target, 0xee060f10, arm920t->d_far, 0x0); + arm920t_write_cp15_interpreted(target, 0xee060f30, arm920t->i_far, 0x0); + + /* read-modify-write CP15 test state register + * to reenable I/D-cache linefills */ + if (arm920t->preserve_cache) + { + arm920t_read_cp15_physical(target, 0x1e, &cp15c15); + jtag_execute_queue(); + cp15c15 &= ~0x600U; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + } +} + +int arm920t_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p, arm920t_common_t **arm920t_p) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + return -1; + } + + arm7_9 = armv4_5->arch_info; + if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC) + { + return -1; + } + + arm9tdmi = arm7_9->arch_info; + if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC) + { + return -1; + } + + arm920t = arm9tdmi->arch_info; + if (arm920t->common_magic != ARM920T_COMMON_MAGIC) + { + return -1; + } + + *armv4_5_p = armv4_5; + *arm7_9_p = arm7_9; + *arm9tdmi_p = arm9tdmi; + *arm920t_p = arm920t; + + return ERROR_OK; +} + +int arm920t_arch_state(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm920t_common_t *arm920t = arm9tdmi->arch_info; + + char *state[] = + { + "disabled", "enabled" + }; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + ERROR("BUG: called for a non-ARMv4/5 target"); + exit(-1); + } + + USER( "target halted in %s state due to %s, current mode: %s\n" + "cpsr: 0x%8.8x pc: 0x%8.8x\n" + "MMU: %s, D-Cache: %s, I-Cache: %s", + armv4_5_state_strings[armv4_5->core_state], + target_debug_reason_strings[target->debug_reason], + armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)], + buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), + buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32), + state[arm920t->armv4_5_mmu.mmu_enabled], + state[arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], + state[arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled]); + + return ERROR_OK; +} + +int arm920t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + int retval; + + retval = arm7_9_read_memory(target, address, size, count, buffer); + + return retval; +} + +int arm920t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + int retval; + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm920t_common_t *arm920t = arm9tdmi->arch_info; + + if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK) + return retval; + + if (((size == 4) || (size == 2)) && (count == 1)) + { + if (arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) + { + DEBUG("D-Cache enabled, writing through to main memory"); + u32 pa, cb, ap; + int type, domain; + + pa = armv4_5_mmu_translate_va(target, &arm920t->armv4_5_mmu, address, &type, &cb, &domain, &ap); + if (type == -1) + return ERROR_OK; + /* cacheable & bufferable means write-back region */ + if (cb == 3) + armv4_5_mmu_write_physical(target, &arm920t->armv4_5_mmu, pa, size, count, buffer); + } + + if (arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled) + { + DEBUG("I-Cache enabled, invalidating affected I-Cache line"); + arm920t_write_cp15_interpreted(target, 0xee070f35, 0x0, address); + } + } + + return retval; +} + +int arm920t_soft_reset_halt(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm920t_common_t *arm920t = arm9tdmi->arch_info; + reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; + + if (target->state == TARGET_RUNNING) + { + target->type->halt(target); + } + + while (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) + { + embeddedice_read_reg(dbg_stat); + jtag_execute_queue(); + } + + target->state = TARGET_HALTED; + + /* SVC, ARM state, IRQ and FIQ disabled */ + buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3); + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1; + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1; + + /* start fetching from 0x0 */ + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0); + armv4_5->core_cache->reg_list[15].dirty = 1; + armv4_5->core_cache->reg_list[15].valid = 1; + + armv4_5->core_mode = ARMV4_5_MODE_SVC; + armv4_5->core_state = ARMV4_5_STATE_ARM; + + arm920t_disable_mmu_caches(target, 1, 1, 1); + arm920t->armv4_5_mmu.mmu_enabled = 0; + arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; + arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + + return ERROR_OK; +} + +int arm920t_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + arm9tdmi_init_target(cmd_ctx, target); + + return ERROR_OK; + +} + +int arm920t_quit() +{ + + return ERROR_OK; +} + +int arm920t_init_arch_info(target_t *target, arm920t_common_t *arm920t, int chain_pos, char *variant) +{ + arm9tdmi_common_t *arm9tdmi = &arm920t->arm9tdmi_common; + arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common; + + /* initialize arm9tdmi specific info (including arm7_9 and armv4_5) + */ + arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant); + + arm9tdmi->arch_info = arm920t; + arm920t->common_magic = ARM920T_COMMON_MAGIC; + + arm7_9->post_debug_entry = arm920t_post_debug_entry; + arm7_9->pre_restore_context = arm920t_pre_restore_context; + + arm920t->armv4_5_mmu.armv4_5_cache.ctype = -1; + arm920t->armv4_5_mmu.get_ttb = arm920t_get_ttb; + arm920t->armv4_5_mmu.read_memory = arm7_9_read_memory; + arm920t->armv4_5_mmu.write_memory = arm7_9_write_memory; + arm920t->armv4_5_mmu.disable_mmu_caches = arm920t_disable_mmu_caches; + arm920t->armv4_5_mmu.enable_mmu_caches = arm920t_enable_mmu_caches; + arm920t->armv4_5_mmu.has_tiny_pages = 1; + arm920t->armv4_5_mmu.mmu_enabled = 0; + + /* disabling linefills leads to lockups, so keep them enabled for now + * this doesn't affect correctness, but might affect timing issues, if + * important data is evicted from the cache during the debug session + * */ + arm920t->preserve_cache = 0; + + /* override hw single-step capability from ARM9TDMI */ + arm7_9->has_single_step = 1; + + return ERROR_OK; +} + +int arm920t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + int chain_pos; + char *variant = NULL; + arm920t_common_t *arm920t = malloc(sizeof(arm920t_common_t)); + + if (argc < 4) + { + ERROR("'target arm920t' requires at least one additional argument"); + exit(-1); + } + + chain_pos = strtoul(args[3], NULL, 0); + + if (argc >= 5) + variant = args[4]; + + DEBUG("chain_pos: %i, variant: %s", chain_pos, variant); + + arm920t_init_arch_info(target, arm920t, chain_pos, variant); + + return ERROR_OK; +} + +int arm920t_register_commands(struct command_context_s *cmd_ctx) +{ + int retval; + command_t *arm920t_cmd; + + + retval = arm9tdmi_register_commands(cmd_ctx); + + arm920t_cmd = register_command(cmd_ctx, NULL, "arm920t", NULL, COMMAND_ANY, "arm920t specific commands"); + + register_command(cmd_ctx, arm920t_cmd, "cp15", arm920t_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register <num> [value]"); + register_command(cmd_ctx, arm920t_cmd, "cp15i", arm920t_handle_cp15i_command, COMMAND_EXEC, "display/modify cp15 (interpreted access) <opcode> [value] [address]"); + register_command(cmd_ctx, arm920t_cmd, "cache_info", arm920t_handle_cache_info_command, COMMAND_EXEC, "display information about target caches"); + register_command(cmd_ctx, arm920t_cmd, "virt2phys", arm920t_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa <va>"); + + register_command(cmd_ctx, arm920t_cmd, "mdw_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory words <physical addr> [count]"); + register_command(cmd_ctx, arm920t_cmd, "mdh_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words <physical addr> [count]"); + register_command(cmd_ctx, arm920t_cmd, "mdb_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes <physical addr> [count]"); + + register_command(cmd_ctx, arm920t_cmd, "mww_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory word <physical addr> <value>"); + register_command(cmd_ctx, arm920t_cmd, "mwh_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word <physical addr> <value>"); + register_command(cmd_ctx, arm920t_cmd, "mwb_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte <physical addr> <value>"); + + register_command(cmd_ctx, arm920t_cmd, "read_cache", arm920t_handle_read_cache_command, COMMAND_EXEC, "display I/D cache content"); + register_command(cmd_ctx, arm920t_cmd, "read_mmu", arm920t_handle_read_mmu_command, COMMAND_EXEC, "display I/D mmu content"); + + return ERROR_OK; +} + +int arm920t_handle_read_cache_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + arm_jtag_t *jtag_info; + u32 cp15c15; + u32 cp15_ctrl, cp15_ctrl_saved; + u32 regs[16]; + u32 *regs_p[16]; + u32 C15_C_D_Ind, C15_C_I_Ind; + int i; + FILE *output; + arm920t_cache_line_t d_cache[8][64], i_cache[8][64]; + int segment, index; + + if (argc != 1) + { + command_print(cmd_ctx, "usage: arm920t read_cache <filename>"); + return ERROR_OK; + } + + if ((output = fopen(args[0], "w")) == NULL) + { + DEBUG("error opening cache content file"); + return ERROR_OK; + } + + for (i = 0; i < 16; i++) + regs_p[i] = ®s[i]; + + if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM920t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + /* disable MMU and Caches */ + arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), &cp15_ctrl); + jtag_execute_queue(); + cp15_ctrl_saved = cp15_ctrl; + cp15_ctrl &= ~(ARMV4_5_MMU_ENABLED | ARMV4_5_D_U_CACHE_ENABLED | ARMV4_5_I_CACHE_ENABLED); + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl); + + /* read CP15 test state register */ + arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), &cp15c15); + jtag_execute_queue(); + + /* read DCache content */ + fprintf(output, "DCache:\n"); + + /* go through segments 0 to nsets (8 on ARM920T, 4 on ARM922T) */ + for (segment = 0; segment < arm920t->armv4_5_mmu.armv4_5_cache.d_u_size.nsets; segment++) + { + fprintf(output, "\nsegment: %i\n----------", segment); + + /* Ra: r0 = SBZ(31:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* D CAM Read, loads current victim into C15.C.D.Ind */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,6,2), ARMV4_5_LDR(1, 0)); + + /* read current victim */ + arm920t_read_cp15_physical(target, 0x3d, &C15_C_D_Ind); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + for (index = 0; index < 64; index++) + { + /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5) | (index << 26); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write DCache victim */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,0), ARMV4_5_LDR(1, 0)); + + /* Read D RAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,10,2), ARMV4_5_LDMIA(0, 0x1fe, 0, 0)); + + /* Read D CAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,6,2), ARMV4_5_LDR(9, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read D RAM and CAM content */ + arm9tdmi_read_core_regs(target, 0x3fe, regs_p); + jtag_execute_queue(); + + d_cache[segment][index].cam = regs[9]; + + /* mask LFSR[6] */ + regs[9] &= 0xfffffffe; + fprintf(output, "\nsegment: %i, index: %i, CAM: 0x%8.8x, content (%s):\n", segment, index, regs[9], (regs[9] & 0x10) ? "valid" : "invalid"); + + for (i = 1; i < 9; i++) + { + d_cache[segment][index].data[i] = regs[i]; + fprintf(output, "%i: 0x%8.8x\n", i-1, regs[i]); + } + + } + + /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5) | (C15_C_D_Ind << 26); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write DCache victim */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,0), ARMV4_5_LDR(1, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + } + + /* read ICache content */ + fprintf(output, "ICache:\n"); + + /* go through segments 0 to nsets (8 on ARM920T, 4 on ARM922T) */ + for (segment = 0; segment < arm920t->armv4_5_mmu.armv4_5_cache.d_u_size.nsets; segment++) + { + fprintf(output, "segment: %i\n----------", segment); + + /* Ra: r0 = SBZ(31:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* I CAM Read, loads current victim into C15.C.I.Ind */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,5,2), ARMV4_5_LDR(1, 0)); + + /* read current victim */ + arm920t_read_cp15_physical(target, 0x3b, &C15_C_I_Ind); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + for (index = 0; index < 64; index++) + { + /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5) | (index << 26); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write ICache victim */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,1), ARMV4_5_LDR(1, 0)); + + /* Read I RAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,9,2), ARMV4_5_LDMIA(0, 0x1fe, 0, 0)); + + /* Read I CAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,5,2), ARMV4_5_LDR(9, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read I RAM and CAM content */ + arm9tdmi_read_core_regs(target, 0x3fe, regs_p); + jtag_execute_queue(); + + i_cache[segment][index].cam = regs[9]; + + /* mask LFSR[6] */ + regs[9] &= 0xfffffffe; + fprintf(output, "\nsegment: %i, index: %i, CAM: 0x%8.8x, content (%s):\n", segment, index, regs[9], (regs[9] & 0x10) ? "valid" : "invalid"); + + for (i = 1; i < 9; i++) + { + i_cache[segment][index].data[i] = regs[i]; + fprintf(output, "%i: 0x%8.8x\n", i-1, regs[i]); + } + + } + + + /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5) | (C15_C_D_Ind << 26); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write ICache victim */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,1), ARMV4_5_LDR(1, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + } + + /* restore CP15 MMU and Cache settings */ + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl_saved); + + command_print(cmd_ctx, "cache content successfully output to %s", args[0]); + + fclose(output); + + /* mark registers dirty. */ + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).valid; + + return ERROR_OK; +} + +int arm920t_handle_read_mmu_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + arm_jtag_t *jtag_info; + u32 cp15c15; + u32 cp15_ctrl, cp15_ctrl_saved; + u32 regs[16]; + u32 *regs_p[16]; + int i; + FILE *output; + u32 Dlockdown, Ilockdown; + arm920t_tlb_entry_t d_tlb[64], i_tlb[64]; + int victim; + + if (argc != 1) + { + command_print(cmd_ctx, "usage: arm920t read_mmu <filename>"); + return ERROR_OK; + } + + if ((output = fopen(args[0], "w")) == NULL) + { + DEBUG("error opening mmu content file"); + return ERROR_OK; + } + + for (i = 0; i < 16; i++) + regs_p[i] = ®s[i]; + + if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM920t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + /* disable MMU and Caches */ + arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), &cp15_ctrl); + jtag_execute_queue(); + cp15_ctrl_saved = cp15_ctrl; + cp15_ctrl &= ~(ARMV4_5_MMU_ENABLED | ARMV4_5_D_U_CACHE_ENABLED | ARMV4_5_I_CACHE_ENABLED); + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl); + + /* read CP15 test state register */ + arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), &cp15c15); + jtag_execute_queue(); + + /* prepare reading D TLB content + * */ + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Read D TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MRC(15,0,0,10,0,0), ARMV4_5_LDR(1, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read D TLB lockdown stored to r1 */ + arm9tdmi_read_core_regs(target, 0x2, regs_p); + jtag_execute_queue(); + Dlockdown = regs[1]; + + for (victim = 0; victim < 64; victim += 8) + { + /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] + * base remains unchanged, victim goes through entries 0 to 63 */ + regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write D TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0)); + + /* Read D TLB CAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,6,4), ARMV4_5_LDMIA(0, 0x3fc, 0, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read D TLB CAM content stored to r2-r9 */ + arm9tdmi_read_core_regs(target, 0x3fc, regs_p); + jtag_execute_queue(); + + for (i = 0; i < 8; i++) + d_tlb[victim + i].cam = regs[i + 2]; + } + + for (victim = 0; victim < 64; victim++) + { + /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] + * base remains unchanged, victim goes through entries 0 to 63 */ + regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write D TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0)); + + /* Read D TLB RAM1 */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,10,4), ARMV4_5_LDR(2,0)); + + /* Read D TLB RAM2 */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,2,5), ARMV4_5_LDR(3,0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read D TLB RAM content stored to r2 and r3 */ + arm9tdmi_read_core_regs(target, 0xc, regs_p); + jtag_execute_queue(); + + d_tlb[victim].ram1 = regs[2]; + d_tlb[victim].ram2 = regs[3]; + } + + /* restore D TLB lockdown */ + regs[1] = Dlockdown; + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* Write D TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0)); + + /* prepare reading I TLB content + * */ + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Read I TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MRC(15,0,0,10,0,1), ARMV4_5_LDR(1, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read I TLB lockdown stored to r1 */ + arm9tdmi_read_core_regs(target, 0x2, regs_p); + jtag_execute_queue(); + Ilockdown = regs[1]; + + for (victim = 0; victim < 64; victim += 8) + { + /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] + * base remains unchanged, victim goes through entries 0 to 63 */ + regs[1] = (Ilockdown & 0xfc000000) | (victim << 20); + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write I TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0)); + + /* Read I TLB CAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,5,4), ARMV4_5_LDMIA(0, 0x3fc, 0, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read I TLB CAM content stored to r2-r9 */ + arm9tdmi_read_core_regs(target, 0x3fc, regs_p); + jtag_execute_queue(); + + for (i = 0; i < 8; i++) + i_tlb[i + victim].cam = regs[i + 2]; + } + + for (victim = 0; victim < 64; victim++) + { + /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] + * base remains unchanged, victim goes through entries 0 to 63 */ + regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write I TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0)); + + /* Read I TLB RAM1 */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,9,4), ARMV4_5_LDR(2,0)); + + /* Read I TLB RAM2 */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,1,5), ARMV4_5_LDR(3,0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read I TLB RAM content stored to r2 and r3 */ + arm9tdmi_read_core_regs(target, 0xc, regs_p); + jtag_execute_queue(); + + i_tlb[victim].ram1 = regs[2]; + i_tlb[victim].ram2 = regs[3]; + } + + /* restore I TLB lockdown */ + regs[1] = Ilockdown; + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* Write I TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0)); + + /* restore CP15 MMU and Cache settings */ + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl_saved); + + /* output data to file */ + fprintf(output, "D TLB content:\n"); + for (i = 0; i < 64; i++) + { + fprintf(output, "%i: 0x%8.8x 0x%8.8x 0x%8.8x %s\n", i, d_tlb[i].cam, d_tlb[i].ram1, d_tlb[i].ram2, (d_tlb[i].cam & 0x20) ? "(valid)" : "(invalid)"); + } + + fprintf(output, "\n\nI TLB content:\n"); + for (i = 0; i < 64; i++) + { + fprintf(output, "%i: 0x%8.8x 0x%8.8x 0x%8.8x %s\n", i, i_tlb[i].cam, i_tlb[i].ram1, i_tlb[i].ram2, (i_tlb[i].cam & 0x20) ? "(valid)" : "(invalid)"); + } + + command_print(cmd_ctx, "mmu content successfully output to %s", args[0]); + + fclose(output); + + /* mark registers dirty */ + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).valid; + + return ERROR_OK; +} +int arm920t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + arm_jtag_t *jtag_info; + + if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM920t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + /* one or more argument, access a single register (write if second argument is given */ + if (argc >= 1) + { + int address = strtoul(args[0], NULL, 0); + + if (argc == 1) + { + u32 value; + if ((retval = arm920t_read_cp15_physical(target, address, &value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access reg %i", address); + return ERROR_OK; + } + jtag_execute_queue(); + + command_print(cmd_ctx, "%i: %8.8x", address, value); + } + else if (argc == 2) + { + u32 value = strtoul(args[1], NULL, 0); + if ((retval = arm920t_write_cp15_physical(target, address, value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access reg %i", address); + return ERROR_OK; + } + command_print(cmd_ctx, "%i: %8.8x", address, value); + } + } + + return ERROR_OK; +} + +int arm920t_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + arm_jtag_t *jtag_info; + + if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM920t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + /* one or more argument, access a single register (write if second argument is given */ + if (argc >= 1) + { + u32 opcode = strtoul(args[0], NULL, 0); + + if (argc == 1) + { + u32 value; + if ((retval = arm920t_read_cp15_interpreted(target, opcode, 0x0, &value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't execute %8.8x", opcode); + return ERROR_OK; + } + + command_print(cmd_ctx, "%8.8x: %8.8x", opcode, value); + } + else if (argc == 2) + { + u32 value = strtoul(args[1], NULL, 0); + if ((retval = arm920t_write_cp15_interpreted(target, opcode, value, 0)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't execute %8.8x", opcode); + return ERROR_OK; + } + command_print(cmd_ctx, "%8.8x: %8.8x", opcode, value); + } + else if (argc == 3) + { + u32 value = strtoul(args[1], NULL, 0); + u32 address = strtoul(args[2], NULL, 0); + if ((retval = arm920t_write_cp15_interpreted(target, opcode, value, address)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't execute %8.8x", opcode); + return ERROR_OK; + } + command_print(cmd_ctx, "%8.8x: %8.8x %8.8x", opcode, value, address); + } + } + else + { + command_print(cmd_ctx, "usage: arm920t cp15i <opcode> [value] [address]"); + } + + return ERROR_OK; +} + +int arm920t_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + + if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM920t target"); + return ERROR_OK; + } + + return armv4_5_handle_cache_info_command(cmd_ctx, &arm920t->armv4_5_mmu.armv4_5_cache); +} + +int arm920t_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + arm_jtag_t *jtag_info; + + if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM920t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu); +} + +int arm920t_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + arm_jtag_t *jtag_info; + + if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM920t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu); +} + +int arm920t_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + arm_jtag_t *jtag_info; + + if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM920t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu); +} diff --git a/src/target/arm926ejs.c b/src/target/arm926ejs.c index a02c27a..afe9226 100644 --- a/src/target/arm926ejs.c +++ b/src/target/arm926ejs.c @@ -1,944 +1,944 @@ -/***************************************************************************
- * Copyright (C) 2007 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 "arm926ejs.h"
-#include "jtag.h"
-#include "log.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#if 1
-#define _DEBUG_INSTRUCTION_EXECUTION_
-#endif
-
-/* cli handling */
-int arm926ejs_register_commands(struct command_context_s *cmd_ctx);
-
-int arm926ejs_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int arm926ejs_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int arm926ejs_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int arm926ejs_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int arm926ejs_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int arm926ejs_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-int arm926ejs_handle_read_cache_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int arm926ejs_handle_read_mmu_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-/* forward declarations */
-int arm926ejs_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
-int arm926ejs_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
-int arm926ejs_quit();
-int arm926ejs_arch_state(struct target_s *target);
-int arm926ejs_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
-int arm926ejs_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
-int arm926ejs_soft_reset_halt(struct target_s *target);
-static int arm926ejs_virt2phys(struct target_s *target, u32 virtual, u32 *physical);
-static int arm926ejs_mmu(struct target_s *target, int *enabled);
-
-target_type_t arm926ejs_target =
-{
- .name = "arm926ejs",
-
- .poll = arm7_9_poll,
- .arch_state = arm926ejs_arch_state,
-
- .target_request_data = arm7_9_target_request_data,
-
- .halt = arm7_9_halt,
- .resume = arm7_9_resume,
- .step = arm7_9_step,
-
- .assert_reset = arm7_9_assert_reset,
- .deassert_reset = arm7_9_deassert_reset,
- .soft_reset_halt = arm926ejs_soft_reset_halt,
- .prepare_reset_halt = arm7_9_prepare_reset_halt,
-
- .get_gdb_reg_list = armv4_5_get_gdb_reg_list,
-
- .read_memory = arm7_9_read_memory,
- .write_memory = arm926ejs_write_memory,
- .bulk_write_memory = arm7_9_bulk_write_memory,
- .checksum_memory = arm7_9_checksum_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,
- .remove_watchpoint = arm7_9_remove_watchpoint,
-
- .register_commands = arm926ejs_register_commands,
- .target_command = arm926ejs_target_command,
- .init_target = arm926ejs_init_target,
- .quit = arm926ejs_quit,
- .virt2phys = arm926ejs_virt2phys,
- .mmu = arm926ejs_mmu
-};
-
-
-int arm926ejs_catch_broken_irscan(u8 *captured, void *priv, scan_field_t *field)
-{
- /* The ARM926EJ-S' instruction register is 4 bits wide */
- u8 t = *captured & 0xf;
- u8 t2 = *field->in_check_value & 0xf;
- if (t == t2)
- {
- return ERROR_OK;
- }
- else if ((t == 0x0f) || (t == 0x00))
- {
- DEBUG("caught ARM926EJ-S invalid Capture-IR result after CP15 access");
- return ERROR_OK;
- }
- return ERROR_JTAG_QUEUE_FAILED;;
-}
-
-#define ARM926EJS_CP15_ADDR(opcode_1, opcode_2, CRn, CRm) ((opcode_1 << 11) | (opcode_2 << 8) | (CRn << 4) | (CRm << 0))
-
-int arm926ejs_cp15_read(target_t *target, u32 op1, u32 op2, u32 CRn, u32 CRm, u32 *value)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
- u32 address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm);
- scan_field_t fields[4];
- u8 address_buf[2];
- u8 nr_w_buf = 0;
- u8 access = 1;
-
- buf_set_u32(address_buf, 0, 14, address);
-
- jtag_add_end_state(TAP_RTI);
- arm_jtag_scann(jtag_info, 0xf);
- arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = NULL;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 1;
- fields[1].out_value = &access;
- fields[1].out_mask = NULL;
- fields[1].in_value = &access;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = jtag_info->chain_pos;
- fields[2].num_bits = 14;
- fields[2].out_value = address_buf;
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- fields[3].device = jtag_info->chain_pos;
- fields[3].num_bits = 1;
- fields[3].out_value = &nr_w_buf;
- fields[3].out_mask = NULL;
- fields[3].in_value = NULL;
- fields[3].in_check_value = NULL;
- fields[3].in_check_mask = NULL;
- fields[3].in_handler = NULL;
- fields[3].in_handler_priv = NULL;
-
- jtag_add_dr_scan(4, fields, -1);
-
- fields[0].in_handler_priv = value;
- fields[0].in_handler = arm_jtag_buf_to_u32;
-
- do
- {
- /* rescan with NOP, to wait for the access to complete */
- access = 0;
- nr_w_buf = 0;
- jtag_add_dr_scan(4, fields, -1);
- jtag_execute_queue();
- } while (buf_get_u32(&access, 0, 1) != 1);
-
-#ifdef _DEBUG_INSTRUCTION_EXECUTION_
- DEBUG("addr: 0x%x value: %8.8x", address, *value);
-#endif
-
- arm_jtag_set_instr(jtag_info, 0xc, &arm926ejs_catch_broken_irscan);
-
- return ERROR_OK;
-}
-
-int arm926ejs_cp15_write(target_t *target, u32 op1, u32 op2, u32 CRn, u32 CRm, u32 value)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
- u32 address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm);
- scan_field_t fields[4];
- u8 value_buf[4];
- u8 address_buf[2];
- u8 nr_w_buf = 1;
- u8 access = 1;
-
- buf_set_u32(address_buf, 0, 14, address);
- buf_set_u32(value_buf, 0, 32, value);
-
- jtag_add_end_state(TAP_RTI);
- arm_jtag_scann(jtag_info, 0xf);
- arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = value_buf;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 1;
- fields[1].out_value = &access;
- fields[1].out_mask = NULL;
- fields[1].in_value = &access;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = jtag_info->chain_pos;
- fields[2].num_bits = 14;
- fields[2].out_value = address_buf;
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- fields[3].device = jtag_info->chain_pos;
- fields[3].num_bits = 1;
- fields[3].out_value = &nr_w_buf;
- fields[3].out_mask = NULL;
- fields[3].in_value = NULL;
- fields[3].in_check_value = NULL;
- fields[3].in_check_mask = NULL;
- fields[3].in_handler = NULL;
- fields[3].in_handler_priv = NULL;
-
- jtag_add_dr_scan(4, fields, -1);
-
- do
- {
- /* rescan with NOP, to wait for the access to complete */
- access = 0;
- nr_w_buf = 0;
- jtag_add_dr_scan(4, fields, -1);
- jtag_execute_queue();
- } while (buf_get_u32(&access, 0, 1) != 1);
-
-#ifdef _DEBUG_INSTRUCTION_EXECUTION_
- DEBUG("addr: 0x%x value: %8.8x", address, value);
-#endif
-
- arm_jtag_set_instr(jtag_info, 0xf, &arm926ejs_catch_broken_irscan);
-
- return ERROR_OK;
-}
-
-int arm926ejs_examine_debug_reason(target_t *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
- int debug_reason;
- int retval;
-
- embeddedice_read_reg(dbg_stat);
- if ((retval = jtag_execute_queue()) != ERROR_OK)
- return retval;
-
- debug_reason = buf_get_u32(dbg_stat->value, 6, 4);
-
- switch (debug_reason)
- {
- case 1:
- DEBUG("breakpoint from EICE unit 0");
- target->debug_reason = DBG_REASON_BREAKPOINT;
- break;
- case 2:
- DEBUG("breakpoint from EICE unit 1");
- target->debug_reason = DBG_REASON_BREAKPOINT;
- break;
- case 3:
- DEBUG("soft breakpoint (BKPT instruction)");
- target->debug_reason = DBG_REASON_BREAKPOINT;
- break;
- case 4:
- DEBUG("vector catch breakpoint");
- target->debug_reason = DBG_REASON_BREAKPOINT;
- break;
- case 5:
- DEBUG("external breakpoint");
- target->debug_reason = DBG_REASON_BREAKPOINT;
- break;
- case 6:
- DEBUG("watchpoint from EICE unit 0");
- target->debug_reason = DBG_REASON_WATCHPOINT;
- break;
- case 7:
- DEBUG("watchpoint from EICE unit 1");
- target->debug_reason = DBG_REASON_WATCHPOINT;
- break;
- case 8:
- DEBUG("external watchpoint");
- target->debug_reason = DBG_REASON_WATCHPOINT;
- break;
- case 9:
- DEBUG("internal debug request");
- target->debug_reason = DBG_REASON_DBGRQ;
- break;
- case 10:
- DEBUG("external debug request");
- target->debug_reason = DBG_REASON_DBGRQ;
- break;
- case 11:
- ERROR("BUG: debug re-entry from system speed access shouldn't be handled here");
- break;
- default:
- ERROR("BUG: unknown debug reason: 0x%x", debug_reason);
- target->debug_reason = DBG_REASON_DBGRQ;
- }
-
- return ERROR_OK;
-}
-
-u32 arm926ejs_get_ttb(target_t *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
- arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info;
- int retval;
- u32 ttb = 0x0;
-
- if ((retval = arm926ejs->read_cp15(target, 0, 0, 2, 0, &ttb)) != ERROR_OK)
- return retval;
-
- return ttb;
-}
-
-void arm926ejs_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
- arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info;
- u32 cp15_control;
-
- /* read cp15 control register */
- arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control);
- jtag_execute_queue();
-
- if (mmu)
- {
- /* invalidate TLB */
- arm926ejs->write_cp15(target, 0, 0, 8, 7, 0x0);
-
- cp15_control &= ~0x1U;
- }
-
- if (d_u_cache)
- {
- u32 debug_override;
- /* read-modify-write CP15 debug override register
- * to enable "test and clean all" */
- arm926ejs->read_cp15(target, 0, 0, 15, 0, &debug_override);
- debug_override |= 0x80000;
- arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override);
-
- /* clean and invalidate DCache */
- arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0);
-
- /* write CP15 debug override register
- * to disable "test and clean all" */
- debug_override &= ~0x80000;
- arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override);
-
- cp15_control &= ~0x4U;
- }
-
- if (i_cache)
- {
- /* invalidate ICache */
- arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0);
-
- cp15_control &= ~0x1000U;
- }
-
- arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control);
-}
-
-void arm926ejs_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
- arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info;
- u32 cp15_control;
-
- /* read cp15 control register */
- arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control);
- jtag_execute_queue();
-
- if (mmu)
- cp15_control |= 0x1U;
-
- if (d_u_cache)
- cp15_control |= 0x4U;
-
- if (i_cache)
- cp15_control |= 0x1000U;
-
- arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control);
-}
-
-void arm926ejs_post_debug_entry(target_t *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
- arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info;
-
- /* examine cp15 control reg */
- arm926ejs->read_cp15(target, 0, 0, 1, 0, &arm926ejs->cp15_control_reg);
- jtag_execute_queue();
- DEBUG("cp15_control_reg: %8.8x", arm926ejs->cp15_control_reg);
-
- if (arm926ejs->armv4_5_mmu.armv4_5_cache.ctype == -1)
- {
- u32 cache_type_reg;
- /* identify caches */
- arm926ejs->read_cp15(target, 0, 1, 0, 0, &cache_type_reg);
- jtag_execute_queue();
- armv4_5_identify_cache(cache_type_reg, &arm926ejs->armv4_5_mmu.armv4_5_cache);
- }
-
- arm926ejs->armv4_5_mmu.mmu_enabled = (arm926ejs->cp15_control_reg & 0x1U) ? 1 : 0;
- arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm926ejs->cp15_control_reg & 0x4U) ? 1 : 0;
- arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm926ejs->cp15_control_reg & 0x1000U) ? 1 : 0;
-
- /* save i/d fault status and address register */
- arm926ejs->read_cp15(target, 0, 0, 5, 0, &arm926ejs->d_fsr);
- arm926ejs->read_cp15(target, 0, 1, 5, 0, &arm926ejs->i_fsr);
- arm926ejs->read_cp15(target, 0, 0, 6, 0, &arm926ejs->d_far);
-
- DEBUG("D FSR: 0x%8.8x, D FAR: 0x%8.8x, I FSR: 0x%8.8x",
- arm926ejs->d_fsr, arm926ejs->d_far, arm926ejs->i_fsr);
-
-
- u32 cache_dbg_ctrl;
-
- /* read-modify-write CP15 cache debug control register
- * to disable I/D-cache linefills and force WT */
- arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl);
- cache_dbg_ctrl |= 0x7;
- arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl);
-}
-
-void arm926ejs_pre_restore_context(target_t *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
- arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info;
-
- /* restore i/d fault status and address register */
- arm926ejs->write_cp15(target, 0, 0, 5, 0, arm926ejs->d_fsr);
- arm926ejs->write_cp15(target, 0, 1, 5, 0, arm926ejs->i_fsr);
- arm926ejs->write_cp15(target, 0, 0, 6, 0, arm926ejs->d_far);
-
- u32 cache_dbg_ctrl;
-
- /* read-modify-write CP15 cache debug control register
- * to reenable I/D-cache linefills and disable WT */
- arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl);
- cache_dbg_ctrl &= ~0x7;
- arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl);
-}
-
-int arm926ejs_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p, arm926ejs_common_t **arm926ejs_p)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm926ejs_common_t *arm926ejs;
-
- if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
- {
- return -1;
- }
-
- arm7_9 = armv4_5->arch_info;
- if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC)
- {
- return -1;
- }
-
- arm9tdmi = arm7_9->arch_info;
- if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC)
- {
- return -1;
- }
-
- arm926ejs = arm9tdmi->arch_info;
- if (arm926ejs->common_magic != ARM926EJS_COMMON_MAGIC)
- {
- return -1;
- }
-
- *armv4_5_p = armv4_5;
- *arm7_9_p = arm7_9;
- *arm9tdmi_p = arm9tdmi;
- *arm926ejs_p = arm926ejs;
-
- return ERROR_OK;
-}
-
-int arm926ejs_arch_state(struct target_s *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
- arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info;
-
- char *state[] =
- {
- "disabled", "enabled"
- };
-
- if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
- {
- ERROR("BUG: called for a non-ARMv4/5 target");
- exit(-1);
- }
-
- USER(
- "target halted in %s state due to %s, current mode: %s\n"
- "cpsr: 0x%8.8x pc: 0x%8.8x\n"
- "MMU: %s, D-Cache: %s, I-Cache: %s",
- armv4_5_state_strings[armv4_5->core_state],
- target_debug_reason_strings[target->debug_reason],
- armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)],
- buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
- buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32),
- state[arm926ejs->armv4_5_mmu.mmu_enabled],
- state[arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled],
- state[arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled]);
-
- return ERROR_OK;
-}
-
-int arm926ejs_soft_reset_halt(struct target_s *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
- arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info;
- reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
-
- if (target->state == TARGET_RUNNING)
- {
- target->type->halt(target);
- }
-
- while (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0)
- {
- embeddedice_read_reg(dbg_stat);
- jtag_execute_queue();
- }
-
- target->state = TARGET_HALTED;
-
- /* SVC, ARM state, IRQ and FIQ disabled */
- buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3);
- armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
- armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
-
- /* start fetching from 0x0 */
- buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0);
- armv4_5->core_cache->reg_list[15].dirty = 1;
- armv4_5->core_cache->reg_list[15].valid = 1;
-
- armv4_5->core_mode = ARMV4_5_MODE_SVC;
- armv4_5->core_state = ARMV4_5_STATE_ARM;
-
- arm926ejs_disable_mmu_caches(target, 1, 1, 1);
- arm926ejs->armv4_5_mmu.mmu_enabled = 0;
- arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0;
- arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
-
- target_call_event_callbacks(target, TARGET_EVENT_HALTED);
-
- return ERROR_OK;
-}
-
-int arm926ejs_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
-{
- int retval;
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info;
- arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info;
-
- if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK)
- return retval;
-
- /* If ICache is enabled, we have to invalidate affected ICache lines
- * the DCache is forced to write-through, so we don't have to clean it here
- */
- if (arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled)
- {
- if (count <= 1)
- {
- /* invalidate ICache single entry with MVA */
- arm926ejs->write_cp15(target, 0, 1, 7, 5, address);
- }
- else
- {
- /* invalidate ICache */
- arm926ejs->write_cp15(target, 0, 0, 7, 5, address);
- }
- }
-
- return retval;
-}
-
-int arm926ejs_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
-{
- arm9tdmi_init_target(cmd_ctx, target);
-
- return ERROR_OK;
-
-}
-
-int arm926ejs_quit()
-{
-
- return ERROR_OK;
-}
-
-int arm926ejs_init_arch_info(target_t *target, arm926ejs_common_t *arm926ejs, int chain_pos, char *variant)
-{
- arm9tdmi_common_t *arm9tdmi = &arm926ejs->arm9tdmi_common;
- arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common;
-
- /* initialize arm9tdmi specific info (including arm7_9 and armv4_5)
- */
- arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant);
-
- arm9tdmi->arch_info = arm926ejs;
- arm926ejs->common_magic = ARM926EJS_COMMON_MAGIC;
-
- arm7_9->post_debug_entry = arm926ejs_post_debug_entry;
- arm7_9->pre_restore_context = arm926ejs_pre_restore_context;
-
- arm926ejs->read_cp15 = arm926ejs_cp15_read;
- arm926ejs->write_cp15 = arm926ejs_cp15_write;
- arm926ejs->armv4_5_mmu.armv4_5_cache.ctype = -1;
- arm926ejs->armv4_5_mmu.get_ttb = arm926ejs_get_ttb;
- arm926ejs->armv4_5_mmu.read_memory = arm7_9_read_memory;
- arm926ejs->armv4_5_mmu.write_memory = arm7_9_write_memory;
- arm926ejs->armv4_5_mmu.disable_mmu_caches = arm926ejs_disable_mmu_caches;
- arm926ejs->armv4_5_mmu.enable_mmu_caches = arm926ejs_enable_mmu_caches;
- arm926ejs->armv4_5_mmu.has_tiny_pages = 1;
- arm926ejs->armv4_5_mmu.mmu_enabled = 0;
-
- arm7_9->examine_debug_reason = arm926ejs_examine_debug_reason;
-
- /* The ARM926EJ-S implements the ARMv5TE architecture which
- * has the BKPT instruction, so we don't have to use a watchpoint comparator
- */
- arm7_9->arm_bkpt = ARMV5_BKPT(0x0);
- arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff;
-
- arm7_9->sw_bkpts_use_wp = 0;
- arm7_9->sw_bkpts_enabled = 1;
-
- return ERROR_OK;
-}
-
-int arm926ejs_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
-{
- int chain_pos;
- char *variant = NULL;
- arm926ejs_common_t *arm926ejs = malloc(sizeof(arm926ejs_common_t));
-
- if (argc < 4)
- {
- ERROR("'target arm926ejs' requires at least one additional argument");
- exit(-1);
- }
-
- chain_pos = strtoul(args[3], NULL, 0);
-
- if (argc >= 5)
- variant = args[4];
-
- DEBUG("chain_pos: %i, variant: %s", chain_pos, variant);
-
- arm926ejs_init_arch_info(target, arm926ejs, chain_pos, variant);
-
- return ERROR_OK;
-}
-
-int arm926ejs_register_commands(struct command_context_s *cmd_ctx)
-{
- int retval;
- command_t *arm926ejs_cmd;
-
-
- retval = arm9tdmi_register_commands(cmd_ctx);
-
- arm926ejs_cmd = register_command(cmd_ctx, NULL, "arm926ejs", NULL, COMMAND_ANY, "arm926ejs specific commands");
-
- register_command(cmd_ctx, arm926ejs_cmd, "cp15", arm926ejs_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register <opcode_1> <opcode_2> <CRn> <CRm> [value]");
-
- register_command(cmd_ctx, arm926ejs_cmd, "cache_info", arm926ejs_handle_cache_info_command, COMMAND_EXEC, "display information about target caches");
- register_command(cmd_ctx, arm926ejs_cmd, "virt2phys", arm926ejs_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa <va>");
-
- register_command(cmd_ctx, arm926ejs_cmd, "mdw_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory words <physical addr> [count]");
- register_command(cmd_ctx, arm926ejs_cmd, "mdh_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory half-words <physical addr> [count]");
- register_command(cmd_ctx, arm926ejs_cmd, "mdb_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory bytes <physical addr> [count]");
-
- register_command(cmd_ctx, arm926ejs_cmd, "mww_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory word <physical addr> <value>");
- register_command(cmd_ctx, arm926ejs_cmd, "mwh_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word <physical addr> <value>");
- register_command(cmd_ctx, arm926ejs_cmd, "mwb_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory byte <physical addr> <value>");
-
- return ERROR_OK;
-}
-
-int arm926ejs_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- int retval;
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm926ejs_common_t *arm926ejs;
- int opcode_1;
- int opcode_2;
- int CRn;
- int CRm;
-
- if ((argc < 4) || (argc > 5))
- {
- command_print(cmd_ctx, "usage: arm926ejs cp15 <opcode_1> <opcode_2> <CRn> <CRm> [value]");
- return ERROR_OK;
- }
-
- opcode_1 = strtoul(args[0], NULL, 0);
- opcode_2 = strtoul(args[1], NULL, 0);
- CRn = strtoul(args[2], NULL, 0);
- CRm = strtoul(args[3], NULL, 0);
-
- if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM926EJ-S target");
- return ERROR_OK;
- }
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- if (argc == 4)
- {
- u32 value;
- if ((retval = arm926ejs->read_cp15(target, opcode_1, opcode_2, CRn, CRm, &value)) != ERROR_OK)
- {
- command_print(cmd_ctx, "couldn't access register");
- return ERROR_OK;
- }
- jtag_execute_queue();
-
- command_print(cmd_ctx, "%i %i %i %i: %8.8x", opcode_1, opcode_2, CRn, CRm, value);
- }
- else
- {
- u32 value = strtoul(args[4], NULL, 0);
- if ((retval = arm926ejs->write_cp15(target, opcode_1, opcode_2, CRn, CRm, value)) != ERROR_OK)
- {
- command_print(cmd_ctx, "couldn't access register");
- return ERROR_OK;
- }
- command_print(cmd_ctx, "%i %i %i %i: %8.8x", opcode_1, opcode_2, CRn, CRm, value);
- }
-
- return ERROR_OK;
-}
-
-int arm926ejs_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm926ejs_common_t *arm926ejs;
-
- if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM926EJ-S target");
- return ERROR_OK;
- }
-
- return armv4_5_handle_cache_info_command(cmd_ctx, &arm926ejs->armv4_5_mmu.armv4_5_cache);
-}
-
-int arm926ejs_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm926ejs_common_t *arm926ejs;
- arm_jtag_t *jtag_info;
-
- if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM926EJ-S target");
- return ERROR_OK;
- }
-
- jtag_info = &arm7_9->jtag_info;
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm926ejs->armv4_5_mmu);
-}
-
-int arm926ejs_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm926ejs_common_t *arm926ejs;
- arm_jtag_t *jtag_info;
-
- if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM926EJ-S target");
- return ERROR_OK;
- }
-
- jtag_info = &arm7_9->jtag_info;
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm926ejs->armv4_5_mmu);
-}
-
-int arm926ejs_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm926ejs_common_t *arm926ejs;
- arm_jtag_t *jtag_info;
-
- if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM926EJ-S target");
- return ERROR_OK;
- }
-
- jtag_info = &arm7_9->jtag_info;
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm926ejs->armv4_5_mmu);
-}
-static int arm926ejs_virt2phys(struct target_s *target, u32 virtual, u32 *physical)
-{
- int retval;
- int type;
- u32 cb;
- int domain;
- u32 ap;
-
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm926ejs_common_t *arm926ejs;
- retval= arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs);
- if (retval != ERROR_OK)
- {
- return retval;
- }
- u32 ret = armv4_5_mmu_translate_va(target, &arm926ejs->armv4_5_mmu, virtual, &type, &cb, &domain, &ap);
- if (type == -1)
- {
- return ret;
- }
- *physical = ret;
- return ERROR_OK;
-}
-
-static int arm926ejs_mmu(struct target_s *target, int *enabled)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm926ejs_common_t *arm926ejs = armv4_5->arch_info;
-
- if (target->state != TARGET_HALTED)
- {
- ERROR("Target not halted");
- return ERROR_TARGET_INVALID;
- }
- *enabled = arm926ejs->armv4_5_mmu.mmu_enabled;
- return ERROR_OK;
-}
+/*************************************************************************** + * Copyright (C) 2007 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 "arm926ejs.h" +#include "jtag.h" +#include "log.h" + +#include <stdlib.h> +#include <string.h> + +#if 1 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + +/* cli handling */ +int arm926ejs_register_commands(struct command_context_s *cmd_ctx); + +int arm926ejs_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int arm926ejs_handle_read_cache_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_read_mmu_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +/* forward declarations */ +int arm926ejs_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int arm926ejs_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int arm926ejs_quit(); +int arm926ejs_arch_state(struct target_s *target); +int arm926ejs_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int arm926ejs_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int arm926ejs_soft_reset_halt(struct target_s *target); +static int arm926ejs_virt2phys(struct target_s *target, u32 virtual, u32 *physical); +static int arm926ejs_mmu(struct target_s *target, int *enabled); + +target_type_t arm926ejs_target = +{ + .name = "arm926ejs", + + .poll = arm7_9_poll, + .arch_state = arm926ejs_arch_state, + + .target_request_data = arm7_9_target_request_data, + + .halt = arm7_9_halt, + .resume = arm7_9_resume, + .step = arm7_9_step, + + .assert_reset = arm7_9_assert_reset, + .deassert_reset = arm7_9_deassert_reset, + .soft_reset_halt = arm926ejs_soft_reset_halt, + .prepare_reset_halt = arm7_9_prepare_reset_halt, + + .get_gdb_reg_list = armv4_5_get_gdb_reg_list, + + .read_memory = arm7_9_read_memory, + .write_memory = arm926ejs_write_memory, + .bulk_write_memory = arm7_9_bulk_write_memory, + .checksum_memory = arm7_9_checksum_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, + .remove_watchpoint = arm7_9_remove_watchpoint, + + .register_commands = arm926ejs_register_commands, + .target_command = arm926ejs_target_command, + .init_target = arm926ejs_init_target, + .quit = arm926ejs_quit, + .virt2phys = arm926ejs_virt2phys, + .mmu = arm926ejs_mmu +}; + + +int arm926ejs_catch_broken_irscan(u8 *captured, void *priv, scan_field_t *field) +{ + /* The ARM926EJ-S' instruction register is 4 bits wide */ + u8 t = *captured & 0xf; + u8 t2 = *field->in_check_value & 0xf; + if (t == t2) + { + return ERROR_OK; + } + else if ((t == 0x0f) || (t == 0x00)) + { + DEBUG("caught ARM926EJ-S invalid Capture-IR result after CP15 access"); + return ERROR_OK; + } + return ERROR_JTAG_QUEUE_FAILED;; +} + +#define ARM926EJS_CP15_ADDR(opcode_1, opcode_2, CRn, CRm) ((opcode_1 << 11) | (opcode_2 << 8) | (CRn << 4) | (CRm << 0)) + +int arm926ejs_cp15_read(target_t *target, u32 op1, u32 op2, u32 CRn, u32 CRm, u32 *value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + u32 address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm); + scan_field_t fields[4]; + u8 address_buf[2]; + u8 nr_w_buf = 0; + u8 access = 1; + + buf_set_u32(address_buf, 0, 14, address); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 1; + fields[1].out_value = &access; + fields[1].out_mask = NULL; + fields[1].in_value = &access; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 14; + fields[2].out_value = address_buf; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + fields[3].device = jtag_info->chain_pos; + fields[3].num_bits = 1; + fields[3].out_value = &nr_w_buf; + fields[3].out_mask = NULL; + fields[3].in_value = NULL; + fields[3].in_check_value = NULL; + fields[3].in_check_mask = NULL; + fields[3].in_handler = NULL; + fields[3].in_handler_priv = NULL; + + jtag_add_dr_scan(4, fields, -1); + + fields[0].in_handler_priv = value; + fields[0].in_handler = arm_jtag_buf_to_u32; + + do + { + /* rescan with NOP, to wait for the access to complete */ + access = 0; + nr_w_buf = 0; + jtag_add_dr_scan(4, fields, -1); + jtag_execute_queue(); + } while (buf_get_u32(&access, 0, 1) != 1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("addr: 0x%x value: %8.8x", address, *value); +#endif + + arm_jtag_set_instr(jtag_info, 0xc, &arm926ejs_catch_broken_irscan); + + return ERROR_OK; +} + +int arm926ejs_cp15_write(target_t *target, u32 op1, u32 op2, u32 CRn, u32 CRm, u32 value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + u32 address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm); + scan_field_t fields[4]; + u8 value_buf[4]; + u8 address_buf[2]; + u8 nr_w_buf = 1; + u8 access = 1; + + buf_set_u32(address_buf, 0, 14, address); + buf_set_u32(value_buf, 0, 32, value); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = value_buf; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 1; + fields[1].out_value = &access; + fields[1].out_mask = NULL; + fields[1].in_value = &access; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 14; + fields[2].out_value = address_buf; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + fields[3].device = jtag_info->chain_pos; + fields[3].num_bits = 1; + fields[3].out_value = &nr_w_buf; + fields[3].out_mask = NULL; + fields[3].in_value = NULL; + fields[3].in_check_value = NULL; + fields[3].in_check_mask = NULL; + fields[3].in_handler = NULL; + fields[3].in_handler_priv = NULL; + + jtag_add_dr_scan(4, fields, -1); + + do + { + /* rescan with NOP, to wait for the access to complete */ + access = 0; + nr_w_buf = 0; + jtag_add_dr_scan(4, fields, -1); + jtag_execute_queue(); + } while (buf_get_u32(&access, 0, 1) != 1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("addr: 0x%x value: %8.8x", address, value); +#endif + + arm_jtag_set_instr(jtag_info, 0xf, &arm926ejs_catch_broken_irscan); + + return ERROR_OK; +} + +int arm926ejs_examine_debug_reason(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; + int debug_reason; + int retval; + + embeddedice_read_reg(dbg_stat); + if ((retval = jtag_execute_queue()) != ERROR_OK) + return retval; + + debug_reason = buf_get_u32(dbg_stat->value, 6, 4); + + switch (debug_reason) + { + case 1: + DEBUG("breakpoint from EICE unit 0"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 2: + DEBUG("breakpoint from EICE unit 1"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 3: + DEBUG("soft breakpoint (BKPT instruction)"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 4: + DEBUG("vector catch breakpoint"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 5: + DEBUG("external breakpoint"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 6: + DEBUG("watchpoint from EICE unit 0"); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case 7: + DEBUG("watchpoint from EICE unit 1"); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case 8: + DEBUG("external watchpoint"); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case 9: + DEBUG("internal debug request"); + target->debug_reason = DBG_REASON_DBGRQ; + break; + case 10: + DEBUG("external debug request"); + target->debug_reason = DBG_REASON_DBGRQ; + break; + case 11: + ERROR("BUG: debug re-entry from system speed access shouldn't be handled here"); + break; + default: + ERROR("BUG: unknown debug reason: 0x%x", debug_reason); + target->debug_reason = DBG_REASON_DBGRQ; + } + + return ERROR_OK; +} + +u32 arm926ejs_get_ttb(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + int retval; + u32 ttb = 0x0; + + if ((retval = arm926ejs->read_cp15(target, 0, 0, 2, 0, &ttb)) != ERROR_OK) + return retval; + + return ttb; +} + +void arm926ejs_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + u32 cp15_control; + + /* read cp15 control register */ + arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control); + jtag_execute_queue(); + + if (mmu) + { + /* invalidate TLB */ + arm926ejs->write_cp15(target, 0, 0, 8, 7, 0x0); + + cp15_control &= ~0x1U; + } + + if (d_u_cache) + { + u32 debug_override; + /* read-modify-write CP15 debug override register + * to enable "test and clean all" */ + arm926ejs->read_cp15(target, 0, 0, 15, 0, &debug_override); + debug_override |= 0x80000; + arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override); + + /* clean and invalidate DCache */ + arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0); + + /* write CP15 debug override register + * to disable "test and clean all" */ + debug_override &= ~0x80000; + arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override); + + cp15_control &= ~0x4U; + } + + if (i_cache) + { + /* invalidate ICache */ + arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0); + + cp15_control &= ~0x1000U; + } + + arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); +} + +void arm926ejs_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + u32 cp15_control; + + /* read cp15 control register */ + arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control); + jtag_execute_queue(); + + if (mmu) + cp15_control |= 0x1U; + + if (d_u_cache) + cp15_control |= 0x4U; + + if (i_cache) + cp15_control |= 0x1000U; + + arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); +} + +void arm926ejs_post_debug_entry(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + + /* examine cp15 control reg */ + arm926ejs->read_cp15(target, 0, 0, 1, 0, &arm926ejs->cp15_control_reg); + jtag_execute_queue(); + DEBUG("cp15_control_reg: %8.8x", arm926ejs->cp15_control_reg); + + if (arm926ejs->armv4_5_mmu.armv4_5_cache.ctype == -1) + { + u32 cache_type_reg; + /* identify caches */ + arm926ejs->read_cp15(target, 0, 1, 0, 0, &cache_type_reg); + jtag_execute_queue(); + armv4_5_identify_cache(cache_type_reg, &arm926ejs->armv4_5_mmu.armv4_5_cache); + } + + arm926ejs->armv4_5_mmu.mmu_enabled = (arm926ejs->cp15_control_reg & 0x1U) ? 1 : 0; + arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm926ejs->cp15_control_reg & 0x4U) ? 1 : 0; + arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm926ejs->cp15_control_reg & 0x1000U) ? 1 : 0; + + /* save i/d fault status and address register */ + arm926ejs->read_cp15(target, 0, 0, 5, 0, &arm926ejs->d_fsr); + arm926ejs->read_cp15(target, 0, 1, 5, 0, &arm926ejs->i_fsr); + arm926ejs->read_cp15(target, 0, 0, 6, 0, &arm926ejs->d_far); + + DEBUG("D FSR: 0x%8.8x, D FAR: 0x%8.8x, I FSR: 0x%8.8x", + arm926ejs->d_fsr, arm926ejs->d_far, arm926ejs->i_fsr); + + + u32 cache_dbg_ctrl; + + /* read-modify-write CP15 cache debug control register + * to disable I/D-cache linefills and force WT */ + arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl); + cache_dbg_ctrl |= 0x7; + arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl); +} + +void arm926ejs_pre_restore_context(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + + /* restore i/d fault status and address register */ + arm926ejs->write_cp15(target, 0, 0, 5, 0, arm926ejs->d_fsr); + arm926ejs->write_cp15(target, 0, 1, 5, 0, arm926ejs->i_fsr); + arm926ejs->write_cp15(target, 0, 0, 6, 0, arm926ejs->d_far); + + u32 cache_dbg_ctrl; + + /* read-modify-write CP15 cache debug control register + * to reenable I/D-cache linefills and disable WT */ + arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl); + cache_dbg_ctrl &= ~0x7; + arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl); +} + +int arm926ejs_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p, arm926ejs_common_t **arm926ejs_p) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm926ejs_common_t *arm926ejs; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + return -1; + } + + arm7_9 = armv4_5->arch_info; + if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC) + { + return -1; + } + + arm9tdmi = arm7_9->arch_info; + if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC) + { + return -1; + } + + arm926ejs = arm9tdmi->arch_info; + if (arm926ejs->common_magic != ARM926EJS_COMMON_MAGIC) + { + return -1; + } + + *armv4_5_p = armv4_5; + *arm7_9_p = arm7_9; + *arm9tdmi_p = arm9tdmi; + *arm926ejs_p = arm926ejs; + + return ERROR_OK; +} + +int arm926ejs_arch_state(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + + char *state[] = + { + "disabled", "enabled" + }; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + ERROR("BUG: called for a non-ARMv4/5 target"); + exit(-1); + } + + USER( + "target halted in %s state due to %s, current mode: %s\n" + "cpsr: 0x%8.8x pc: 0x%8.8x\n" + "MMU: %s, D-Cache: %s, I-Cache: %s", + armv4_5_state_strings[armv4_5->core_state], + target_debug_reason_strings[target->debug_reason], + armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)], + buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), + buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32), + state[arm926ejs->armv4_5_mmu.mmu_enabled], + state[arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], + state[arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled]); + + return ERROR_OK; +} + +int arm926ejs_soft_reset_halt(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; + + if (target->state == TARGET_RUNNING) + { + target->type->halt(target); + } + + while (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) + { + embeddedice_read_reg(dbg_stat); + jtag_execute_queue(); + } + + target->state = TARGET_HALTED; + + /* SVC, ARM state, IRQ and FIQ disabled */ + buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3); + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1; + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1; + + /* start fetching from 0x0 */ + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0); + armv4_5->core_cache->reg_list[15].dirty = 1; + armv4_5->core_cache->reg_list[15].valid = 1; + + armv4_5->core_mode = ARMV4_5_MODE_SVC; + armv4_5->core_state = ARMV4_5_STATE_ARM; + + arm926ejs_disable_mmu_caches(target, 1, 1, 1); + arm926ejs->armv4_5_mmu.mmu_enabled = 0; + arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; + arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + + return ERROR_OK; +} + +int arm926ejs_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + int retval; + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + + if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK) + return retval; + + /* If ICache is enabled, we have to invalidate affected ICache lines + * the DCache is forced to write-through, so we don't have to clean it here + */ + if (arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled) + { + if (count <= 1) + { + /* invalidate ICache single entry with MVA */ + arm926ejs->write_cp15(target, 0, 1, 7, 5, address); + } + else + { + /* invalidate ICache */ + arm926ejs->write_cp15(target, 0, 0, 7, 5, address); + } + } + + return retval; +} + +int arm926ejs_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + arm9tdmi_init_target(cmd_ctx, target); + + return ERROR_OK; + +} + +int arm926ejs_quit() +{ + + return ERROR_OK; +} + +int arm926ejs_init_arch_info(target_t *target, arm926ejs_common_t *arm926ejs, int chain_pos, char *variant) +{ + arm9tdmi_common_t *arm9tdmi = &arm926ejs->arm9tdmi_common; + arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common; + + /* initialize arm9tdmi specific info (including arm7_9 and armv4_5) + */ + arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant); + + arm9tdmi->arch_info = arm926ejs; + arm926ejs->common_magic = ARM926EJS_COMMON_MAGIC; + + arm7_9->post_debug_entry = arm926ejs_post_debug_entry; + arm7_9->pre_restore_context = arm926ejs_pre_restore_context; + + arm926ejs->read_cp15 = arm926ejs_cp15_read; + arm926ejs->write_cp15 = arm926ejs_cp15_write; + arm926ejs->armv4_5_mmu.armv4_5_cache.ctype = -1; + arm926ejs->armv4_5_mmu.get_ttb = arm926ejs_get_ttb; + arm926ejs->armv4_5_mmu.read_memory = arm7_9_read_memory; + arm926ejs->armv4_5_mmu.write_memory = arm7_9_write_memory; + arm926ejs->armv4_5_mmu.disable_mmu_caches = arm926ejs_disable_mmu_caches; + arm926ejs->armv4_5_mmu.enable_mmu_caches = arm926ejs_enable_mmu_caches; + arm926ejs->armv4_5_mmu.has_tiny_pages = 1; + arm926ejs->armv4_5_mmu.mmu_enabled = 0; + + arm7_9->examine_debug_reason = arm926ejs_examine_debug_reason; + + /* The ARM926EJ-S implements the ARMv5TE architecture which + * has the BKPT instruction, so we don't have to use a watchpoint comparator + */ + arm7_9->arm_bkpt = ARMV5_BKPT(0x0); + arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; + + arm7_9->sw_bkpts_use_wp = 0; + arm7_9->sw_bkpts_enabled = 1; + + return ERROR_OK; +} + +int arm926ejs_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + int chain_pos; + char *variant = NULL; + arm926ejs_common_t *arm926ejs = malloc(sizeof(arm926ejs_common_t)); + + if (argc < 4) + { + ERROR("'target arm926ejs' requires at least one additional argument"); + exit(-1); + } + + chain_pos = strtoul(args[3], NULL, 0); + + if (argc >= 5) + variant = args[4]; + + DEBUG("chain_pos: %i, variant: %s", chain_pos, variant); + + arm926ejs_init_arch_info(target, arm926ejs, chain_pos, variant); + + return ERROR_OK; +} + +int arm926ejs_register_commands(struct command_context_s *cmd_ctx) +{ + int retval; + command_t *arm926ejs_cmd; + + + retval = arm9tdmi_register_commands(cmd_ctx); + + arm926ejs_cmd = register_command(cmd_ctx, NULL, "arm926ejs", NULL, COMMAND_ANY, "arm926ejs specific commands"); + + register_command(cmd_ctx, arm926ejs_cmd, "cp15", arm926ejs_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register <opcode_1> <opcode_2> <CRn> <CRm> [value]"); + + register_command(cmd_ctx, arm926ejs_cmd, "cache_info", arm926ejs_handle_cache_info_command, COMMAND_EXEC, "display information about target caches"); + register_command(cmd_ctx, arm926ejs_cmd, "virt2phys", arm926ejs_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa <va>"); + + register_command(cmd_ctx, arm926ejs_cmd, "mdw_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory words <physical addr> [count]"); + register_command(cmd_ctx, arm926ejs_cmd, "mdh_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory half-words <physical addr> [count]"); + register_command(cmd_ctx, arm926ejs_cmd, "mdb_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory bytes <physical addr> [count]"); + + register_command(cmd_ctx, arm926ejs_cmd, "mww_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory word <physical addr> <value>"); + register_command(cmd_ctx, arm926ejs_cmd, "mwh_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word <physical addr> <value>"); + register_command(cmd_ctx, arm926ejs_cmd, "mwb_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory byte <physical addr> <value>"); + + return ERROR_OK; +} + +int arm926ejs_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm926ejs_common_t *arm926ejs; + int opcode_1; + int opcode_2; + int CRn; + int CRm; + + if ((argc < 4) || (argc > 5)) + { + command_print(cmd_ctx, "usage: arm926ejs cp15 <opcode_1> <opcode_2> <CRn> <CRm> [value]"); + return ERROR_OK; + } + + opcode_1 = strtoul(args[0], NULL, 0); + opcode_2 = strtoul(args[1], NULL, 0); + CRn = strtoul(args[2], NULL, 0); + CRm = strtoul(args[3], NULL, 0); + + if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + if (argc == 4) + { + u32 value; + if ((retval = arm926ejs->read_cp15(target, opcode_1, opcode_2, CRn, CRm, &value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access register"); + return ERROR_OK; + } + jtag_execute_queue(); + + command_print(cmd_ctx, "%i %i %i %i: %8.8x", opcode_1, opcode_2, CRn, CRm, value); + } + else + { + u32 value = strtoul(args[4], NULL, 0); + if ((retval = arm926ejs->write_cp15(target, opcode_1, opcode_2, CRn, CRm, value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access register"); + return ERROR_OK; + } + command_print(cmd_ctx, "%i %i %i %i: %8.8x", opcode_1, opcode_2, CRn, CRm, value); + } + + return ERROR_OK; +} + +int arm926ejs_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm926ejs_common_t *arm926ejs; + + if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); + return ERROR_OK; + } + + return armv4_5_handle_cache_info_command(cmd_ctx, &arm926ejs->armv4_5_mmu.armv4_5_cache); +} + +int arm926ejs_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm926ejs_common_t *arm926ejs; + arm_jtag_t *jtag_info; + + if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm926ejs->armv4_5_mmu); +} + +int arm926ejs_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm926ejs_common_t *arm926ejs; + arm_jtag_t *jtag_info; + + if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm926ejs->armv4_5_mmu); +} + +int arm926ejs_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm926ejs_common_t *arm926ejs; + arm_jtag_t *jtag_info; + + if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm926ejs->armv4_5_mmu); +} +static int arm926ejs_virt2phys(struct target_s *target, u32 virtual, u32 *physical) +{ + int retval; + int type; + u32 cb; + int domain; + u32 ap; + + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm926ejs_common_t *arm926ejs; + retval= arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs); + if (retval != ERROR_OK) + { + return retval; + } + u32 ret = armv4_5_mmu_translate_va(target, &arm926ejs->armv4_5_mmu, virtual, &type, &cb, &domain, &ap); + if (type == -1) + { + return ret; + } + *physical = ret; + return ERROR_OK; +} + +static int arm926ejs_mmu(struct target_s *target, int *enabled) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm926ejs_common_t *arm926ejs = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + ERROR("Target not halted"); + return ERROR_TARGET_INVALID; + } + *enabled = arm926ejs->armv4_5_mmu.mmu_enabled; + return ERROR_OK; +} diff --git a/src/target/arm966e.c b/src/target/arm966e.c index 1ea2ce7..4ba5d85 100644 --- a/src/target/arm966e.c +++ b/src/target/arm966e.c @@ -1,364 +1,364 @@ -/***************************************************************************
- * 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 "arm966e.h"
-
-#include "arm7_9_common.h"
-#include "register.h"
-#include "target.h"
-#include "armv4_5.h"
-#include "embeddedice.h"
-#include "log.h"
-#include "jtag.h"
-#include "arm_jtag.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#if 0
-#define _DEBUG_INSTRUCTION_EXECUTION_
-#endif
-
-/* cli handling */
-int arm966e_register_commands(struct command_context_s *cmd_ctx);
-
-/* forward declarations */
-int arm966e_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
-int arm966e_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
-int arm966e_quit(void);
-
-target_type_t arm966e_target =
-{
- .name = "arm966e",
-
- .poll = arm7_9_poll,
- .arch_state = armv4_5_arch_state,
-
- .target_request_data = arm7_9_target_request_data,
-
- .halt = arm7_9_halt,
- .resume = arm7_9_resume,
- .step = arm7_9_step,
-
- .assert_reset = arm7_9_assert_reset,
- .deassert_reset = arm7_9_deassert_reset,
- .soft_reset_halt = arm7_9_soft_reset_halt,
- .prepare_reset_halt = arm7_9_prepare_reset_halt,
-
- .get_gdb_reg_list = armv4_5_get_gdb_reg_list,
-
- .read_memory = arm7_9_read_memory,
- .write_memory = arm7_9_write_memory,
- .bulk_write_memory = arm7_9_bulk_write_memory,
- .checksum_memory = arm7_9_checksum_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,
- .remove_watchpoint = arm7_9_remove_watchpoint,
-
- .register_commands = arm966e_register_commands,
- .target_command = arm966e_target_command,
- .init_target = arm966e_init_target,
- .quit = arm966e_quit,
-};
-
-int arm966e_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
-{
- arm9tdmi_init_target(cmd_ctx, target);
-
- return ERROR_OK;
-}
-
-int arm966e_quit(void)
-{
-
- return ERROR_OK;
-}
-
-int arm966e_init_arch_info(target_t *target, arm966e_common_t *arm966e, int chain_pos, char *variant)
-{
- arm9tdmi_common_t *arm9tdmi = &arm966e->arm9tdmi_common;
- arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common;
-
- arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant);
-
- arm9tdmi->arch_info = arm966e;
- arm966e->common_magic = ARM966E_COMMON_MAGIC;
-
- /* The ARM966E-S implements the ARMv5TE architecture which
- * has the BKPT instruction, so we don't have to use a watchpoint comparator
- */
- arm7_9->arm_bkpt = ARMV5_BKPT(0x0);
- arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff;
-
- arm7_9->sw_bkpts_use_wp = 0;
- arm7_9->sw_bkpts_enabled = 1;
-
- return ERROR_OK;
-}
-
-int arm966e_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
-{
- int chain_pos;
- char *variant = NULL;
- arm966e_common_t *arm966e = malloc(sizeof(arm966e_common_t));
-
- if (argc < 4)
- {
- ERROR("'target arm966e' requires at least one additional argument");
- exit(-1);
- }
-
- chain_pos = strtoul(args[3], NULL, 0);
-
- if (argc >= 5)
- variant = args[4];
-
- DEBUG("chain_pos: %i, variant: %s", chain_pos, variant);
-
- arm966e_init_arch_info(target, arm966e, chain_pos, variant);
-
- return ERROR_OK;
-}
-
-int arm966e_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p, arm966e_common_t **arm966e_p)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm966e_common_t *arm966e;
-
- if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
- {
- return -1;
- }
-
- arm7_9 = armv4_5->arch_info;
- if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC)
- {
- return -1;
- }
-
- arm9tdmi = arm7_9->arch_info;
- if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC)
- {
- return -1;
- }
-
- arm966e = arm9tdmi->arch_info;
- if (arm966e->common_magic != ARM966E_COMMON_MAGIC)
- {
- return -1;
- }
-
- *armv4_5_p = armv4_5;
- *arm7_9_p = arm7_9;
- *arm9tdmi_p = arm9tdmi;
- *arm966e_p = arm966e;
-
- return ERROR_OK;
-}
-
-int arm966e_read_cp15(target_t *target, int reg_addr, u32 *value)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
- scan_field_t fields[3];
- u8 reg_addr_buf = reg_addr & 0x3f;
- u8 nr_w_buf = 0;
-
- jtag_add_end_state(TAP_RTI);
- arm_jtag_scann(jtag_info, 0xf);
- arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = NULL;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 6;
- fields[1].out_value = ®_addr_buf;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = jtag_info->chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = &nr_w_buf;
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- jtag_add_dr_scan(3, fields, -1);
-
- fields[0].in_handler_priv = value;
- fields[0].in_handler = arm_jtag_buf_to_u32;
-
- jtag_add_dr_scan(3, fields, -1);
-
-#ifdef _DEBUG_INSTRUCTION_EXECUTION_
- jtag_execute_queue();
- DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value);
-#endif
-
- return ERROR_OK;
-}
-
-int arm966e_write_cp15(target_t *target, int reg_addr, u32 value)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
- scan_field_t fields[3];
- u8 reg_addr_buf = reg_addr & 0x3f;
- u8 nr_w_buf = 1;
- u8 value_buf[4];
-
- buf_set_u32(value_buf, 0, 32, value);
-
- jtag_add_end_state(TAP_RTI);
- arm_jtag_scann(jtag_info, 0xf);
- arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = value_buf;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 6;
- fields[1].out_value = ®_addr_buf;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = jtag_info->chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = &nr_w_buf;
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- jtag_add_dr_scan(3, fields, -1);
-
-#ifdef _DEBUG_INSTRUCTION_EXECUTION_
- DEBUG("addr: 0x%x value: %8.8x", reg_addr, value);
-#endif
-
- return ERROR_OK;
-}
-
-int arm966e_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- int retval;
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- arm966e_common_t *arm966e;
- arm_jtag_t *jtag_info;
-
- if (arm966e_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm966e) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM966e target");
- return ERROR_OK;
- }
-
- jtag_info = &arm7_9->jtag_info;
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- /* one or more argument, access a single register (write if second argument is given */
- if (argc >= 1)
- {
- int address = strtoul(args[0], NULL, 0);
-
- if (argc == 1)
- {
- u32 value;
- if ((retval = arm966e_read_cp15(target, address, &value)) != ERROR_OK)
- {
- command_print(cmd_ctx, "couldn't access reg %i", address);
- return ERROR_OK;
- }
- jtag_execute_queue();
-
- command_print(cmd_ctx, "%i: %8.8x", address, value);
- }
- else if (argc == 2)
- {
- u32 value = strtoul(args[1], NULL, 0);
- if ((retval = arm966e_write_cp15(target, address, value)) != ERROR_OK)
- {
- command_print(cmd_ctx, "couldn't access reg %i", address);
- return ERROR_OK;
- }
- command_print(cmd_ctx, "%i: %8.8x", address, value);
- }
- }
-
- return ERROR_OK;
-}
-
-int arm966e_register_commands(struct command_context_s *cmd_ctx)
-{
- int retval;
- command_t *arm966e_cmd;
-
- retval = arm9tdmi_register_commands(cmd_ctx);
- arm966e_cmd = register_command(cmd_ctx, NULL, "arm966e", NULL, COMMAND_ANY, "arm966e specific commands");
- register_command(cmd_ctx, arm966e_cmd, "cp15", arm966e_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register <num> [value]");
-
- return ERROR_OK;
-}
+/*************************************************************************** + * 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 "arm966e.h" + +#include "arm7_9_common.h" +#include "register.h" +#include "target.h" +#include "armv4_5.h" +#include "embeddedice.h" +#include "log.h" +#include "jtag.h" +#include "arm_jtag.h" + +#include <stdlib.h> +#include <string.h> + +#if 0 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + +/* cli handling */ +int arm966e_register_commands(struct command_context_s *cmd_ctx); + +/* forward declarations */ +int arm966e_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int arm966e_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int arm966e_quit(void); + +target_type_t arm966e_target = +{ + .name = "arm966e", + + .poll = arm7_9_poll, + .arch_state = armv4_5_arch_state, + + .target_request_data = arm7_9_target_request_data, + + .halt = arm7_9_halt, + .resume = arm7_9_resume, + .step = arm7_9_step, + + .assert_reset = arm7_9_assert_reset, + .deassert_reset = arm7_9_deassert_reset, + .soft_reset_halt = arm7_9_soft_reset_halt, + .prepare_reset_halt = arm7_9_prepare_reset_halt, + + .get_gdb_reg_list = armv4_5_get_gdb_reg_list, + + .read_memory = arm7_9_read_memory, + .write_memory = arm7_9_write_memory, + .bulk_write_memory = arm7_9_bulk_write_memory, + .checksum_memory = arm7_9_checksum_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, + .remove_watchpoint = arm7_9_remove_watchpoint, + + .register_commands = arm966e_register_commands, + .target_command = arm966e_target_command, + .init_target = arm966e_init_target, + .quit = arm966e_quit, +}; + +int arm966e_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + arm9tdmi_init_target(cmd_ctx, target); + + return ERROR_OK; +} + +int arm966e_quit(void) +{ + + return ERROR_OK; +} + +int arm966e_init_arch_info(target_t *target, arm966e_common_t *arm966e, int chain_pos, char *variant) +{ + arm9tdmi_common_t *arm9tdmi = &arm966e->arm9tdmi_common; + arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common; + + arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant); + + arm9tdmi->arch_info = arm966e; + arm966e->common_magic = ARM966E_COMMON_MAGIC; + + /* The ARM966E-S implements the ARMv5TE architecture which + * has the BKPT instruction, so we don't have to use a watchpoint comparator + */ + arm7_9->arm_bkpt = ARMV5_BKPT(0x0); + arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; + + arm7_9->sw_bkpts_use_wp = 0; + arm7_9->sw_bkpts_enabled = 1; + + return ERROR_OK; +} + +int arm966e_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + int chain_pos; + char *variant = NULL; + arm966e_common_t *arm966e = malloc(sizeof(arm966e_common_t)); + + if (argc < 4) + { + ERROR("'target arm966e' requires at least one additional argument"); + exit(-1); + } + + chain_pos = strtoul(args[3], NULL, 0); + + if (argc >= 5) + variant = args[4]; + + DEBUG("chain_pos: %i, variant: %s", chain_pos, variant); + + arm966e_init_arch_info(target, arm966e, chain_pos, variant); + + return ERROR_OK; +} + +int arm966e_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p, arm966e_common_t **arm966e_p) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm966e_common_t *arm966e; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + return -1; + } + + arm7_9 = armv4_5->arch_info; + if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC) + { + return -1; + } + + arm9tdmi = arm7_9->arch_info; + if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC) + { + return -1; + } + + arm966e = arm9tdmi->arch_info; + if (arm966e->common_magic != ARM966E_COMMON_MAGIC) + { + return -1; + } + + *armv4_5_p = armv4_5; + *arm7_9_p = arm7_9; + *arm9tdmi_p = arm9tdmi; + *arm966e_p = arm966e; + + return ERROR_OK; +} + +int arm966e_read_cp15(target_t *target, int reg_addr, u32 *value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + scan_field_t fields[3]; + u8 reg_addr_buf = reg_addr & 0x3f; + u8 nr_w_buf = 0; + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 6; + fields[1].out_value = ®_addr_buf; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = &nr_w_buf; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + fields[0].in_handler_priv = value; + fields[0].in_handler = arm_jtag_buf_to_u32; + + jtag_add_dr_scan(3, fields, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + jtag_execute_queue(); + DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value); +#endif + + return ERROR_OK; +} + +int arm966e_write_cp15(target_t *target, int reg_addr, u32 value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + scan_field_t fields[3]; + u8 reg_addr_buf = reg_addr & 0x3f; + u8 nr_w_buf = 1; + u8 value_buf[4]; + + buf_set_u32(value_buf, 0, 32, value); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = value_buf; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 6; + fields[1].out_value = ®_addr_buf; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = &nr_w_buf; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); +#endif + + return ERROR_OK; +} + +int arm966e_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm966e_common_t *arm966e; + arm_jtag_t *jtag_info; + + if (arm966e_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm966e) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM966e target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + /* one or more argument, access a single register (write if second argument is given */ + if (argc >= 1) + { + int address = strtoul(args[0], NULL, 0); + + if (argc == 1) + { + u32 value; + if ((retval = arm966e_read_cp15(target, address, &value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access reg %i", address); + return ERROR_OK; + } + jtag_execute_queue(); + + command_print(cmd_ctx, "%i: %8.8x", address, value); + } + else if (argc == 2) + { + u32 value = strtoul(args[1], NULL, 0); + if ((retval = arm966e_write_cp15(target, address, value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access reg %i", address); + return ERROR_OK; + } + command_print(cmd_ctx, "%i: %8.8x", address, value); + } + } + + return ERROR_OK; +} + +int arm966e_register_commands(struct command_context_s *cmd_ctx) +{ + int retval; + command_t *arm966e_cmd; + + retval = arm9tdmi_register_commands(cmd_ctx); + arm966e_cmd = register_command(cmd_ctx, NULL, "arm966e", NULL, COMMAND_ANY, "arm966e specific commands"); + register_command(cmd_ctx, arm966e_cmd, "cp15", arm966e_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register <num> [value]"); + + return ERROR_OK; +} diff --git a/src/target/arm9tdmi.c b/src/target/arm9tdmi.c index 7170693..595790b 100644 --- a/src/target/arm9tdmi.c +++ b/src/target/arm9tdmi.c @@ -1,1105 +1,1105 @@ -/***************************************************************************
- * 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 "arm9tdmi.h"
-
-#include "arm7_9_common.h"
-#include "register.h"
-#include "target.h"
-#include "armv4_5.h"
-#include "embeddedice.h"
-#include "etm.h"
-#include "etb.h"
-#include "log.h"
-#include "jtag.h"
-#include "arm_jtag.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#if 0
-#define _DEBUG_INSTRUCTION_EXECUTION_
-#endif
-
-/* cli handling */
-int arm9tdmi_register_commands(struct command_context_s *cmd_ctx);
-int handle_arm9tdmi_catch_vectors_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-/* forward declarations */
-int arm9tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
-int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
-int arm9tdmi_quit();
-
-target_type_t arm9tdmi_target =
-{
- .name = "arm9tdmi",
-
- .poll = arm7_9_poll,
- .arch_state = armv4_5_arch_state,
-
- .target_request_data = arm7_9_target_request_data,
-
- .halt = arm7_9_halt,
- .resume = arm7_9_resume,
- .step = arm7_9_step,
-
- .assert_reset = arm7_9_assert_reset,
- .deassert_reset = arm7_9_deassert_reset,
- .soft_reset_halt = arm7_9_soft_reset_halt,
- .prepare_reset_halt = arm7_9_prepare_reset_halt,
-
- .get_gdb_reg_list = armv4_5_get_gdb_reg_list,
-
- .read_memory = arm7_9_read_memory,
- .write_memory = arm7_9_write_memory,
- .bulk_write_memory = arm7_9_bulk_write_memory,
- .checksum_memory = arm7_9_checksum_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,
- .remove_watchpoint = arm7_9_remove_watchpoint,
-
- .register_commands = arm9tdmi_register_commands,
- .target_command = arm9tdmi_target_command,
- .init_target = arm9tdmi_init_target,
- .quit = arm9tdmi_quit
-};
-
-arm9tdmi_vector_t arm9tdmi_vectors[] =
-{
- {"reset", ARM9TDMI_RESET_VECTOR},
- {"undef", ARM9TDMI_UNDEF_VECTOR},
- {"swi", ARM9TDMI_SWI_VECTOR},
- {"pabt", ARM9TDMI_PABT_VECTOR},
- {"dabt", ARM9TDMI_DABT_VECTOR},
- {"reserved", ARM9TDMI_RESERVED_VECTOR},
- {"irq", ARM9TDMI_IRQ_VECTOR},
- {"fiq", ARM9TDMI_FIQ_VECTOR},
- {0, 0},
-};
-
-int arm9tdmi_examine_debug_reason(target_t *target)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
-
- /* only check the debug reason if we don't know it already */
- if ((target->debug_reason != DBG_REASON_DBGRQ)
- && (target->debug_reason != DBG_REASON_SINGLESTEP))
- {
- scan_field_t fields[3];
- u8 databus[4];
- u8 instructionbus[4];
- u8 debug_reason;
-
- jtag_add_end_state(TAP_PD);
-
- fields[0].device = arm7_9->jtag_info.chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = NULL;
- fields[0].out_mask = NULL;
- fields[0].in_value = databus;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = arm7_9->jtag_info.chain_pos;
- fields[1].num_bits = 3;
- fields[1].out_value = NULL;
- fields[1].out_mask = NULL;
- fields[1].in_value = &debug_reason;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = arm7_9->jtag_info.chain_pos;
- fields[2].num_bits = 32;
- fields[2].out_value = NULL;
- fields[2].out_mask = NULL;
- fields[2].in_value = instructionbus;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- arm_jtag_scann(&arm7_9->jtag_info, 0x1);
- arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr, NULL);
-
- jtag_add_dr_scan(3, fields, TAP_PD);
- jtag_execute_queue();
-
- fields[0].in_value = NULL;
- fields[0].out_value = databus;
- fields[1].in_value = NULL;
- fields[1].out_value = &debug_reason;
- fields[2].in_value = NULL;
- fields[2].out_value = instructionbus;
-
- jtag_add_dr_scan(3, fields, TAP_PD);
-
- if (debug_reason & 0x4)
- if (debug_reason & 0x2)
- target->debug_reason = DBG_REASON_WPTANDBKPT;
- else
- target->debug_reason = DBG_REASON_WATCHPOINT;
- else
- target->debug_reason = DBG_REASON_BREAKPOINT;
- }
-
- return ERROR_OK;
-}
-
-/* put an instruction in the ARM9TDMI pipeline or write the data bus, and optionally read data */
-int arm9tdmi_clock_out(arm_jtag_t *jtag_info, u32 instr, u32 out, u32 *in, int sysspeed)
-{
- scan_field_t fields[3];
- u8 out_buf[4];
- u8 instr_buf[4];
- u8 sysspeed_buf = 0x0;
-
- /* prepare buffer */
- buf_set_u32(out_buf, 0, 32, out);
-
- buf_set_u32(instr_buf, 0, 32, flip_u32(instr, 32));
-
- if (sysspeed)
- buf_set_u32(&sysspeed_buf, 2, 1, 1);
-
- jtag_add_end_state(TAP_PD);
- arm_jtag_scann(jtag_info, 0x1);
-
- arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = out_buf;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- if (in)
- {
- fields[0].in_handler = arm_jtag_buf_to_u32;
- fields[0].in_handler_priv = in;
- }
- else
- {
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
- }
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 3;
- fields[1].out_value = &sysspeed_buf;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = jtag_info->chain_pos;
- fields[2].num_bits = 32;
- fields[2].out_value = instr_buf;
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- jtag_add_dr_scan(3, fields, -1);
-
- jtag_add_runtest(0, -1);
-
-#ifdef _DEBUG_INSTRUCTION_EXECUTION_
- {
- jtag_execute_queue();
-
- if (in)
- {
- DEBUG("instr: 0x%8.8x, out: 0x%8.8x, in: 0x%8.8x", instr, out, *in);
- }
- else
- DEBUG("instr: 0x%8.8x, out: 0x%8.8x", instr, out);
- }
-#endif
-
- return ERROR_OK;
-}
-
-/* just read data (instruction and data-out = don't care) */
-int arm9tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in)
-{
- scan_field_t fields[3];
-
- jtag_add_end_state(TAP_PD);
- arm_jtag_scann(jtag_info, 0x1);
-
- arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = NULL;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_handler = arm_jtag_buf_to_u32;
- fields[0].in_handler_priv = in;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 3;
- fields[1].out_value = NULL;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
-
- fields[2].device = jtag_info->chain_pos;
- fields[2].num_bits = 32;
- fields[2].out_value = NULL;
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- jtag_add_dr_scan(3, fields, -1);
-
- jtag_add_runtest(0, -1);
-
-#ifdef _DEBUG_INSTRUCTION_EXECUTION_
- {
- jtag_execute_queue();
-
- if (in)
- {
- DEBUG("in: 0x%8.8x", *in);
- }
- else
- {
- ERROR("BUG: called with in == NULL");
- }
- }
-#endif
-
- return ERROR_OK;
-}
-
-/* clock the target, and read the databus
- * the *in pointer points to a buffer where elements of 'size' bytes
- * are stored in big (be==1) or little (be==0) endianness
- */
-int arm9tdmi_clock_data_in_endianness(arm_jtag_t *jtag_info, void *in, int size, int be)
-{
- scan_field_t fields[3];
-
- jtag_add_end_state(TAP_PD);
- arm_jtag_scann(jtag_info, 0x1);
-
- arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = NULL;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- switch (size)
- {
- case 4:
- fields[0].in_handler = (be) ? arm_jtag_buf_to_be32 : arm_jtag_buf_to_le32;
- break;
- case 2:
- fields[0].in_handler = (be) ? arm_jtag_buf_to_be16 : arm_jtag_buf_to_le16;
- break;
- case 1:
- fields[0].in_handler = arm_jtag_buf_to_8;
- break;
- }
- fields[0].in_handler_priv = in;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 3;
- fields[1].out_value = NULL;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
-
- fields[2].device = jtag_info->chain_pos;
- fields[2].num_bits = 32;
- fields[2].out_value = NULL;
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- jtag_add_dr_scan(3, fields, -1);
-
- jtag_add_runtest(0, -1);
-
-#ifdef _DEBUG_INSTRUCTION_EXECUTION_
- {
- jtag_execute_queue();
-
- if (in)
- {
- DEBUG("in: 0x%8.8x", *in);
- }
- else
- {
- ERROR("BUG: called with in == NULL");
- }
- }
-#endif
-
- return ERROR_OK;
-}
-
-void arm9tdmi_change_to_arm(target_t *target, u32 *r0, u32 *pc)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* save r0 before using it and put system in ARM state
- * to allow common handling of ARM and THUMB debugging */
-
- /* fetch STR r0, [r0] */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
- /* STR r0, [r0] in Memory */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, r0, 0);
-
- /* MOV r0, r15 fetched, STR in Decode */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
- /* nothing fetched, STR r0, [r0] in Memory */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, pc, 0);
-
- /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0, NULL, 0);
- /* LDR in Decode */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
- /* LDR in Execute */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
- /* LDR in Memory (to account for interlock) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
-
- /* fetch BX */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), 0, NULL, 0);
- /* NOP fetched, BX in Decode, MOV in Execute */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
- /* NOP fetched, BX in Execute (1) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
-
- jtag_execute_queue();
-
- /* fix program counter:
- * MOV r0, r15 was the 5th instruction (+8)
- * reading PC in Thumb state gives address of instruction + 4
- */
- *pc -= 0xc;
-}
-
-void arm9tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16])
-{
- int i;
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* STMIA r0-15, [r0] at debug speed
- * register values will start to appear on 4th DCLK
- */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
-
- /* fetch NOP, STM in DECODE stage */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* fetch NOP, STM in EXECUTE stage (1st cycle) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
-
- for (i = 0; i <= 15; i++)
- {
- if (mask & (1 << i))
- /* nothing fetched, STM in MEMORY (i'th cycle) */
- arm9tdmi_clock_data_in(jtag_info, core_regs[i]);
- }
-
-}
-
-void arm9tdmi_read_core_regs_target_buffer(target_t *target, u32 mask, void* buffer, int size)
-{
- int i;
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
- int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0;
- u32 *buf_u32 = buffer;
- u16 *buf_u16 = buffer;
- u8 *buf_u8 = buffer;
-
- /* STMIA r0-15, [r0] at debug speed
- * register values will start to appear on 4th DCLK
- */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
-
- /* fetch NOP, STM in DECODE stage */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* fetch NOP, STM in EXECUTE stage (1st cycle) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
-
- for (i = 0; i <= 15; i++)
- {
- if (mask & (1 << i))
- /* nothing fetched, STM in MEMORY (i'th cycle) */
- switch (size)
- {
- case 4:
- arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be);
- break;
- case 2:
- arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be);
- break;
- case 1:
- arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be);
- break;
- }
- }
-
-}
-
-void arm9tdmi_read_xpsr(target_t *target, u32 *xpsr, int spsr)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* MRS r0, cpsr */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
-
- /* STR r0, [r15] */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), 0, NULL, 0);
- /* fetch NOP, STR in DECODE stage */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* fetch NOP, STR in EXECUTE stage (1st cycle) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* nothing fetched, STR in MEMORY */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, xpsr, 0);
-
-}
-
-void arm9tdmi_write_xpsr(target_t *target, u32 xpsr, int spsr)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- DEBUG("xpsr: %8.8x, spsr: %i", xpsr, spsr);
-
- /* MSR1 fetched */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0, NULL, 0);
- /* MSR2 fetched, MSR1 in DECODE */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0, NULL, 0);
- /* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0, NULL, 0);
- /* nothing fetched, MSR1 in EXECUTE (2) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* nothing fetched, MSR1 in EXECUTE (3) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0, NULL, 0);
- /* nothing fetched, MSR2 in EXECUTE (2) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* nothing fetched, MSR2 in EXECUTE (3) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* nothing fetched, MSR3 in EXECUTE (2) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* nothing fetched, MSR3 in EXECUTE (3) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* NOP fetched, MSR4 in EXECUTE (1) */
- /* last MSR writes flags, which takes only one cycle */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
-}
-
-void arm9tdmi_write_xpsr_im8(target_t *target, u8 xpsr_im, int rot, int spsr)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr);
-
- /* MSR fetched */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0, NULL, 0);
- /* NOP fetched, MSR in DECODE */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* NOP fetched, MSR in EXECUTE (1) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
-
- /* rot == 4 writes flags, which takes only one cycle */
- if (rot != 4)
- {
- /* nothing fetched, MSR in EXECUTE (2) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* nothing fetched, MSR in EXECUTE (3) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- }
-}
-
-void arm9tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16])
-{
- int i;
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* LDMIA r0-15, [r0] at debug speed
- * register values will start to appear on 4th DCLK
- */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0);
-
- /* fetch NOP, LDM in DECODE stage */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* fetch NOP, LDM in EXECUTE stage (1st cycle) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
-
- for (i = 0; i <= 15; i++)
- {
- if (mask & (1 << i))
- /* nothing fetched, LDM still in EXECUTE (1+i cycle) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, core_regs[i], NULL, 0);
- }
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
-
-}
-
-void arm9tdmi_load_word_regs(target_t *target, u32 mask)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* put system-speed load-multiple into the pipeline */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
-
-}
-
-void arm9tdmi_load_hword_reg(target_t *target, int num)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* put system-speed load half-word into the pipeline */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
-}
-
-void arm9tdmi_load_byte_reg(target_t *target, int num)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* put system-speed load byte into the pipeline */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
-
-}
-
-void arm9tdmi_store_word_regs(target_t *target, u32 mask)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* put system-speed store-multiple into the pipeline */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
-
-}
-
-void arm9tdmi_store_hword_reg(target_t *target, int num)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* put system-speed store half-word into the pipeline */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
-
-}
-
-void arm9tdmi_store_byte_reg(target_t *target, int num)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* put system-speed store byte into the pipeline */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
-
-}
-
-void arm9tdmi_write_pc(target_t *target, u32 pc)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- /* LDMIA r0-15, [r0] at debug speed
- * register values will start to appear on 4th DCLK
- */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), 0, NULL, 0);
-
- /* fetch NOP, LDM in DECODE stage */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* fetch NOP, LDM in EXECUTE stage (1st cycle) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* nothing fetched, LDM in EXECUTE stage (2nd cycle) (output data) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, pc, NULL, 0);
- /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* fetch NOP, LDM in EXECUTE stage (4th cycle) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* fetch NOP, LDM in EXECUTE stage (5th cycle) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
-
-}
-
-void arm9tdmi_branch_resume(target_t *target)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- arm9tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffffc, 0), 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1);
-
-}
-
-void arm9tdmi_branch_resume_thumb(target_t *target)
-{
- DEBUG("-");
-
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
- reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT];
-
- /* LDMIA r0-15, [r0] at debug speed
- * register values will start to appear on 4th DCLK
- */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), 0, NULL, 0);
-
- /* fetch NOP, LDM in DECODE stage */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* fetch NOP, LDM in EXECUTE stage (1st cycle) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
- /* nothing fetched, LDM in EXECUTE stage (2nd cycle) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) | 1, NULL, 0);
- /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
-
- /* Branch and eXchange */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_BX(0), 0, NULL, 0);
-
- embeddedice_read_reg(dbg_stat);
-
- /* fetch NOP, BX in DECODE stage */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
-
- embeddedice_read_reg(dbg_stat);
-
- /* fetch NOP, BX in EXECUTE stage (1st cycle) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0);
-
- /* target is now in Thumb state */
- embeddedice_read_reg(dbg_stat);
-
- /* load r0 value, MOV_IM in Decode*/
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0, NULL, 0);
- /* fetch NOP, LDR in Decode, MOV_IM in Execute */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
- /* fetch NOP, LDR in Execute */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
- /* nothing fetched, LDR in EXECUTE stage (2nd cycle) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32), NULL, 0);
- /* nothing fetched, LDR in EXECUTE stage (3rd cycle) */
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
-
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
-
- embeddedice_read_reg(dbg_stat);
-
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f7), 0, NULL, 1);
- arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0);
-
-}
-
-void arm9tdmi_enable_single_step(target_t *target)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
-
- if (arm7_9->has_single_step)
- {
- buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 1);
- embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]);
- }
- else
- {
- arm7_9_enable_eice_step(target);
- }
-}
-
-void arm9tdmi_disable_single_step(target_t *target)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
-
- if (arm7_9->has_single_step)
- {
- buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 0);
- embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]);
- }
- else
- {
- arm7_9_disable_eice_step(target);
- }
-}
-
-void arm9tdmi_build_reg_cache(target_t *target)
-{
- reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache);
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9 = armv4_5->arch_info;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
-
- (*cache_p) = armv4_5_build_reg_cache(target, armv4_5);
- armv4_5->core_cache = (*cache_p);
-
- /* one extra register (vector catch) */
- (*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9);
- arm7_9->eice_cache = (*cache_p)->next;
-
- if (arm7_9->etm_ctx)
- {
- (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx);
- arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next;
- }
-}
-
-int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
-{
-
- arm9tdmi_build_reg_cache(target);
-
- return ERROR_OK;
-
-}
-
-int arm9tdmi_quit()
-{
-
- return ERROR_OK;
-}
-
-int arm9tdmi_init_arch_info(target_t *target, arm9tdmi_common_t *arm9tdmi, int chain_pos, char *variant)
-{
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
-
- arm7_9 = &arm9tdmi->arm7_9_common;
- armv4_5 = &arm7_9->armv4_5_common;
-
- /* prepare JTAG information for the new target */
- arm7_9->jtag_info.chain_pos = chain_pos;
- arm7_9->jtag_info.scann_size = 5;
-
- /* register arch-specific functions */
- arm7_9->examine_debug_reason = arm9tdmi_examine_debug_reason;
- arm7_9->change_to_arm = arm9tdmi_change_to_arm;
- arm7_9->read_core_regs = arm9tdmi_read_core_regs;
- arm7_9->read_core_regs_target_buffer = arm9tdmi_read_core_regs_target_buffer;
- arm7_9->read_xpsr = arm9tdmi_read_xpsr;
-
- arm7_9->write_xpsr = arm9tdmi_write_xpsr;
- arm7_9->write_xpsr_im8 = arm9tdmi_write_xpsr_im8;
- arm7_9->write_core_regs = arm9tdmi_write_core_regs;
-
- arm7_9->load_word_regs = arm9tdmi_load_word_regs;
- arm7_9->load_hword_reg = arm9tdmi_load_hword_reg;
- arm7_9->load_byte_reg = arm9tdmi_load_byte_reg;
-
- arm7_9->store_word_regs = arm9tdmi_store_word_regs;
- arm7_9->store_hword_reg = arm9tdmi_store_hword_reg;
- arm7_9->store_byte_reg = arm9tdmi_store_byte_reg;
-
- arm7_9->write_pc = arm9tdmi_write_pc;
- arm7_9->branch_resume = arm9tdmi_branch_resume;
- arm7_9->branch_resume_thumb = arm9tdmi_branch_resume_thumb;
-
- arm7_9->enable_single_step = arm9tdmi_enable_single_step;
- arm7_9->disable_single_step = arm9tdmi_disable_single_step;
-
- arm7_9->pre_debug_entry = NULL;
- arm7_9->post_debug_entry = NULL;
-
- arm7_9->pre_restore_context = NULL;
- arm7_9->post_restore_context = NULL;
-
- /* initialize arch-specific breakpoint handling */
- arm7_9->arm_bkpt = 0xdeeedeee;
- arm7_9->thumb_bkpt = 0xdeee;
-
- arm7_9->sw_bkpts_use_wp = 1;
- arm7_9->sw_bkpts_enabled = 0;
- arm7_9->dbgreq_adjust_pc = 3;
- arm7_9->arch_info = arm9tdmi;
-
- arm9tdmi->common_magic = ARM9TDMI_COMMON_MAGIC;
- arm9tdmi->arch_info = NULL;
-
- if (variant)
- {
- arm9tdmi->variant = strdup(variant);
- }
- else
- {
- arm9tdmi->variant = strdup("");
- }
-
- arm7_9_init_arch_info(target, arm7_9);
-
- /* override use of DBGRQ, this is safe on ARM9TDMI */
- arm7_9->use_dbgrq = 1;
-
- /* all ARM9s have the vector catch register */
- arm7_9->has_vector_catch = 1;
-
- return ERROR_OK;
-}
-
-int arm9tdmi_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
-
- if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
- {
- return -1;
- }
-
- arm7_9 = armv4_5->arch_info;
- if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC)
- {
- return -1;
- }
-
- arm9tdmi = arm7_9->arch_info;
- if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC)
- {
- return -1;
- }
-
- *armv4_5_p = armv4_5;
- *arm7_9_p = arm7_9;
- *arm9tdmi_p = arm9tdmi;
-
- return ERROR_OK;
-}
-
-
-/* target arm9tdmi <endianess> <startup_mode> <chain_pos> <variant>*/
-int arm9tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
-{
- int chain_pos;
- char *variant = NULL;
- arm9tdmi_common_t *arm9tdmi = malloc(sizeof(arm9tdmi_common_t));
-
- if (argc < 4)
- {
- ERROR("'target arm9tdmi' requires at least one additional argument");
- exit(-1);
- }
-
- chain_pos = strtoul(args[3], NULL, 0);
-
- if (argc >= 5)
- variant = args[4];
-
- arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant);
-
- return ERROR_OK;
-}
-
-int arm9tdmi_register_commands(struct command_context_s *cmd_ctx)
-{
- int retval;
-
- command_t *arm9tdmi_cmd;
-
-
- retval = arm7_9_register_commands(cmd_ctx);
-
- arm9tdmi_cmd = register_command(cmd_ctx, NULL, "arm9tdmi", NULL, COMMAND_ANY, "arm9tdmi specific commands");
-
- register_command(cmd_ctx, arm9tdmi_cmd, "vector_catch", handle_arm9tdmi_catch_vectors_command, COMMAND_EXEC, "catch arm920t vectors ['all'|'none'|'<vec1 vec2 ...>']");
-
-
- return ERROR_OK;
-
-}
-
-int handle_arm9tdmi_catch_vectors_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- arm9tdmi_common_t *arm9tdmi;
- reg_t *vector_catch;
- u32 vector_catch_value;
- int i, j;
-
- if (arm9tdmi_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM9TDMI based target");
- return ERROR_OK;
- }
-
- vector_catch = &arm7_9->eice_cache->reg_list[EICE_VEC_CATCH];
-
- /* read the vector catch register if necessary */
- if (!vector_catch->valid)
- embeddedice_read_reg(vector_catch);
-
- /* get the current setting */
- vector_catch_value = buf_get_u32(vector_catch->value, 0, 32);
-
- if (argc > 0)
- {
- vector_catch_value = 0x0;
- if (strcmp(args[0], "all") == 0)
- {
- vector_catch_value = 0xdf;
- }
- else if (strcmp(args[0], "none") == 0)
- {
- /* do nothing */
- }
- else
- {
- for (i = 0; i < argc; i++)
- {
- /* go through list of vectors */
- for(j = 0; arm9tdmi_vectors[j].name; j++)
- {
- if (strcmp(args[i], arm9tdmi_vectors[j].name) == 0)
- {
- vector_catch_value |= arm9tdmi_vectors[j].value;
- break;
- }
- }
-
- /* complain if vector wasn't found */
- if (!arm9tdmi_vectors[j].name)
- {
- command_print(cmd_ctx, "vector '%s' not found, leaving current setting unchanged", args[i]);
-
- /* reread current setting */
- vector_catch_value = buf_get_u32(vector_catch->value, 0, 32);
-
- break;
- }
- }
- }
-
- /* store new settings */
- buf_set_u32(vector_catch->value, 0, 32, vector_catch_value);
- embeddedice_store_reg(vector_catch);
- }
-
- /* output current settings (skip RESERVED vector) */
- for (i = 0; i < 8; i++)
- {
- if (i != 5)
- {
- command_print(cmd_ctx, "%s: %s", arm9tdmi_vectors[i].name,
- (vector_catch_value & (1 << i)) ? "catch" : "don't catch");
- }
- }
-
- return ERROR_OK;
-}
+/*************************************************************************** + * 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 "arm9tdmi.h" + +#include "arm7_9_common.h" +#include "register.h" +#include "target.h" +#include "armv4_5.h" +#include "embeddedice.h" +#include "etm.h" +#include "etb.h" +#include "log.h" +#include "jtag.h" +#include "arm_jtag.h" + +#include <stdlib.h> +#include <string.h> + +#if 0 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + +/* cli handling */ +int arm9tdmi_register_commands(struct command_context_s *cmd_ctx); +int handle_arm9tdmi_catch_vectors_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +/* forward declarations */ +int arm9tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int arm9tdmi_quit(); + +target_type_t arm9tdmi_target = +{ + .name = "arm9tdmi", + + .poll = arm7_9_poll, + .arch_state = armv4_5_arch_state, + + .target_request_data = arm7_9_target_request_data, + + .halt = arm7_9_halt, + .resume = arm7_9_resume, + .step = arm7_9_step, + + .assert_reset = arm7_9_assert_reset, + .deassert_reset = arm7_9_deassert_reset, + .soft_reset_halt = arm7_9_soft_reset_halt, + .prepare_reset_halt = arm7_9_prepare_reset_halt, + + .get_gdb_reg_list = armv4_5_get_gdb_reg_list, + + .read_memory = arm7_9_read_memory, + .write_memory = arm7_9_write_memory, + .bulk_write_memory = arm7_9_bulk_write_memory, + .checksum_memory = arm7_9_checksum_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, + .remove_watchpoint = arm7_9_remove_watchpoint, + + .register_commands = arm9tdmi_register_commands, + .target_command = arm9tdmi_target_command, + .init_target = arm9tdmi_init_target, + .quit = arm9tdmi_quit +}; + +arm9tdmi_vector_t arm9tdmi_vectors[] = +{ + {"reset", ARM9TDMI_RESET_VECTOR}, + {"undef", ARM9TDMI_UNDEF_VECTOR}, + {"swi", ARM9TDMI_SWI_VECTOR}, + {"pabt", ARM9TDMI_PABT_VECTOR}, + {"dabt", ARM9TDMI_DABT_VECTOR}, + {"reserved", ARM9TDMI_RESERVED_VECTOR}, + {"irq", ARM9TDMI_IRQ_VECTOR}, + {"fiq", ARM9TDMI_FIQ_VECTOR}, + {0, 0}, +}; + +int arm9tdmi_examine_debug_reason(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + + /* only check the debug reason if we don't know it already */ + if ((target->debug_reason != DBG_REASON_DBGRQ) + && (target->debug_reason != DBG_REASON_SINGLESTEP)) + { + scan_field_t fields[3]; + u8 databus[4]; + u8 instructionbus[4]; + u8 debug_reason; + + jtag_add_end_state(TAP_PD); + + fields[0].device = arm7_9->jtag_info.chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = databus; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = arm7_9->jtag_info.chain_pos; + fields[1].num_bits = 3; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = &debug_reason; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = arm7_9->jtag_info.chain_pos; + fields[2].num_bits = 32; + fields[2].out_value = NULL; + fields[2].out_mask = NULL; + fields[2].in_value = instructionbus; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + arm_jtag_scann(&arm7_9->jtag_info, 0x1); + arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr, NULL); + + jtag_add_dr_scan(3, fields, TAP_PD); + jtag_execute_queue(); + + fields[0].in_value = NULL; + fields[0].out_value = databus; + fields[1].in_value = NULL; + fields[1].out_value = &debug_reason; + fields[2].in_value = NULL; + fields[2].out_value = instructionbus; + + jtag_add_dr_scan(3, fields, TAP_PD); + + if (debug_reason & 0x4) + if (debug_reason & 0x2) + target->debug_reason = DBG_REASON_WPTANDBKPT; + else + target->debug_reason = DBG_REASON_WATCHPOINT; + else + target->debug_reason = DBG_REASON_BREAKPOINT; + } + + return ERROR_OK; +} + +/* put an instruction in the ARM9TDMI pipeline or write the data bus, and optionally read data */ +int arm9tdmi_clock_out(arm_jtag_t *jtag_info, u32 instr, u32 out, u32 *in, int sysspeed) +{ + scan_field_t fields[3]; + u8 out_buf[4]; + u8 instr_buf[4]; + u8 sysspeed_buf = 0x0; + + /* prepare buffer */ + buf_set_u32(out_buf, 0, 32, out); + + buf_set_u32(instr_buf, 0, 32, flip_u32(instr, 32)); + + if (sysspeed) + buf_set_u32(&sysspeed_buf, 2, 1, 1); + + jtag_add_end_state(TAP_PD); + arm_jtag_scann(jtag_info, 0x1); + + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = out_buf; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + if (in) + { + fields[0].in_handler = arm_jtag_buf_to_u32; + fields[0].in_handler_priv = in; + } + else + { + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + } + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 3; + fields[1].out_value = &sysspeed_buf; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 32; + fields[2].out_value = instr_buf; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + jtag_add_runtest(0, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + { + jtag_execute_queue(); + + if (in) + { + DEBUG("instr: 0x%8.8x, out: 0x%8.8x, in: 0x%8.8x", instr, out, *in); + } + else + DEBUG("instr: 0x%8.8x, out: 0x%8.8x", instr, out); + } +#endif + + return ERROR_OK; +} + +/* just read data (instruction and data-out = don't care) */ +int arm9tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in) +{ + scan_field_t fields[3]; + + jtag_add_end_state(TAP_PD); + arm_jtag_scann(jtag_info, 0x1); + + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_handler = arm_jtag_buf_to_u32; + fields[0].in_handler_priv = in; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 3; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 32; + fields[2].out_value = NULL; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + jtag_add_runtest(0, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + { + jtag_execute_queue(); + + if (in) + { + DEBUG("in: 0x%8.8x", *in); + } + else + { + ERROR("BUG: called with in == NULL"); + } + } +#endif + + return ERROR_OK; +} + +/* clock the target, and read the databus + * the *in pointer points to a buffer where elements of 'size' bytes + * are stored in big (be==1) or little (be==0) endianness + */ +int arm9tdmi_clock_data_in_endianness(arm_jtag_t *jtag_info, void *in, int size, int be) +{ + scan_field_t fields[3]; + + jtag_add_end_state(TAP_PD); + arm_jtag_scann(jtag_info, 0x1); + + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + switch (size) + { + case 4: + fields[0].in_handler = (be) ? arm_jtag_buf_to_be32 : arm_jtag_buf_to_le32; + break; + case 2: + fields[0].in_handler = (be) ? arm_jtag_buf_to_be16 : arm_jtag_buf_to_le16; + break; + case 1: + fields[0].in_handler = arm_jtag_buf_to_8; + break; + } + fields[0].in_handler_priv = in; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 3; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 32; + fields[2].out_value = NULL; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + jtag_add_runtest(0, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + { + jtag_execute_queue(); + + if (in) + { + DEBUG("in: 0x%8.8x", *in); + } + else + { + ERROR("BUG: called with in == NULL"); + } + } +#endif + + return ERROR_OK; +} + +void arm9tdmi_change_to_arm(target_t *target, u32 *r0, u32 *pc) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* save r0 before using it and put system in ARM state + * to allow common handling of ARM and THUMB debugging */ + + /* fetch STR r0, [r0] */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + /* STR r0, [r0] in Memory */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, r0, 0); + + /* MOV r0, r15 fetched, STR in Decode */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + /* nothing fetched, STR r0, [r0] in Memory */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, pc, 0); + + /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0, NULL, 0); + /* LDR in Decode */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + /* LDR in Execute */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + /* LDR in Memory (to account for interlock) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + + /* fetch BX */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), 0, NULL, 0); + /* NOP fetched, BX in Decode, MOV in Execute */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + /* NOP fetched, BX in Execute (1) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + + jtag_execute_queue(); + + /* fix program counter: + * MOV r0, r15 was the 5th instruction (+8) + * reading PC in Thumb state gives address of instruction + 4 + */ + *pc -= 0xc; +} + +void arm9tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16]) +{ + int i; + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* STMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); + + /* fetch NOP, STM in DECODE stage */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* fetch NOP, STM in EXECUTE stage (1st cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + + for (i = 0; i <= 15; i++) + { + if (mask & (1 << i)) + /* nothing fetched, STM in MEMORY (i'th cycle) */ + arm9tdmi_clock_data_in(jtag_info, core_regs[i]); + } + +} + +void arm9tdmi_read_core_regs_target_buffer(target_t *target, u32 mask, void* buffer, int size) +{ + int i; + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; + u32 *buf_u32 = buffer; + u16 *buf_u16 = buffer; + u8 *buf_u8 = buffer; + + /* STMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); + + /* fetch NOP, STM in DECODE stage */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* fetch NOP, STM in EXECUTE stage (1st cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + + for (i = 0; i <= 15; i++) + { + if (mask & (1 << i)) + /* nothing fetched, STM in MEMORY (i'th cycle) */ + switch (size) + { + case 4: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); + break; + case 2: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); + break; + case 1: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); + break; + } + } + +} + +void arm9tdmi_read_xpsr(target_t *target, u32 *xpsr, int spsr) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* MRS r0, cpsr */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + + /* STR r0, [r15] */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), 0, NULL, 0); + /* fetch NOP, STR in DECODE stage */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* fetch NOP, STR in EXECUTE stage (1st cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* nothing fetched, STR in MEMORY */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, xpsr, 0); + +} + +void arm9tdmi_write_xpsr(target_t *target, u32 xpsr, int spsr) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + DEBUG("xpsr: %8.8x, spsr: %i", xpsr, spsr); + + /* MSR1 fetched */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0, NULL, 0); + /* MSR2 fetched, MSR1 in DECODE */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0, NULL, 0); + /* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0, NULL, 0); + /* nothing fetched, MSR1 in EXECUTE (2) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* nothing fetched, MSR1 in EXECUTE (3) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0, NULL, 0); + /* nothing fetched, MSR2 in EXECUTE (2) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* nothing fetched, MSR2 in EXECUTE (3) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* nothing fetched, MSR3 in EXECUTE (2) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* nothing fetched, MSR3 in EXECUTE (3) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* NOP fetched, MSR4 in EXECUTE (1) */ + /* last MSR writes flags, which takes only one cycle */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); +} + +void arm9tdmi_write_xpsr_im8(target_t *target, u8 xpsr_im, int rot, int spsr) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr); + + /* MSR fetched */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0, NULL, 0); + /* NOP fetched, MSR in DECODE */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* NOP fetched, MSR in EXECUTE (1) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + + /* rot == 4 writes flags, which takes only one cycle */ + if (rot != 4) + { + /* nothing fetched, MSR in EXECUTE (2) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* nothing fetched, MSR in EXECUTE (3) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + } +} + +void arm9tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16]) +{ + int i; + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* LDMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); + + /* fetch NOP, LDM in DECODE stage */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + + for (i = 0; i <= 15; i++) + { + if (mask & (1 << i)) + /* nothing fetched, LDM still in EXECUTE (1+i cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, core_regs[i], NULL, 0); + } + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + +} + +void arm9tdmi_load_word_regs(target_t *target, u32 mask) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed load-multiple into the pipeline */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); + +} + +void arm9tdmi_load_hword_reg(target_t *target, int num) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed load half-word into the pipeline */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); +} + +void arm9tdmi_load_byte_reg(target_t *target, int num) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed load byte into the pipeline */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); + +} + +void arm9tdmi_store_word_regs(target_t *target, u32 mask) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed store-multiple into the pipeline */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); + +} + +void arm9tdmi_store_hword_reg(target_t *target, int num) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed store half-word into the pipeline */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); + +} + +void arm9tdmi_store_byte_reg(target_t *target, int num) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed store byte into the pipeline */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); + +} + +void arm9tdmi_write_pc(target_t *target, u32 pc) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* LDMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), 0, NULL, 0); + + /* fetch NOP, LDM in DECODE stage */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (2nd cycle) (output data) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, pc, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (4th cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (5th cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + +} + +void arm9tdmi_branch_resume(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + arm9tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffffc, 0), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); + +} + +void arm9tdmi_branch_resume_thumb(target_t *target) +{ + DEBUG("-"); + + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; + + /* LDMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), 0, NULL, 0); + + /* fetch NOP, LDM in DECODE stage */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (2nd cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) | 1, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + + /* Branch and eXchange */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_BX(0), 0, NULL, 0); + + embeddedice_read_reg(dbg_stat); + + /* fetch NOP, BX in DECODE stage */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + + embeddedice_read_reg(dbg_stat); + + /* fetch NOP, BX in EXECUTE stage (1st cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + + /* target is now in Thumb state */ + embeddedice_read_reg(dbg_stat); + + /* load r0 value, MOV_IM in Decode*/ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0, NULL, 0); + /* fetch NOP, LDR in Decode, MOV_IM in Execute */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + /* fetch NOP, LDR in Execute */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + /* nothing fetched, LDR in EXECUTE stage (2nd cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32), NULL, 0); + /* nothing fetched, LDR in EXECUTE stage (3rd cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + + embeddedice_read_reg(dbg_stat); + + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f7), 0, NULL, 1); + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + +} + +void arm9tdmi_enable_single_step(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + + if (arm7_9->has_single_step) + { + buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 1); + embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]); + } + else + { + arm7_9_enable_eice_step(target); + } +} + +void arm9tdmi_disable_single_step(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + + if (arm7_9->has_single_step) + { + buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 0); + embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]); + } + else + { + arm7_9_disable_eice_step(target); + } +} + +void arm9tdmi_build_reg_cache(target_t *target) +{ + reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache); + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + (*cache_p) = armv4_5_build_reg_cache(target, armv4_5); + armv4_5->core_cache = (*cache_p); + + /* one extra register (vector catch) */ + (*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9); + arm7_9->eice_cache = (*cache_p)->next; + + if (arm7_9->etm_ctx) + { + (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx); + arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next; + } +} + +int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + + arm9tdmi_build_reg_cache(target); + + return ERROR_OK; + +} + +int arm9tdmi_quit() +{ + + return ERROR_OK; +} + +int arm9tdmi_init_arch_info(target_t *target, arm9tdmi_common_t *arm9tdmi, int chain_pos, char *variant) +{ + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + + arm7_9 = &arm9tdmi->arm7_9_common; + armv4_5 = &arm7_9->armv4_5_common; + + /* prepare JTAG information for the new target */ + arm7_9->jtag_info.chain_pos = chain_pos; + arm7_9->jtag_info.scann_size = 5; + + /* register arch-specific functions */ + arm7_9->examine_debug_reason = arm9tdmi_examine_debug_reason; + arm7_9->change_to_arm = arm9tdmi_change_to_arm; + arm7_9->read_core_regs = arm9tdmi_read_core_regs; + arm7_9->read_core_regs_target_buffer = arm9tdmi_read_core_regs_target_buffer; + arm7_9->read_xpsr = arm9tdmi_read_xpsr; + + arm7_9->write_xpsr = arm9tdmi_write_xpsr; + arm7_9->write_xpsr_im8 = arm9tdmi_write_xpsr_im8; + arm7_9->write_core_regs = arm9tdmi_write_core_regs; + + arm7_9->load_word_regs = arm9tdmi_load_word_regs; + arm7_9->load_hword_reg = arm9tdmi_load_hword_reg; + arm7_9->load_byte_reg = arm9tdmi_load_byte_reg; + + arm7_9->store_word_regs = arm9tdmi_store_word_regs; + arm7_9->store_hword_reg = arm9tdmi_store_hword_reg; + arm7_9->store_byte_reg = arm9tdmi_store_byte_reg; + + arm7_9->write_pc = arm9tdmi_write_pc; + arm7_9->branch_resume = arm9tdmi_branch_resume; + arm7_9->branch_resume_thumb = arm9tdmi_branch_resume_thumb; + + arm7_9->enable_single_step = arm9tdmi_enable_single_step; + arm7_9->disable_single_step = arm9tdmi_disable_single_step; + + arm7_9->pre_debug_entry = NULL; + arm7_9->post_debug_entry = NULL; + + arm7_9->pre_restore_context = NULL; + arm7_9->post_restore_context = NULL; + + /* initialize arch-specific breakpoint handling */ + arm7_9->arm_bkpt = 0xdeeedeee; + arm7_9->thumb_bkpt = 0xdeee; + + arm7_9->sw_bkpts_use_wp = 1; + arm7_9->sw_bkpts_enabled = 0; + arm7_9->dbgreq_adjust_pc = 3; + arm7_9->arch_info = arm9tdmi; + + arm9tdmi->common_magic = ARM9TDMI_COMMON_MAGIC; + arm9tdmi->arch_info = NULL; + + if (variant) + { + arm9tdmi->variant = strdup(variant); + } + else + { + arm9tdmi->variant = strdup(""); + } + + arm7_9_init_arch_info(target, arm7_9); + + /* override use of DBGRQ, this is safe on ARM9TDMI */ + arm7_9->use_dbgrq = 1; + + /* all ARM9s have the vector catch register */ + arm7_9->has_vector_catch = 1; + + return ERROR_OK; +} + +int arm9tdmi_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + return -1; + } + + arm7_9 = armv4_5->arch_info; + if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC) + { + return -1; + } + + arm9tdmi = arm7_9->arch_info; + if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC) + { + return -1; + } + + *armv4_5_p = armv4_5; + *arm7_9_p = arm7_9; + *arm9tdmi_p = arm9tdmi; + + return ERROR_OK; +} + + +/* target arm9tdmi <endianess> <startup_mode> <chain_pos> <variant>*/ +int arm9tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + int chain_pos; + char *variant = NULL; + arm9tdmi_common_t *arm9tdmi = malloc(sizeof(arm9tdmi_common_t)); + + if (argc < 4) + { + ERROR("'target arm9tdmi' requires at least one additional argument"); + exit(-1); + } + + chain_pos = strtoul(args[3], NULL, 0); + + if (argc >= 5) + variant = args[4]; + + arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant); + + return ERROR_OK; +} + +int arm9tdmi_register_commands(struct command_context_s *cmd_ctx) +{ + int retval; + + command_t *arm9tdmi_cmd; + + + retval = arm7_9_register_commands(cmd_ctx); + + arm9tdmi_cmd = register_command(cmd_ctx, NULL, "arm9tdmi", NULL, COMMAND_ANY, "arm9tdmi specific commands"); + + register_command(cmd_ctx, arm9tdmi_cmd, "vector_catch", handle_arm9tdmi_catch_vectors_command, COMMAND_EXEC, "catch arm920t vectors ['all'|'none'|'<vec1 vec2 ...>']"); + + + return ERROR_OK; + +} + +int handle_arm9tdmi_catch_vectors_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + reg_t *vector_catch; + u32 vector_catch_value; + int i, j; + + if (arm9tdmi_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM9TDMI based target"); + return ERROR_OK; + } + + vector_catch = &arm7_9->eice_cache->reg_list[EICE_VEC_CATCH]; + + /* read the vector catch register if necessary */ + if (!vector_catch->valid) + embeddedice_read_reg(vector_catch); + + /* get the current setting */ + vector_catch_value = buf_get_u32(vector_catch->value, 0, 32); + + if (argc > 0) + { + vector_catch_value = 0x0; + if (strcmp(args[0], "all") == 0) + { + vector_catch_value = 0xdf; + } + else if (strcmp(args[0], "none") == 0) + { + /* do nothing */ + } + else + { + for (i = 0; i < argc; i++) + { + /* go through list of vectors */ + for(j = 0; arm9tdmi_vectors[j].name; j++) + { + if (strcmp(args[i], arm9tdmi_vectors[j].name) == 0) + { + vector_catch_value |= arm9tdmi_vectors[j].value; + break; + } + } + + /* complain if vector wasn't found */ + if (!arm9tdmi_vectors[j].name) + { + command_print(cmd_ctx, "vector '%s' not found, leaving current setting unchanged", args[i]); + + /* reread current setting */ + vector_catch_value = buf_get_u32(vector_catch->value, 0, 32); + + break; + } + } + } + + /* store new settings */ + buf_set_u32(vector_catch->value, 0, 32, vector_catch_value); + embeddedice_store_reg(vector_catch); + } + + /* output current settings (skip RESERVED vector) */ + for (i = 0; i < 8; i++) + { + if (i != 5) + { + command_print(cmd_ctx, "%s: %s", arm9tdmi_vectors[i].name, + (vector_catch_value & (1 << i)) ? "catch" : "don't catch"); + } + } + + return ERROR_OK; +} diff --git a/src/target/arm_jtag.c b/src/target/arm_jtag.c index 08cf346..7a9e878 100644 --- a/src/target/arm_jtag.c +++ b/src/target/arm_jtag.c @@ -1,207 +1,207 @@ -/***************************************************************************
- * 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 "arm_jtag.h"
-
-#include "binarybuffer.h"
-#include "log.h"
-#include "jtag.h"
-
-#include <stdlib.h>
-
-#if 0
-#define _ARM_JTAG_SCAN_N_CHECK_
-#endif
-
-int arm_jtag_set_instr(arm_jtag_t *jtag_info, u32 new_instr, in_handler_t handler)
-{
- jtag_device_t *device = jtag_get_device(jtag_info->chain_pos);
-
- if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr)
- {
- scan_field_t field;
-
- field.device = jtag_info->chain_pos;
- field.num_bits = device->ir_length;
- field.out_value = calloc(CEIL(field.num_bits, 8), 1);
- buf_set_u32(field.out_value, 0, field.num_bits, new_instr);
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = handler;
- field.in_handler_priv = NULL;
- jtag_add_ir_scan(1, &field, -1);
-
-
- free(field.out_value);
- }
-
- return ERROR_OK;
-}
-
-int arm_jtag_scann(arm_jtag_t *jtag_info, u32 new_scan_chain)
-{
- if(jtag_info->cur_scan_chain != new_scan_chain)
- {
-#ifdef _ARM_JTAG_SCAN_N_CHECK_
- u8 scan_n_check_value = 1 << (jtag_info->scann_size - 1);
-#endif
- scan_field_t field;
-
- field.device = jtag_info->chain_pos;
- field.num_bits = jtag_info->scann_size;
- field.out_value = calloc(CEIL(field.num_bits, 8), 1);
- buf_set_u32(field.out_value, 0, field.num_bits, new_scan_chain);
- field.out_mask = NULL;
- field.in_value = NULL;
-#ifdef _ARM_JTAG_SCAN_N_CHECK_
- jtag_set_check_value(&field, &scan_n_check_value, NULL, NULL, NULL);
-#else
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-#endif
-
-
- arm_jtag_set_instr(jtag_info, jtag_info->scann_instr, NULL);
- jtag_add_dr_scan(1, &field, -1);
-
- jtag_info->cur_scan_chain = new_scan_chain;
-
- free(field.out_value);
- }
-
- return ERROR_OK;
-}
-
-int arm_jtag_reset_callback(enum jtag_event event, void *priv)
-{
- arm_jtag_t *jtag_info = priv;
-
- if (event == JTAG_TRST_ASSERTED)
- {
- jtag_info->cur_scan_chain = 0;
- }
-
- return ERROR_OK;
-}
-
-int arm_jtag_setup_connection(arm_jtag_t *jtag_info)
-{
- jtag_info->scann_instr = 0x2;
- jtag_info->cur_scan_chain = 0;
- jtag_info->intest_instr = 0xc;
-
- jtag_register_event_callback(arm_jtag_reset_callback, jtag_info);
-
- return ERROR_OK;
-}
-
-/* read JTAG buffer into host-endian u32, flipping bit-order */
-int arm_jtag_buf_to_u32_flip(u8 *in_buf, void *priv, struct scan_field_s *field)
-{
- u32 *dest = priv;
- *dest = flip_u32(le_to_h_u32(in_buf), 32);
- return ERROR_OK;
-}
-
-/* read JTAG buffer into little-endian u32, flipping bit-order */
-int arm_jtag_buf_to_le32_flip(u8 *in_buf, void *priv, struct scan_field_s *field)
-{
- h_u32_to_le(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32));
- return ERROR_OK;
-}
-
-/* read JTAG buffer into little-endian u16, flipping bit-order */
-int arm_jtag_buf_to_le16_flip(u8 *in_buf, void *priv, struct scan_field_s *field)
-{
- h_u16_to_le(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32) & 0xffff);
- return ERROR_OK;
-}
-
-/* read JTAG buffer into big-endian u32, flipping bit-order */
-int arm_jtag_buf_to_be32_flip(u8 *in_buf, void *priv, struct scan_field_s *field)
-{
- h_u32_to_be(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32));
- return ERROR_OK;
-}
-
-/* read JTAG buffer into big-endian u16, flipping bit-order */
-int arm_jtag_buf_to_be16_flip(u8 *in_buf, void *priv, struct scan_field_s *field)
-{
- h_u16_to_be(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32) & 0xffff);
- return ERROR_OK;
-}
-
-/* read JTAG buffer into u8, flipping bit-order */
-int arm_jtag_buf_to_8_flip(u8 *in_buf, void *priv, struct scan_field_s *field)
-{
- u8 *dest = priv;
- *dest = flip_u32(le_to_h_u32(in_buf), 32) & 0xff;
- return ERROR_OK;
-}
-
-/* not-flipping variants */
-/* read JTAG buffer into host-endian u32 */
-int arm_jtag_buf_to_u32(u8 *in_buf, void *priv, struct scan_field_s *field)
-{
- u32 *dest = priv;
- *dest = le_to_h_u32(in_buf);
- return ERROR_OK;
-}
-
-/* read JTAG buffer into little-endian u32 */
-int arm_jtag_buf_to_le32(u8 *in_buf, void *priv, struct scan_field_s *field)
-{
- h_u32_to_le(((u8*)priv), le_to_h_u32(in_buf));
- return ERROR_OK;
-}
-
-/* read JTAG buffer into little-endian u16 */
-int arm_jtag_buf_to_le16(u8 *in_buf, void *priv, struct scan_field_s *field)
-{
- h_u16_to_le(((u8*)priv), le_to_h_u32(in_buf) & 0xffff);
- return ERROR_OK;
-}
-
-/* read JTAG buffer into big-endian u32 */
-int arm_jtag_buf_to_be32(u8 *in_buf, void *priv, struct scan_field_s *field)
-{
- h_u32_to_be(((u8*)priv), le_to_h_u32(in_buf));
- return ERROR_OK;
-}
-
-/* read JTAG buffer into big-endian u16 */
-int arm_jtag_buf_to_be16(u8 *in_buf, void *priv, struct scan_field_s *field)
-{
- h_u16_to_be(((u8*)priv), le_to_h_u32(in_buf) & 0xffff);
- return ERROR_OK;
-}
-
-/* read JTAG buffer into u8 */
-int arm_jtag_buf_to_8(u8 *in_buf, void *priv, struct scan_field_s *field)
-{
- u8 *dest = priv;
- *dest = le_to_h_u32(in_buf) & 0xff;
- return ERROR_OK;
-}
+/*************************************************************************** + * 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 "arm_jtag.h" + +#include "binarybuffer.h" +#include "log.h" +#include "jtag.h" + +#include <stdlib.h> + +#if 0 +#define _ARM_JTAG_SCAN_N_CHECK_ +#endif + +int arm_jtag_set_instr(arm_jtag_t *jtag_info, u32 new_instr, in_handler_t handler) +{ + jtag_device_t *device = jtag_get_device(jtag_info->chain_pos); + + if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) + { + scan_field_t field; + + field.device = jtag_info->chain_pos; + field.num_bits = device->ir_length; + field.out_value = calloc(CEIL(field.num_bits, 8), 1); + buf_set_u32(field.out_value, 0, field.num_bits, new_instr); + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = handler; + field.in_handler_priv = NULL; + jtag_add_ir_scan(1, &field, -1); + + + free(field.out_value); + } + + return ERROR_OK; +} + +int arm_jtag_scann(arm_jtag_t *jtag_info, u32 new_scan_chain) +{ + if(jtag_info->cur_scan_chain != new_scan_chain) + { +#ifdef _ARM_JTAG_SCAN_N_CHECK_ + u8 scan_n_check_value = 1 << (jtag_info->scann_size - 1); +#endif + scan_field_t field; + + field.device = jtag_info->chain_pos; + field.num_bits = jtag_info->scann_size; + field.out_value = calloc(CEIL(field.num_bits, 8), 1); + buf_set_u32(field.out_value, 0, field.num_bits, new_scan_chain); + field.out_mask = NULL; + field.in_value = NULL; +#ifdef _ARM_JTAG_SCAN_N_CHECK_ + jtag_set_check_value(&field, &scan_n_check_value, NULL, NULL, NULL); +#else + field.in_handler = NULL; + field.in_handler_priv = NULL; +#endif + + + arm_jtag_set_instr(jtag_info, jtag_info->scann_instr, NULL); + jtag_add_dr_scan(1, &field, -1); + + jtag_info->cur_scan_chain = new_scan_chain; + + free(field.out_value); + } + + return ERROR_OK; +} + +int arm_jtag_reset_callback(enum jtag_event event, void *priv) +{ + arm_jtag_t *jtag_info = priv; + + if (event == JTAG_TRST_ASSERTED) + { + jtag_info->cur_scan_chain = 0; + } + + return ERROR_OK; +} + +int arm_jtag_setup_connection(arm_jtag_t *jtag_info) +{ + jtag_info->scann_instr = 0x2; + jtag_info->cur_scan_chain = 0; + jtag_info->intest_instr = 0xc; + + jtag_register_event_callback(arm_jtag_reset_callback, jtag_info); + + return ERROR_OK; +} + +/* read JTAG buffer into host-endian u32, flipping bit-order */ +int arm_jtag_buf_to_u32_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + u32 *dest = priv; + *dest = flip_u32(le_to_h_u32(in_buf), 32); + return ERROR_OK; +} + +/* read JTAG buffer into little-endian u32, flipping bit-order */ +int arm_jtag_buf_to_le32_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u32_to_le(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32)); + return ERROR_OK; +} + +/* read JTAG buffer into little-endian u16, flipping bit-order */ +int arm_jtag_buf_to_le16_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u16_to_le(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32) & 0xffff); + return ERROR_OK; +} + +/* read JTAG buffer into big-endian u32, flipping bit-order */ +int arm_jtag_buf_to_be32_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u32_to_be(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32)); + return ERROR_OK; +} + +/* read JTAG buffer into big-endian u16, flipping bit-order */ +int arm_jtag_buf_to_be16_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u16_to_be(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32) & 0xffff); + return ERROR_OK; +} + +/* read JTAG buffer into u8, flipping bit-order */ +int arm_jtag_buf_to_8_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + u8 *dest = priv; + *dest = flip_u32(le_to_h_u32(in_buf), 32) & 0xff; + return ERROR_OK; +} + +/* not-flipping variants */ +/* read JTAG buffer into host-endian u32 */ +int arm_jtag_buf_to_u32(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + u32 *dest = priv; + *dest = le_to_h_u32(in_buf); + return ERROR_OK; +} + +/* read JTAG buffer into little-endian u32 */ +int arm_jtag_buf_to_le32(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u32_to_le(((u8*)priv), le_to_h_u32(in_buf)); + return ERROR_OK; +} + +/* read JTAG buffer into little-endian u16 */ +int arm_jtag_buf_to_le16(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u16_to_le(((u8*)priv), le_to_h_u32(in_buf) & 0xffff); + return ERROR_OK; +} + +/* read JTAG buffer into big-endian u32 */ +int arm_jtag_buf_to_be32(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u32_to_be(((u8*)priv), le_to_h_u32(in_buf)); + return ERROR_OK; +} + +/* read JTAG buffer into big-endian u16 */ +int arm_jtag_buf_to_be16(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u16_to_be(((u8*)priv), le_to_h_u32(in_buf) & 0xffff); + return ERROR_OK; +} + +/* read JTAG buffer into u8 */ +int arm_jtag_buf_to_8(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + u8 *dest = priv; + *dest = le_to_h_u32(in_buf) & 0xff; + return ERROR_OK; +} diff --git a/src/target/cortex_swjdp.c b/src/target/cortex_swjdp.c index 88b641e..160f4c5 100644 --- a/src/target/cortex_swjdp.c +++ b/src/target/cortex_swjdp.c @@ -1,708 +1,708 @@ -/***************************************************************************
- * Copyright (C) 2006 by Magnus Lundin *
- * lundin@mlu.mine.nu *
- * *
- * 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. *
- ***************************************************************************/
-/***************************************************************************
- * *
- * CoreSight (Light?) SerialWireJtagDebugPort *
- * *
- * CoreSightâ„¢ DAP-Lite TRM, ARM DDI 0316A *
- * Cortex-M3â„¢ TRM, ARM DDI 0337C *
- * *
-***************************************************************************/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "replacements.h"
-
-#include "cortex_m3.h"
-#include "cortex_swjdp.h"
-#include "jtag.h"
-#include "log.h"
-#include <stdlib.h>
-
-/*
-
-Transaction Mode:
-swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-Uses Overrun checking mode and does not do actual JTAG send/receive or transaction
-result checking until swjdp_end_transaction()
-This must be done before using or deallocating any return variables.
-
-swjdp->trans_mode == TRANS_MODE_ATOMIC
-All reads and writes to the AHB bus are checked for valid completion, and return values
-are immediatley available.
-
-*/
-
-/***************************************************************************
- * *
- * DPACC and APACC scanchain access through JTAG-DR *
- * *
-***************************************************************************/
-
-/* Scan out and in from target ordered u8 buffers */
-int swjdp_scan(arm_jtag_t *jtag_info, u8 instr, u8 reg_addr, u8 RnW, u8 *outvalue, u8 *invalue, u8 *ack)
-{
- scan_field_t fields[2];
- u8 out_addr_buf;
-
- jtag_add_end_state(TAP_RTI);
- arm_jtag_set_instr(jtag_info, instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 3;
- buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1));
- fields[0].out_value = &out_addr_buf;
- fields[0].out_mask = NULL;
- fields[0].in_value = ack;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 32;
- fields[1].out_value = outvalue;
- fields[1].out_mask = NULL;
- fields[1].in_value = invalue;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
-
- jtag_add_dr_scan(2, fields, -1);
-
- return ERROR_OK;
-}
-
-/* Scan out and in from host ordered u32 variables */
-int swjdp_scan_u32(arm_jtag_t *jtag_info, u8 instr, u8 reg_addr, u8 RnW, u32 outvalue, u32 *invalue, u8 *ack)
-{
- scan_field_t fields[2];
- u8 out_value_buf[4];
- u8 out_addr_buf;
-
- jtag_add_end_state(TAP_RTI);
- arm_jtag_set_instr(jtag_info, instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 3;
- buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1));
- fields[0].out_value = &out_addr_buf;
- fields[0].out_mask = NULL;
- fields[0].in_value = ack;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 32;
- buf_set_u32(out_value_buf, 0, 32, outvalue);
- fields[1].out_value = out_value_buf;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- if (invalue)
- {
- fields[1].in_handler = arm_jtag_buf_to_u32;
- fields[1].in_handler_priv = invalue;
- }
- else
- {
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
- }
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
-
- jtag_add_dr_scan(2, fields, -1);
-
- return ERROR_OK;
-}
-
-/* scan_inout_check adds one extra inscan for DPAP_READ commands to read variables */
-int scan_inout_check(swjdp_common_t *swjdp, u8 instr, u8 reg_addr, u8 RnW, u8 *outvalue, u8 *invalue)
-{
- swjdp_scan(swjdp->jtag_info, instr, reg_addr, RnW, outvalue, NULL, NULL);
- if ((RnW == DPAP_READ) && (invalue != NULL))
- {
- swjdp_scan(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, invalue, &swjdp->ack);
- }
-
- /* In TRANS_MODE_ATOMIC all SWJDP_IR_APACC transactions wait for ack=OK/FAULT and the check CTRL_STAT */
- if ((instr == SWJDP_IR_APACC) && (swjdp->trans_mode == TRANS_MODE_ATOMIC))
- {
- return swjdp_transaction_endcheck(swjdp);
- }
-
- return ERROR_OK;
-}
-
-int scan_inout_check_u32(swjdp_common_t *swjdp, u8 instr, u8 reg_addr, u8 RnW, u32 outvalue, u32 *invalue)
-{
-
- swjdp_scan_u32(swjdp->jtag_info, instr, reg_addr, RnW, outvalue, NULL, NULL);
- if ((RnW==DPAP_READ) && (invalue != NULL))
- {
- swjdp_scan_u32(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, invalue, &swjdp->ack);
- }
-
- /* In TRANS_MODE_ATOMIC all SWJDP_IR_APACC transactions wait for ack=OK/FAULT and then check CTRL_STAT */
- if ((instr == SWJDP_IR_APACC) && (swjdp->trans_mode == TRANS_MODE_ATOMIC))
- {
- return swjdp_transaction_endcheck(swjdp);
- }
-
- return ERROR_OK;
-}
-
-int swjdp_transaction_endcheck(swjdp_common_t *swjdp)
-{
- int waitcount = 0;
- u32 ctrlstat;
-
- scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
- scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
- jtag_execute_queue();
-
- swjdp->ack = swjdp->ack & 0x7;
-
- while (swjdp->ack != 2)
- {
- if (swjdp->ack == 1)
- {
- waitcount++;
- if (waitcount > 100)
- {
- WARNING("Timeout waiting for ACK = OK/FAULT in SWJDP transaction");
-
- return ERROR_JTAG_DEVICE_ERROR;
- }
- }
- else
- {
- WARNING("Invalid ACK in SWJDP transaction");
- return ERROR_JTAG_DEVICE_ERROR;
- }
-
- scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
- jtag_execute_queue();
- swjdp->ack = swjdp->ack & 0x7;
- }
-
- /* Check for STICKYERR and STICKYORUN */
- if (ctrlstat & (SSTICKYORUN | SSTICKYERR))
- {
- DEBUG("swjdp: CTRL/STAT error 0x%x", ctrlstat);
- /* Check power to debug regions */
- if ((ctrlstat & 0xf0000000) != 0xf0000000)
- {
- ahbap_debugport_init(swjdp);
- }
- else
- {
- u32 dcb_dhcsr,nvic_shcsr, nvic_bfar, nvic_cfsr;
-
- if (ctrlstat & SSTICKYORUN)
- ERROR("SWJ-DP OVERRUN - check clock or reduce jtag speed");
-
- if (ctrlstat & SSTICKYERR)
- ERROR("SWJ-DP STICKY ERROR");
-
- /* Clear Sticky Error Bits */
- scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_WRITE, swjdp->dp_ctrl_stat | SSTICKYORUN | SSTICKYERR, NULL);
- scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
- jtag_execute_queue();
-
- DEBUG("swjdp: status 0x%x", ctrlstat);
-
- /* Can we find out the reason for the error ?? */
- ahbap_read_system_atomic_u32(swjdp, DCB_DHCSR, &dcb_dhcsr);
- ahbap_read_system_atomic_u32(swjdp, NVIC_SHCSR, &nvic_shcsr);
- ahbap_read_system_atomic_u32(swjdp, NVIC_CFSR, &nvic_cfsr);
- ahbap_read_system_atomic_u32(swjdp, NVIC_BFAR, &nvic_bfar);
- ERROR("dcb_dhcsr 0x%x, nvic_shcsr 0x%x, nvic_cfsr 0x%x, nvic_bfar 0x%x", dcb_dhcsr, nvic_shcsr, nvic_cfsr, nvic_bfar);
- }
- jtag_execute_queue();
- return ERROR_JTAG_DEVICE_ERROR;
- }
-
- return ERROR_OK;
-}
-
-/***************************************************************************
- * *
- * DP and AHB-AP register access through APACC and DPACC *
- * *
-***************************************************************************/
-
-int swjdp_write_dpacc(swjdp_common_t *swjdp, u32 value, u8 reg_addr)
-{
- u8 out_value_buf[4];
-
- buf_set_u32(out_value_buf, 0, 32, value);
- return scan_inout_check(swjdp, SWJDP_IR_DPACC, reg_addr, DPAP_WRITE, out_value_buf, NULL);
-}
-
-int swjdp_read_dpacc(swjdp_common_t *swjdp, u32 *value, u8 reg_addr)
-{
- scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, reg_addr, DPAP_READ, 0, value);
-
- return ERROR_OK;
-}
-
-int swjdp_bankselect_apacc(swjdp_common_t *swjdp,u32 reg_addr)
-{
- u32 select;
- select = (reg_addr & 0xFF0000F0);
-
- if (select != swjdp->dp_select_value)
- {
- swjdp_write_dpacc(swjdp, select, DP_SELECT);
- swjdp->dp_select_value = select;
- }
-
- return ERROR_OK;
-}
-
-int ahbap_write_reg(swjdp_common_t *swjdp, u32 reg_addr, u8* out_value_buf)
-{
- swjdp_bankselect_apacc(swjdp, reg_addr);
- scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_WRITE, out_value_buf, NULL);
-
- return ERROR_OK;
-}
-
-int ahbap_read_reg(swjdp_common_t *swjdp, u32 reg_addr, u8 *in_value_buf)
-{
- swjdp_bankselect_apacc(swjdp, reg_addr);
- scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_READ, 0, in_value_buf);
-
- return ERROR_OK;
-}
-int ahbap_write_reg_u32(swjdp_common_t *swjdp, u32 reg_addr, u32 value)
-{
- u8 out_value_buf[4];
-
- buf_set_u32(out_value_buf, 0, 32, value);
- swjdp_bankselect_apacc(swjdp, reg_addr);
- scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_WRITE, out_value_buf, NULL);
-
- return ERROR_OK;
-}
-
-int ahbap_read_reg_u32(swjdp_common_t *swjdp, u32 reg_addr, u32 *value)
-{
- swjdp_bankselect_apacc(swjdp, reg_addr);
- scan_inout_check_u32(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_READ, 0, value);
-
- return ERROR_OK;
-}
-
-/***************************************************************************
- * *
- * AHB-AP access to memory and system registers on AHB bus *
- * *
-***************************************************************************/
-
-int ahbap_setup_accessport(swjdp_common_t *swjdp, u32 csw, u32 tar)
-{
- csw = csw | CSW_DBGSWENABLE | CSW_MASTER_DEBUG | CSW_HPROT;
- if (csw != swjdp->ap_csw_value)
- {
- //DEBUG("swjdp : Set CSW %x",csw);
- ahbap_write_reg_u32(swjdp, AHBAP_CSW, csw );
- swjdp->ap_csw_value = csw;
- }
- if (tar != swjdp->ap_tar_value)
- {
- //DEBUG("swjdp : Set TAR %x",tar);
- ahbap_write_reg_u32(swjdp, AHBAP_TAR, tar );
- swjdp->ap_tar_value = tar;
- }
- if (csw & CSW_ADDRINC_MASK)
- {
- /* Do not cache TAR value when autoincrementing */
- swjdp->ap_tar_value = -1;
- }
- return ERROR_OK;
-}
-
-/*****************************************************************************
-* *
-* ahbap_read_system_u32(swjdp_common_t *swjdp, u32 address, u32 *value) *
-* *
-* Read a u32 value from memory or system register *
-* Functionally equivalent to target_read_u32(target, address, u32 *value), *
-* but with less overhead *
-*****************************************************************************/
-int ahbap_read_system_u32(swjdp_common_t *swjdp, u32 address, u32 *value)
-{
- swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
- ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0);
- ahbap_read_reg_u32(swjdp, AHBAP_BD0 | (address & 0xC), value );
-
- return ERROR_OK;
-}
-
-int ahbap_read_system_atomic_u32(swjdp_common_t *swjdp, u32 address, u32 *value)
-{
- ahbap_read_system_u32(swjdp, address, value);
-
- return swjdp_transaction_endcheck(swjdp);
-}
-
-/*****************************************************************************
-* *
-* ahbap_write_system_u32(swjdp_common_t *swjdp, u32 address, u32 value) *
-* *
-* Write a u32 value to memory or system register *
-* *
-*****************************************************************************/
-int ahbap_write_system_u32(swjdp_common_t *swjdp, u32 address, u32 value)
-{
- swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
- ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0);
- ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (address & 0xC), value );
-
- return ERROR_OK;
-}
-
-int ahbap_write_system_atomic_u32(swjdp_common_t *swjdp, u32 address, u32 value)
-{
- ahbap_write_system_u32(swjdp, address, value);
-
- return swjdp_transaction_endcheck(swjdp);
-}
-
-/*****************************************************************************
-* *
-* ahbap_write_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) *
-* *
-* Write a buffer in target order (little endian) *
-* *
-*****************************************************************************/
-int ahbap_write_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address)
-{
- u32 outvalue;
- int wcount, blocksize, writecount, errorcount = 0, retval = ERROR_OK;
-
- swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
- while ((address & 0x3) && (count > 0))
- {
- ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address);
- outvalue = (*buffer++) << 8 * (address & 0x3);
- ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue );
- swjdp_transaction_endcheck(swjdp);
- count--;
- address++;
- }
- wcount = count >> 2;
- count = count - 4 * wcount;
- while (wcount > 0)
- {
- /* Adjust to write blocks within 4K aligned boundaries */
- blocksize = (0x1000 - (0xFFF & address)) >> 2;
- if (wcount < blocksize)
- blocksize = wcount;
- ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address);
- for (writecount=0; writecount<blocksize; writecount++)
- {
- ahbap_write_reg(swjdp, AHBAP_DRW, buffer + 4 * writecount );
- }
- if (swjdp_transaction_endcheck(swjdp) == ERROR_OK)
- {
- wcount = wcount - blocksize;
- address = address + 4 * blocksize;
- buffer = buffer + 4 * blocksize;
- }
- else
- {
- errorcount++;
- }
- if (errorcount > 1)
- {
- WARNING("Block write error address 0x%x, wcount 0x%x", address, wcount);
- return ERROR_JTAG_DEVICE_ERROR;
- }
- }
-
- while (count > 0)
- {
- ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address);
- outvalue = (*buffer++) << 8 * (address & 0x3);
- ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue );
- retval = swjdp_transaction_endcheck(swjdp);
- count--;
- address++;
- }
-
- return retval;
-}
-
-int ahbap_write_buf_u16(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address)
-{
- u32 outvalue;
- int retval = ERROR_OK;
-
- swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
- while (count > 0)
- {
- ahbap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address);
- outvalue = *((u16*)buffer) << 8 * (address & 0x3);
- ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue );
- retval = swjdp_transaction_endcheck(swjdp);
- count -= 2;
- address += 2;
- buffer += 2;
- }
-
- return retval;
-}
-
-/*****************************************************************************
-* *
-* ahbap_read_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) *
-* *
-* Read block fast in target order (little endian) into a buffer *
-* *
-*****************************************************************************/
-int ahbap_read_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address)
-{
- u32 invalue;
- int wcount, blocksize, readcount, errorcount = 0, retval = ERROR_OK;
-
- swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
- while ((address & 0x3) && (count > 0))
- {
- ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address);
- ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue);
- swjdp_transaction_endcheck(swjdp);
- *buffer++ = (invalue >> 8 * (address & 0x3)) & 0xFF;
- count--;
- address++;
- }
- wcount = count >> 2;
- count = count - 4 * wcount;
- while (wcount > 0)
- {
- /* Adjust to read within 4K block boundaries */
- blocksize = (0x1000 - (0xFFF & address)) >> 2;
- if (wcount < blocksize)
- blocksize = wcount;
- ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address);
- /* Scan out first read */
- swjdp_scan(swjdp->jtag_info, SWJDP_IR_APACC, AHBAP_DRW, DPAP_READ, 0, NULL, NULL);
- for (readcount = 0; readcount < blocksize - 1; readcount++)
- {
- /* Scan out read instruction and scan in previous value */
- swjdp_scan(swjdp->jtag_info, SWJDP_IR_APACC, AHBAP_DRW, DPAP_READ, 0, buffer + 4 * readcount, &swjdp->ack);
- }
- /* Scan in last value */
- swjdp_scan(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, buffer + 4 * readcount, &swjdp->ack);
- if (swjdp_transaction_endcheck(swjdp) == ERROR_OK)
- {
- wcount = wcount - blocksize;
- address += 4 * blocksize;
- buffer += 4 * blocksize;
- }
- else
- {
- errorcount++;
- }
- if (errorcount > 1)
- {
- WARNING("Block read error address 0x%x, count 0x%x", address, count);
- return ERROR_JTAG_DEVICE_ERROR;
- }
- }
-
- while (count > 0)
- {
- ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address);
- ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue );
- retval = swjdp_transaction_endcheck(swjdp);
- *buffer++ = (invalue >> 8 * (address & 0x3)) & 0xFF;
- count--;
- address++;
- }
-
- return retval;
-}
-
-int ahbap_read_buf_u16(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address)
-{
- u32 invalue;
- int retval = ERROR_OK;
-
- swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
- while (count > 0)
- {
- ahbap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address);
- ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue );
- retval = swjdp_transaction_endcheck(swjdp);
- *((u16*)buffer) = (invalue >> 8 * (address & 0x3));
- count -= 2;
- address += 2;
- buffer += 2;
- }
-
- return retval;
-}
-
-int ahbap_block_read_u32(swjdp_common_t *swjdp, u32 *buffer, int count, u32 address)
-{
- int readcount, errorcount = 0;
- u32 blocksize;
-
- swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
- while (count > 0)
- {
- /* Adjust to read within 4K block boundaries */
- blocksize = (0x1000 - (0xFFF & address)) >> 2;
- if (count < blocksize)
- blocksize = count;
- ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address);
- for (readcount = 0; readcount < blocksize; readcount++)
- {
- ahbap_read_reg_u32(swjdp, AHBAP_DRW, buffer + readcount );
- }
- if (swjdp_transaction_endcheck(swjdp) == ERROR_OK)
- {
- count = count - blocksize;
- address = address + 4 * blocksize;
- buffer = buffer + blocksize;
- }
- else
- {
- errorcount++;
- }
- if (errorcount > 1)
- {
- WARNING("Block read error address 0x%x, count 0x%x", address, count);
- return ERROR_JTAG_DEVICE_ERROR;
- }
- }
-
- return ERROR_OK;
-}
-
-int ahbap_read_coreregister_u32(swjdp_common_t *swjdp, u32 *value, int regnum)
-{
- int retval;
- u32 dcrdr;
-
- ahbap_read_system_atomic_u32(swjdp, DCB_DCRDR, &dcrdr);
-
- swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
- /* ahbap_write_system_u32(swjdp, DCB_DCRSR, regnum); */
- ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0);
- ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRSR & 0xC), regnum );
-
- /* ahbap_read_system_u32(swjdp, DCB_DCRDR, value); */
- ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0);
- ahbap_read_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRDR & 0xC), value );
-
- retval = swjdp_transaction_endcheck(swjdp);
- ahbap_write_system_atomic_u32(swjdp, DCB_DCRDR, dcrdr);
- return retval;
-}
-
-int ahbap_write_coreregister_u32(swjdp_common_t *swjdp, u32 value, int regnum)
-{
- int retval;
- u32 dcrdr;
-
- ahbap_read_system_atomic_u32(swjdp, DCB_DCRDR, &dcrdr);
-
- swjdp->trans_mode = TRANS_MODE_COMPOSITE;
-
- /* ahbap_write_system_u32(swjdp, DCB_DCRDR, core_regs[i]); */
- ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0);
- ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRDR & 0xC), value );
-
- /* ahbap_write_system_u32(swjdp, DCB_DCRSR, i | DCRSR_WnR ); */
- ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0);
- ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRSR & 0xC), regnum | DCRSR_WnR );
-
- retval = swjdp_transaction_endcheck(swjdp);
- ahbap_write_system_atomic_u32(swjdp, DCB_DCRDR, dcrdr);
- return retval;
-}
-
-int ahbap_debugport_init(swjdp_common_t *swjdp)
-{
- u32 idreg, romaddr, dummy;
- u32 ctrlstat;
- int cnt = 0;
-
- DEBUG(" ");
-
- swjdp->ap_csw_value = -1;
- swjdp->ap_tar_value = -1;
- swjdp->trans_mode = TRANS_MODE_ATOMIC;
- swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT);
- swjdp_write_dpacc(swjdp, SSTICKYERR, DP_CTRL_STAT);
- swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT);
-
- swjdp->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ;
-
- swjdp_write_dpacc(swjdp, swjdp->dp_ctrl_stat, DP_CTRL_STAT);
- swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT);
- jtag_execute_queue();
-
- /* Check that we have debug power domains activated */
- while (!(ctrlstat & CDBGPWRUPACK) && (cnt++ < 10))
- {
- DEBUG("swjdp: wait CDBGPWRUPACK");
- swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT);
- jtag_execute_queue();
- usleep(10000);
- }
-
- while (!(ctrlstat & CSYSPWRUPACK) && (cnt++ < 10))
- {
- DEBUG("swjdp: wait CSYSPWRUPACK");
- swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT);
- jtag_execute_queue();
- usleep(10000);
- }
-
- swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT);
- /* With debug power on we can activate OVERRUN checking */
- swjdp->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ | CORUNDETECT;
- swjdp_write_dpacc(swjdp, swjdp->dp_ctrl_stat , DP_CTRL_STAT);
- swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT);
-
- ahbap_read_reg_u32(swjdp, 0xFC, &idreg);
- ahbap_read_reg_u32(swjdp, 0xF8, &romaddr);
-
- DEBUG("AHB-AP ID Register 0x%x, Debug ROM Address 0x%x", idreg, romaddr);
-
- return ERROR_OK;
-}
+/*************************************************************************** + * Copyright (C) 2006 by Magnus Lundin * + * lundin@mlu.mine.nu * + * * + * 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. * + ***************************************************************************/ +/*************************************************************************** + * * + * CoreSight (Light?) SerialWireJtagDebugPort * + * * + * CoreSightâ„¢ DAP-Lite TRM, ARM DDI 0316A * + * Cortex-M3â„¢ TRM, ARM DDI 0337C * + * * +***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "replacements.h" + +#include "cortex_m3.h" +#include "cortex_swjdp.h" +#include "jtag.h" +#include "log.h" +#include <stdlib.h> + +/* + +Transaction Mode: +swjdp->trans_mode = TRANS_MODE_COMPOSITE; +Uses Overrun checking mode and does not do actual JTAG send/receive or transaction +result checking until swjdp_end_transaction() +This must be done before using or deallocating any return variables. + +swjdp->trans_mode == TRANS_MODE_ATOMIC +All reads and writes to the AHB bus are checked for valid completion, and return values +are immediatley available. + +*/ + +/*************************************************************************** + * * + * DPACC and APACC scanchain access through JTAG-DR * + * * +***************************************************************************/ + +/* Scan out and in from target ordered u8 buffers */ +int swjdp_scan(arm_jtag_t *jtag_info, u8 instr, u8 reg_addr, u8 RnW, u8 *outvalue, u8 *invalue, u8 *ack) +{ + scan_field_t fields[2]; + u8 out_addr_buf; + + jtag_add_end_state(TAP_RTI); + arm_jtag_set_instr(jtag_info, instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 3; + buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1)); + fields[0].out_value = &out_addr_buf; + fields[0].out_mask = NULL; + fields[0].in_value = ack; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = outvalue; + fields[1].out_mask = NULL; + fields[1].in_value = invalue; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + jtag_add_dr_scan(2, fields, -1); + + return ERROR_OK; +} + +/* Scan out and in from host ordered u32 variables */ +int swjdp_scan_u32(arm_jtag_t *jtag_info, u8 instr, u8 reg_addr, u8 RnW, u32 outvalue, u32 *invalue, u8 *ack) +{ + scan_field_t fields[2]; + u8 out_value_buf[4]; + u8 out_addr_buf; + + jtag_add_end_state(TAP_RTI); + arm_jtag_set_instr(jtag_info, instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 3; + buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1)); + fields[0].out_value = &out_addr_buf; + fields[0].out_mask = NULL; + fields[0].in_value = ack; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + buf_set_u32(out_value_buf, 0, 32, outvalue); + fields[1].out_value = out_value_buf; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + if (invalue) + { + fields[1].in_handler = arm_jtag_buf_to_u32; + fields[1].in_handler_priv = invalue; + } + else + { + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + } + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + jtag_add_dr_scan(2, fields, -1); + + return ERROR_OK; +} + +/* scan_inout_check adds one extra inscan for DPAP_READ commands to read variables */ +int scan_inout_check(swjdp_common_t *swjdp, u8 instr, u8 reg_addr, u8 RnW, u8 *outvalue, u8 *invalue) +{ + swjdp_scan(swjdp->jtag_info, instr, reg_addr, RnW, outvalue, NULL, NULL); + if ((RnW == DPAP_READ) && (invalue != NULL)) + { + swjdp_scan(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, invalue, &swjdp->ack); + } + + /* In TRANS_MODE_ATOMIC all SWJDP_IR_APACC transactions wait for ack=OK/FAULT and the check CTRL_STAT */ + if ((instr == SWJDP_IR_APACC) && (swjdp->trans_mode == TRANS_MODE_ATOMIC)) + { + return swjdp_transaction_endcheck(swjdp); + } + + return ERROR_OK; +} + +int scan_inout_check_u32(swjdp_common_t *swjdp, u8 instr, u8 reg_addr, u8 RnW, u32 outvalue, u32 *invalue) +{ + + swjdp_scan_u32(swjdp->jtag_info, instr, reg_addr, RnW, outvalue, NULL, NULL); + if ((RnW==DPAP_READ) && (invalue != NULL)) + { + swjdp_scan_u32(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, invalue, &swjdp->ack); + } + + /* In TRANS_MODE_ATOMIC all SWJDP_IR_APACC transactions wait for ack=OK/FAULT and then check CTRL_STAT */ + if ((instr == SWJDP_IR_APACC) && (swjdp->trans_mode == TRANS_MODE_ATOMIC)) + { + return swjdp_transaction_endcheck(swjdp); + } + + return ERROR_OK; +} + +int swjdp_transaction_endcheck(swjdp_common_t *swjdp) +{ + int waitcount = 0; + u32 ctrlstat; + + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + jtag_execute_queue(); + + swjdp->ack = swjdp->ack & 0x7; + + while (swjdp->ack != 2) + { + if (swjdp->ack == 1) + { + waitcount++; + if (waitcount > 100) + { + WARNING("Timeout waiting for ACK = OK/FAULT in SWJDP transaction"); + + return ERROR_JTAG_DEVICE_ERROR; + } + } + else + { + WARNING("Invalid ACK in SWJDP transaction"); + return ERROR_JTAG_DEVICE_ERROR; + } + + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + jtag_execute_queue(); + swjdp->ack = swjdp->ack & 0x7; + } + + /* Check for STICKYERR and STICKYORUN */ + if (ctrlstat & (SSTICKYORUN | SSTICKYERR)) + { + DEBUG("swjdp: CTRL/STAT error 0x%x", ctrlstat); + /* Check power to debug regions */ + if ((ctrlstat & 0xf0000000) != 0xf0000000) + { + ahbap_debugport_init(swjdp); + } + else + { + u32 dcb_dhcsr,nvic_shcsr, nvic_bfar, nvic_cfsr; + + if (ctrlstat & SSTICKYORUN) + ERROR("SWJ-DP OVERRUN - check clock or reduce jtag speed"); + + if (ctrlstat & SSTICKYERR) + ERROR("SWJ-DP STICKY ERROR"); + + /* Clear Sticky Error Bits */ + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_WRITE, swjdp->dp_ctrl_stat | SSTICKYORUN | SSTICKYERR, NULL); + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + jtag_execute_queue(); + + DEBUG("swjdp: status 0x%x", ctrlstat); + + /* Can we find out the reason for the error ?? */ + ahbap_read_system_atomic_u32(swjdp, DCB_DHCSR, &dcb_dhcsr); + ahbap_read_system_atomic_u32(swjdp, NVIC_SHCSR, &nvic_shcsr); + ahbap_read_system_atomic_u32(swjdp, NVIC_CFSR, &nvic_cfsr); + ahbap_read_system_atomic_u32(swjdp, NVIC_BFAR, &nvic_bfar); + ERROR("dcb_dhcsr 0x%x, nvic_shcsr 0x%x, nvic_cfsr 0x%x, nvic_bfar 0x%x", dcb_dhcsr, nvic_shcsr, nvic_cfsr, nvic_bfar); + } + jtag_execute_queue(); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +/*************************************************************************** + * * + * DP and AHB-AP register access through APACC and DPACC * + * * +***************************************************************************/ + +int swjdp_write_dpacc(swjdp_common_t *swjdp, u32 value, u8 reg_addr) +{ + u8 out_value_buf[4]; + + buf_set_u32(out_value_buf, 0, 32, value); + return scan_inout_check(swjdp, SWJDP_IR_DPACC, reg_addr, DPAP_WRITE, out_value_buf, NULL); +} + +int swjdp_read_dpacc(swjdp_common_t *swjdp, u32 *value, u8 reg_addr) +{ + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, reg_addr, DPAP_READ, 0, value); + + return ERROR_OK; +} + +int swjdp_bankselect_apacc(swjdp_common_t *swjdp,u32 reg_addr) +{ + u32 select; + select = (reg_addr & 0xFF0000F0); + + if (select != swjdp->dp_select_value) + { + swjdp_write_dpacc(swjdp, select, DP_SELECT); + swjdp->dp_select_value = select; + } + + return ERROR_OK; +} + +int ahbap_write_reg(swjdp_common_t *swjdp, u32 reg_addr, u8* out_value_buf) +{ + swjdp_bankselect_apacc(swjdp, reg_addr); + scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_WRITE, out_value_buf, NULL); + + return ERROR_OK; +} + +int ahbap_read_reg(swjdp_common_t *swjdp, u32 reg_addr, u8 *in_value_buf) +{ + swjdp_bankselect_apacc(swjdp, reg_addr); + scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_READ, 0, in_value_buf); + + return ERROR_OK; +} +int ahbap_write_reg_u32(swjdp_common_t *swjdp, u32 reg_addr, u32 value) +{ + u8 out_value_buf[4]; + + buf_set_u32(out_value_buf, 0, 32, value); + swjdp_bankselect_apacc(swjdp, reg_addr); + scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_WRITE, out_value_buf, NULL); + + return ERROR_OK; +} + +int ahbap_read_reg_u32(swjdp_common_t *swjdp, u32 reg_addr, u32 *value) +{ + swjdp_bankselect_apacc(swjdp, reg_addr); + scan_inout_check_u32(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_READ, 0, value); + + return ERROR_OK; +} + +/*************************************************************************** + * * + * AHB-AP access to memory and system registers on AHB bus * + * * +***************************************************************************/ + +int ahbap_setup_accessport(swjdp_common_t *swjdp, u32 csw, u32 tar) +{ + csw = csw | CSW_DBGSWENABLE | CSW_MASTER_DEBUG | CSW_HPROT; + if (csw != swjdp->ap_csw_value) + { + //DEBUG("swjdp : Set CSW %x",csw); + ahbap_write_reg_u32(swjdp, AHBAP_CSW, csw ); + swjdp->ap_csw_value = csw; + } + if (tar != swjdp->ap_tar_value) + { + //DEBUG("swjdp : Set TAR %x",tar); + ahbap_write_reg_u32(swjdp, AHBAP_TAR, tar ); + swjdp->ap_tar_value = tar; + } + if (csw & CSW_ADDRINC_MASK) + { + /* Do not cache TAR value when autoincrementing */ + swjdp->ap_tar_value = -1; + } + return ERROR_OK; +} + +/***************************************************************************** +* * +* ahbap_read_system_u32(swjdp_common_t *swjdp, u32 address, u32 *value) * +* * +* Read a u32 value from memory or system register * +* Functionally equivalent to target_read_u32(target, address, u32 *value), * +* but with less overhead * +*****************************************************************************/ +int ahbap_read_system_u32(swjdp_common_t *swjdp, u32 address, u32 *value) +{ + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0); + ahbap_read_reg_u32(swjdp, AHBAP_BD0 | (address & 0xC), value ); + + return ERROR_OK; +} + +int ahbap_read_system_atomic_u32(swjdp_common_t *swjdp, u32 address, u32 *value) +{ + ahbap_read_system_u32(swjdp, address, value); + + return swjdp_transaction_endcheck(swjdp); +} + +/***************************************************************************** +* * +* ahbap_write_system_u32(swjdp_common_t *swjdp, u32 address, u32 value) * +* * +* Write a u32 value to memory or system register * +* * +*****************************************************************************/ +int ahbap_write_system_u32(swjdp_common_t *swjdp, u32 address, u32 value) +{ + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0); + ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (address & 0xC), value ); + + return ERROR_OK; +} + +int ahbap_write_system_atomic_u32(swjdp_common_t *swjdp, u32 address, u32 value) +{ + ahbap_write_system_u32(swjdp, address, value); + + return swjdp_transaction_endcheck(swjdp); +} + +/***************************************************************************** +* * +* ahbap_write_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) * +* * +* Write a buffer in target order (little endian) * +* * +*****************************************************************************/ +int ahbap_write_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) +{ + u32 outvalue; + int wcount, blocksize, writecount, errorcount = 0, retval = ERROR_OK; + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + while ((address & 0x3) && (count > 0)) + { + ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); + outvalue = (*buffer++) << 8 * (address & 0x3); + ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue ); + swjdp_transaction_endcheck(swjdp); + count--; + address++; + } + wcount = count >> 2; + count = count - 4 * wcount; + while (wcount > 0) + { + /* Adjust to write blocks within 4K aligned boundaries */ + blocksize = (0x1000 - (0xFFF & address)) >> 2; + if (wcount < blocksize) + blocksize = wcount; + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); + for (writecount=0; writecount<blocksize; writecount++) + { + ahbap_write_reg(swjdp, AHBAP_DRW, buffer + 4 * writecount ); + } + if (swjdp_transaction_endcheck(swjdp) == ERROR_OK) + { + wcount = wcount - blocksize; + address = address + 4 * blocksize; + buffer = buffer + 4 * blocksize; + } + else + { + errorcount++; + } + if (errorcount > 1) + { + WARNING("Block write error address 0x%x, wcount 0x%x", address, wcount); + return ERROR_JTAG_DEVICE_ERROR; + } + } + + while (count > 0) + { + ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); + outvalue = (*buffer++) << 8 * (address & 0x3); + ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue ); + retval = swjdp_transaction_endcheck(swjdp); + count--; + address++; + } + + return retval; +} + +int ahbap_write_buf_u16(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) +{ + u32 outvalue; + int retval = ERROR_OK; + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + while (count > 0) + { + ahbap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address); + outvalue = *((u16*)buffer) << 8 * (address & 0x3); + ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue ); + retval = swjdp_transaction_endcheck(swjdp); + count -= 2; + address += 2; + buffer += 2; + } + + return retval; +} + +/***************************************************************************** +* * +* ahbap_read_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) * +* * +* Read block fast in target order (little endian) into a buffer * +* * +*****************************************************************************/ +int ahbap_read_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) +{ + u32 invalue; + int wcount, blocksize, readcount, errorcount = 0, retval = ERROR_OK; + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + while ((address & 0x3) && (count > 0)) + { + ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); + ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue); + swjdp_transaction_endcheck(swjdp); + *buffer++ = (invalue >> 8 * (address & 0x3)) & 0xFF; + count--; + address++; + } + wcount = count >> 2; + count = count - 4 * wcount; + while (wcount > 0) + { + /* Adjust to read within 4K block boundaries */ + blocksize = (0x1000 - (0xFFF & address)) >> 2; + if (wcount < blocksize) + blocksize = wcount; + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); + /* Scan out first read */ + swjdp_scan(swjdp->jtag_info, SWJDP_IR_APACC, AHBAP_DRW, DPAP_READ, 0, NULL, NULL); + for (readcount = 0; readcount < blocksize - 1; readcount++) + { + /* Scan out read instruction and scan in previous value */ + swjdp_scan(swjdp->jtag_info, SWJDP_IR_APACC, AHBAP_DRW, DPAP_READ, 0, buffer + 4 * readcount, &swjdp->ack); + } + /* Scan in last value */ + swjdp_scan(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, buffer + 4 * readcount, &swjdp->ack); + if (swjdp_transaction_endcheck(swjdp) == ERROR_OK) + { + wcount = wcount - blocksize; + address += 4 * blocksize; + buffer += 4 * blocksize; + } + else + { + errorcount++; + } + if (errorcount > 1) + { + WARNING("Block read error address 0x%x, count 0x%x", address, count); + return ERROR_JTAG_DEVICE_ERROR; + } + } + + while (count > 0) + { + ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); + ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue ); + retval = swjdp_transaction_endcheck(swjdp); + *buffer++ = (invalue >> 8 * (address & 0x3)) & 0xFF; + count--; + address++; + } + + return retval; +} + +int ahbap_read_buf_u16(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) +{ + u32 invalue; + int retval = ERROR_OK; + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + while (count > 0) + { + ahbap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address); + ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue ); + retval = swjdp_transaction_endcheck(swjdp); + *((u16*)buffer) = (invalue >> 8 * (address & 0x3)); + count -= 2; + address += 2; + buffer += 2; + } + + return retval; +} + +int ahbap_block_read_u32(swjdp_common_t *swjdp, u32 *buffer, int count, u32 address) +{ + int readcount, errorcount = 0; + u32 blocksize; + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + while (count > 0) + { + /* Adjust to read within 4K block boundaries */ + blocksize = (0x1000 - (0xFFF & address)) >> 2; + if (count < blocksize) + blocksize = count; + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); + for (readcount = 0; readcount < blocksize; readcount++) + { + ahbap_read_reg_u32(swjdp, AHBAP_DRW, buffer + readcount ); + } + if (swjdp_transaction_endcheck(swjdp) == ERROR_OK) + { + count = count - blocksize; + address = address + 4 * blocksize; + buffer = buffer + blocksize; + } + else + { + errorcount++; + } + if (errorcount > 1) + { + WARNING("Block read error address 0x%x, count 0x%x", address, count); + return ERROR_JTAG_DEVICE_ERROR; + } + } + + return ERROR_OK; +} + +int ahbap_read_coreregister_u32(swjdp_common_t *swjdp, u32 *value, int regnum) +{ + int retval; + u32 dcrdr; + + ahbap_read_system_atomic_u32(swjdp, DCB_DCRDR, &dcrdr); + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + /* ahbap_write_system_u32(swjdp, DCB_DCRSR, regnum); */ + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0); + ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRSR & 0xC), regnum ); + + /* ahbap_read_system_u32(swjdp, DCB_DCRDR, value); */ + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0); + ahbap_read_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRDR & 0xC), value ); + + retval = swjdp_transaction_endcheck(swjdp); + ahbap_write_system_atomic_u32(swjdp, DCB_DCRDR, dcrdr); + return retval; +} + +int ahbap_write_coreregister_u32(swjdp_common_t *swjdp, u32 value, int regnum) +{ + int retval; + u32 dcrdr; + + ahbap_read_system_atomic_u32(swjdp, DCB_DCRDR, &dcrdr); + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + /* ahbap_write_system_u32(swjdp, DCB_DCRDR, core_regs[i]); */ + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0); + ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRDR & 0xC), value ); + + /* ahbap_write_system_u32(swjdp, DCB_DCRSR, i | DCRSR_WnR ); */ + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0); + ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRSR & 0xC), regnum | DCRSR_WnR ); + + retval = swjdp_transaction_endcheck(swjdp); + ahbap_write_system_atomic_u32(swjdp, DCB_DCRDR, dcrdr); + return retval; +} + +int ahbap_debugport_init(swjdp_common_t *swjdp) +{ + u32 idreg, romaddr, dummy; + u32 ctrlstat; + int cnt = 0; + + DEBUG(" "); + + swjdp->ap_csw_value = -1; + swjdp->ap_tar_value = -1; + swjdp->trans_mode = TRANS_MODE_ATOMIC; + swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); + swjdp_write_dpacc(swjdp, SSTICKYERR, DP_CTRL_STAT); + swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); + + swjdp->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; + + swjdp_write_dpacc(swjdp, swjdp->dp_ctrl_stat, DP_CTRL_STAT); + swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT); + jtag_execute_queue(); + + /* Check that we have debug power domains activated */ + while (!(ctrlstat & CDBGPWRUPACK) && (cnt++ < 10)) + { + DEBUG("swjdp: wait CDBGPWRUPACK"); + swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT); + jtag_execute_queue(); + usleep(10000); + } + + while (!(ctrlstat & CSYSPWRUPACK) && (cnt++ < 10)) + { + DEBUG("swjdp: wait CSYSPWRUPACK"); + swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT); + jtag_execute_queue(); + usleep(10000); + } + + swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); + /* With debug power on we can activate OVERRUN checking */ + swjdp->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ | CORUNDETECT; + swjdp_write_dpacc(swjdp, swjdp->dp_ctrl_stat , DP_CTRL_STAT); + swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); + + ahbap_read_reg_u32(swjdp, 0xFC, &idreg); + ahbap_read_reg_u32(swjdp, 0xF8, &romaddr); + + DEBUG("AHB-AP ID Register 0x%x, Debug ROM Address 0x%x", idreg, romaddr); + + return ERROR_OK; +} diff --git a/src/target/embeddedice.c b/src/target/embeddedice.c index 07b965b..333c1c4 100644 --- a/src/target/embeddedice.c +++ b/src/target/embeddedice.c @@ -1,565 +1,565 @@ -/***************************************************************************
- * 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 "embeddedice.h"
-
-#include "armv4_5.h"
-#include "arm7_9_common.h"
-
-#include "log.h"
-#include "arm_jtag.h"
-#include "types.h"
-#include "binarybuffer.h"
-#include "target.h"
-#include "register.h"
-#include "jtag.h"
-
-#include <stdlib.h>
-
-bitfield_desc_t embeddedice_comms_ctrl_bitfield_desc[] =
-{
- {"R", 1},
- {"W", 1},
- {"reserved", 26},
- {"version", 4}
-};
-
-int embeddedice_reg_arch_info[] =
-{
- 0x0, 0x1, 0x4, 0x5,
- 0x8, 0x9, 0xa, 0xb, 0xc, 0xd,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
- 0x2
-};
-
-char* embeddedice_reg_list[] =
-{
- "debug_ctrl",
- "debug_status",
-
- "comms_ctrl",
- "comms_data",
-
- "watch 0 addr value",
- "watch 0 addr mask",
- "watch 0 data value",
- "watch 0 data mask",
- "watch 0 control value",
- "watch 0 control mask",
-
- "watch 1 addr value",
- "watch 1 addr mask",
- "watch 1 data value",
- "watch 1 data mask",
- "watch 1 control value",
- "watch 1 control mask",
-
- "vector catch"
-};
-
-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);
-
-reg_cache_t* embeddedice_build_reg_cache(target_t *target, arm7_9_common_t *arm7_9)
-{
- reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t));
- reg_t *reg_list = NULL;
- embeddedice_reg_t *arch_info = NULL;
- arm_jtag_t *jtag_info = &arm7_9->jtag_info;
- int num_regs;
- int i;
- int eice_version = 0;
-
- /* register a register arch-type for EmbeddedICE registers only once */
- if (embeddedice_reg_arch_type == -1)
- embeddedice_reg_arch_type = register_reg_arch_type(embeddedice_get_reg, embeddedice_set_reg_w_exec);
-
- if (arm7_9->has_vector_catch)
- num_regs = 17;
- else
- num_regs = 16;
-
- /* the actual registers are kept in two arrays */
- reg_list = calloc(num_regs, sizeof(reg_t));
- arch_info = calloc(num_regs, sizeof(embeddedice_reg_t));
-
- /* fill in values for the reg cache */
- reg_cache->name = "EmbeddedICE registers";
- reg_cache->next = NULL;
- reg_cache->reg_list = reg_list;
- reg_cache->num_regs = num_regs;
-
- /* set up registers */
- for (i = 0; i < num_regs; i++)
- {
- reg_list[i].name = embeddedice_reg_list[i];
- reg_list[i].size = 32;
- reg_list[i].dirty = 0;
- reg_list[i].valid = 0;
- reg_list[i].bitfield_desc = NULL;
- reg_list[i].num_bitfields = 0;
- reg_list[i].value = calloc(1, 4);
- reg_list[i].arch_info = &arch_info[i];
- reg_list[i].arch_type = embeddedice_reg_arch_type;
- arch_info[i].addr = embeddedice_reg_arch_info[i];
- arch_info[i].jtag_info = jtag_info;
- }
-
- /* identify EmbeddedICE version by reading DCC control register */
- embeddedice_read_reg(®_list[EICE_COMMS_CTRL]);
- jtag_execute_queue();
-
- eice_version = buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 28, 4);
-
- switch (eice_version)
- {
- case 1:
- reg_list[EICE_DBG_CTRL].size = 3;
- reg_list[EICE_DBG_STAT].size = 5;
- break;
- case 2:
- reg_list[EICE_DBG_CTRL].size = 4;
- reg_list[EICE_DBG_STAT].size = 5;
- arm7_9->has_single_step = 1;
- break;
- case 3:
- ERROR("EmbeddedICE version 3 detected, EmbeddedICE handling might be broken");
- reg_list[EICE_DBG_CTRL].size = 6;
- reg_list[EICE_DBG_STAT].size = 5;
- arm7_9->has_single_step = 1;
- arm7_9->has_monitor_mode = 1;
- break;
- case 4:
- reg_list[EICE_DBG_CTRL].size = 6;
- reg_list[EICE_DBG_STAT].size = 5;
- arm7_9->has_monitor_mode = 1;
- break;
- case 5:
- reg_list[EICE_DBG_CTRL].size = 6;
- reg_list[EICE_DBG_STAT].size = 5;
- arm7_9->has_single_step = 1;
- arm7_9->has_monitor_mode = 1;
- break;
- case 6:
- reg_list[EICE_DBG_CTRL].size = 6;
- reg_list[EICE_DBG_STAT].size = 10;
- arm7_9->has_monitor_mode = 1;
- break;
- case 7:
- WARNING("EmbeddedICE version 7 detected, EmbeddedICE handling might be broken");
- reg_list[EICE_DBG_CTRL].size = 6;
- reg_list[EICE_DBG_STAT].size = 5;
- arm7_9->has_monitor_mode = 1;
- break;
- default:
- ERROR("unknown EmbeddedICE version (comms ctrl: 0x%8.8x)", buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 0, 32));
- }
-
- /* explicitly disable monitor mode */
- if (arm7_9->has_monitor_mode)
- {
- embeddedice_read_reg(®_list[EICE_DBG_CTRL]);
- jtag_execute_queue();
- buf_set_u32(reg_list[EICE_DBG_CTRL].value, 4, 1, 0);
- embeddedice_set_reg_w_exec(®_list[EICE_DBG_CTRL], reg_list[EICE_DBG_CTRL].value);
- }
-
- return reg_cache;
-}
-
-int embeddedice_get_reg(reg_t *reg)
-{
- if (embeddedice_read_reg(reg) != ERROR_OK)
- {
- ERROR("BUG: error scheduling EmbeddedICE register read");
- exit(-1);
- }
-
- if (jtag_execute_queue() != ERROR_OK)
- {
- ERROR("register read failed");
- }
-
- return ERROR_OK;
-}
-
-int embeddedice_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask)
-{
- embeddedice_reg_t *ice_reg = reg->arch_info;
- u8 reg_addr = ice_reg->addr & 0x1f;
- scan_field_t fields[3];
- u8 field1_out[1];
- u8 field2_out[1];
-
- DEBUG("%i", ice_reg->addr);
-
- jtag_add_end_state(TAP_RTI);
- arm_jtag_scann(ice_reg->jtag_info, 0x2);
-
- arm_jtag_set_instr(ice_reg->jtag_info, ice_reg->jtag_info->intest_instr, NULL);
-
- fields[0].device = ice_reg->jtag_info->chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = reg->value;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = ice_reg->jtag_info->chain_pos;
- fields[1].num_bits = 5;
- fields[1].out_value = field1_out;
- buf_set_u32(fields[1].out_value, 0, 5, reg_addr);
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = ice_reg->jtag_info->chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = field2_out;
- buf_set_u32(fields[2].out_value, 0, 1, 0);
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- jtag_add_dr_scan(3, fields, -1);
-
- fields[0].in_value = reg->value;
- jtag_set_check_value(fields+0, check_value, check_mask, NULL);
-
- /* when reading the DCC data register, leaving the address field set to
- * EICE_COMMS_DATA would read the register twice
- * reading the control register is safe
- */
- buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]);
-
- jtag_add_dr_scan(3, fields, -1);
-
- return ERROR_OK;
-}
-
-/* receive <size> words of 32 bit from the DCC
- * we pretend the target is always going to be fast enough
- * (relative to the JTAG clock), so we don't need to handshake
- */
-int embeddedice_receive(arm_jtag_t *jtag_info, u32 *data, u32 size)
-{
- scan_field_t fields[3];
- u8 field1_out[1];
- u8 field2_out[1];
-
- jtag_add_end_state(TAP_RTI);
- arm_jtag_scann(jtag_info, 0x2);
- arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = NULL;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 5;
- fields[1].out_value = field1_out;
- buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_DATA]);
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = jtag_info->chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = field2_out;
- buf_set_u32(fields[2].out_value, 0, 1, 0);
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- jtag_add_dr_scan(3, fields, -1);
-
- while (size > 0)
- {
- /* when reading the last item, set the register address to the DCC control reg,
- * to avoid reading additional data from the DCC data reg
- */
- if (size == 1)
- buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]);
-
- fields[0].in_handler = arm_jtag_buf_to_u32;
- fields[0].in_handler_priv = data;
- jtag_add_dr_scan(3, fields, -1);
-
- data++;
- size--;
- }
-
- return jtag_execute_queue();
-}
-
-int embeddedice_read_reg(reg_t *reg)
-{
- return embeddedice_read_reg_w_check(reg, NULL, NULL);
-}
-
-int embeddedice_set_reg(reg_t *reg, u32 value)
-{
- if (embeddedice_write_reg(reg, value) != ERROR_OK)
- {
- ERROR("BUG: error scheduling EmbeddedICE register write");
- exit(-1);
- }
-
- buf_set_u32(reg->value, 0, reg->size, value);
- reg->valid = 1;
- reg->dirty = 0;
-
- return ERROR_OK;
-}
-
-int embeddedice_set_reg_w_exec(reg_t *reg, u8 *buf)
-{
- embeddedice_set_reg(reg, buf_get_u32(buf, 0, reg->size));
-
- if (jtag_execute_queue() != ERROR_OK)
- {
- ERROR("register write failed");
- exit(-1);
- }
- return ERROR_OK;
-}
-
-int embeddedice_write_reg(reg_t *reg, u32 value)
-{
- embeddedice_reg_t *ice_reg = reg->arch_info;
- u8 reg_addr = ice_reg->addr & 0x1f;
- scan_field_t fields[3];
- u8 field0_out[4];
- u8 field1_out[1];
- u8 field2_out[1];
-
- DEBUG("%i: 0x%8.8x", ice_reg->addr, value);
-
- jtag_add_end_state(TAP_RTI);
- arm_jtag_scann(ice_reg->jtag_info, 0x2);
-
- arm_jtag_set_instr(ice_reg->jtag_info, ice_reg->jtag_info->intest_instr, NULL);
-
- fields[0].device = ice_reg->jtag_info->chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = field0_out;
- buf_set_u32(fields[0].out_value, 0, 32, value);
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = ice_reg->jtag_info->chain_pos;
- fields[1].num_bits = 5;
- fields[1].out_value = field1_out;
- buf_set_u32(fields[1].out_value, 0, 5, reg_addr);
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = ice_reg->jtag_info->chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = field2_out;
- buf_set_u32(fields[2].out_value, 0, 1, 1);
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- jtag_add_dr_scan(3, fields, -1);
-
- return ERROR_OK;
-}
-
-int embeddedice_store_reg(reg_t *reg)
-{
- return embeddedice_write_reg(reg, buf_get_u32(reg->value, 0, reg->size));
-}
-
-/* send <size> words of 32 bit to the DCC
- * we pretend the target is always going to be fast enough
- * (relative to the JTAG clock), so we don't need to handshake
- */
-int embeddedice_send(arm_jtag_t *jtag_info, u32 *data, u32 size)
-{
- scan_field_t fields[3];
- u8 field0_out[4];
- u8 field1_out[1];
- u8 field2_out[1];
-
- jtag_add_end_state(TAP_RTI);
- arm_jtag_scann(jtag_info, 0x2);
- arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = field0_out;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 5;
- fields[1].out_value = field1_out;
- buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_DATA]);
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = jtag_info->chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = field2_out;
- buf_set_u32(fields[2].out_value, 0, 1, 1);
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- while (size > 0)
- {
- buf_set_u32(fields[0].out_value, 0, 32, *data);
- jtag_add_dr_scan(3, fields, -1);
-
- data++;
- size--;
- }
-
- /* call to jtag_execute_queue() intentionally omitted */
- return ERROR_OK;
-}
-
-/* wait for DCC control register R/W handshake bit to become active
- */
-int embeddedice_handshake(arm_jtag_t *jtag_info, int hsbit, u32 timeout)
-{
- scan_field_t fields[3];
- u8 field0_in[4];
- u8 field1_out[1];
- u8 field2_out[1];
- int retval;
- int hsact;
- struct timeval lap;
- struct timeval now;
-
- if (hsbit == EICE_COMM_CTRL_WBIT)
- hsact = 1;
- else if (hsbit == EICE_COMM_CTRL_RBIT)
- hsact = 0;
- else
- return ERROR_INVALID_ARGUMENTS;
-
- jtag_add_end_state(TAP_RTI);
- arm_jtag_scann(jtag_info, 0x2);
- arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL);
-
- fields[0].device = jtag_info->chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = NULL;
- fields[0].out_mask = NULL;
- fields[0].in_value = field0_in;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = jtag_info->chain_pos;
- fields[1].num_bits = 5;
- fields[1].out_value = field1_out;
- buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]);
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = jtag_info->chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = field2_out;
- buf_set_u32(fields[2].out_value, 0, 1, 0);
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- jtag_add_dr_scan(3, fields, -1);
- gettimeofday(&lap, NULL);
- do
- {
- jtag_add_dr_scan(3, fields, -1);
- if ((retval = jtag_execute_queue()) != ERROR_OK)
- return retval;
-
- if (buf_get_u32(field0_in, hsbit, 1) == hsact)
- return ERROR_OK;
-
- gettimeofday(&now, NULL);
- }
- while ((now.tv_sec-lap.tv_sec)*1000 + (now.tv_usec-lap.tv_usec)/1000 <= timeout);
-
- return ERROR_TARGET_TIMEOUT;
-}
+/*************************************************************************** + * 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 "embeddedice.h" + +#include "armv4_5.h" +#include "arm7_9_common.h" + +#include "log.h" +#include "arm_jtag.h" +#include "types.h" +#include "binarybuffer.h" +#include "target.h" +#include "register.h" +#include "jtag.h" + +#include <stdlib.h> + +bitfield_desc_t embeddedice_comms_ctrl_bitfield_desc[] = +{ + {"R", 1}, + {"W", 1}, + {"reserved", 26}, + {"version", 4} +}; + +int embeddedice_reg_arch_info[] = +{ + 0x0, 0x1, 0x4, 0x5, + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x2 +}; + +char* embeddedice_reg_list[] = +{ + "debug_ctrl", + "debug_status", + + "comms_ctrl", + "comms_data", + + "watch 0 addr value", + "watch 0 addr mask", + "watch 0 data value", + "watch 0 data mask", + "watch 0 control value", + "watch 0 control mask", + + "watch 1 addr value", + "watch 1 addr mask", + "watch 1 data value", + "watch 1 data mask", + "watch 1 control value", + "watch 1 control mask", + + "vector catch" +}; + +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); + +reg_cache_t* embeddedice_build_reg_cache(target_t *target, arm7_9_common_t *arm7_9) +{ + reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t)); + reg_t *reg_list = NULL; + embeddedice_reg_t *arch_info = NULL; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + int num_regs; + int i; + int eice_version = 0; + + /* register a register arch-type for EmbeddedICE registers only once */ + if (embeddedice_reg_arch_type == -1) + embeddedice_reg_arch_type = register_reg_arch_type(embeddedice_get_reg, embeddedice_set_reg_w_exec); + + if (arm7_9->has_vector_catch) + num_regs = 17; + else + num_regs = 16; + + /* the actual registers are kept in two arrays */ + reg_list = calloc(num_regs, sizeof(reg_t)); + arch_info = calloc(num_regs, sizeof(embeddedice_reg_t)); + + /* fill in values for the reg cache */ + reg_cache->name = "EmbeddedICE registers"; + reg_cache->next = NULL; + reg_cache->reg_list = reg_list; + reg_cache->num_regs = num_regs; + + /* set up registers */ + for (i = 0; i < num_regs; i++) + { + reg_list[i].name = embeddedice_reg_list[i]; + reg_list[i].size = 32; + reg_list[i].dirty = 0; + reg_list[i].valid = 0; + reg_list[i].bitfield_desc = NULL; + reg_list[i].num_bitfields = 0; + reg_list[i].value = calloc(1, 4); + reg_list[i].arch_info = &arch_info[i]; + reg_list[i].arch_type = embeddedice_reg_arch_type; + arch_info[i].addr = embeddedice_reg_arch_info[i]; + arch_info[i].jtag_info = jtag_info; + } + + /* identify EmbeddedICE version by reading DCC control register */ + embeddedice_read_reg(®_list[EICE_COMMS_CTRL]); + jtag_execute_queue(); + + eice_version = buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 28, 4); + + switch (eice_version) + { + case 1: + reg_list[EICE_DBG_CTRL].size = 3; + reg_list[EICE_DBG_STAT].size = 5; + break; + case 2: + reg_list[EICE_DBG_CTRL].size = 4; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_single_step = 1; + break; + case 3: + ERROR("EmbeddedICE version 3 detected, EmbeddedICE handling might be broken"); + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_single_step = 1; + arm7_9->has_monitor_mode = 1; + break; + case 4: + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_monitor_mode = 1; + break; + case 5: + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_single_step = 1; + arm7_9->has_monitor_mode = 1; + break; + case 6: + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 10; + arm7_9->has_monitor_mode = 1; + break; + case 7: + WARNING("EmbeddedICE version 7 detected, EmbeddedICE handling might be broken"); + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_monitor_mode = 1; + break; + default: + ERROR("unknown EmbeddedICE version (comms ctrl: 0x%8.8x)", buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 0, 32)); + } + + /* explicitly disable monitor mode */ + if (arm7_9->has_monitor_mode) + { + embeddedice_read_reg(®_list[EICE_DBG_CTRL]); + jtag_execute_queue(); + buf_set_u32(reg_list[EICE_DBG_CTRL].value, 4, 1, 0); + embeddedice_set_reg_w_exec(®_list[EICE_DBG_CTRL], reg_list[EICE_DBG_CTRL].value); + } + + return reg_cache; +} + +int embeddedice_get_reg(reg_t *reg) +{ + if (embeddedice_read_reg(reg) != ERROR_OK) + { + ERROR("BUG: error scheduling EmbeddedICE register read"); + exit(-1); + } + + if (jtag_execute_queue() != ERROR_OK) + { + ERROR("register read failed"); + } + + return ERROR_OK; +} + +int embeddedice_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask) +{ + embeddedice_reg_t *ice_reg = reg->arch_info; + u8 reg_addr = ice_reg->addr & 0x1f; + scan_field_t fields[3]; + u8 field1_out[1]; + u8 field2_out[1]; + + DEBUG("%i", ice_reg->addr); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(ice_reg->jtag_info, 0x2); + + arm_jtag_set_instr(ice_reg->jtag_info, ice_reg->jtag_info->intest_instr, NULL); + + fields[0].device = ice_reg->jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = reg->value; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = ice_reg->jtag_info->chain_pos; + fields[1].num_bits = 5; + fields[1].out_value = field1_out; + buf_set_u32(fields[1].out_value, 0, 5, reg_addr); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = ice_reg->jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = field2_out; + buf_set_u32(fields[2].out_value, 0, 1, 0); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + fields[0].in_value = reg->value; + jtag_set_check_value(fields+0, check_value, check_mask, NULL); + + /* when reading the DCC data register, leaving the address field set to + * EICE_COMMS_DATA would read the register twice + * reading the control register is safe + */ + buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]); + + jtag_add_dr_scan(3, fields, -1); + + return ERROR_OK; +} + +/* receive <size> words of 32 bit from the DCC + * we pretend the target is always going to be fast enough + * (relative to the JTAG clock), so we don't need to handshake + */ +int embeddedice_receive(arm_jtag_t *jtag_info, u32 *data, u32 size) +{ + scan_field_t fields[3]; + u8 field1_out[1]; + u8 field2_out[1]; + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0x2); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 5; + fields[1].out_value = field1_out; + buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_DATA]); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = field2_out; + buf_set_u32(fields[2].out_value, 0, 1, 0); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + while (size > 0) + { + /* when reading the last item, set the register address to the DCC control reg, + * to avoid reading additional data from the DCC data reg + */ + if (size == 1) + buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]); + + fields[0].in_handler = arm_jtag_buf_to_u32; + fields[0].in_handler_priv = data; + jtag_add_dr_scan(3, fields, -1); + + data++; + size--; + } + + return jtag_execute_queue(); +} + +int embeddedice_read_reg(reg_t *reg) +{ + return embeddedice_read_reg_w_check(reg, NULL, NULL); +} + +int embeddedice_set_reg(reg_t *reg, u32 value) +{ + if (embeddedice_write_reg(reg, value) != ERROR_OK) + { + ERROR("BUG: error scheduling EmbeddedICE register write"); + exit(-1); + } + + buf_set_u32(reg->value, 0, reg->size, value); + reg->valid = 1; + reg->dirty = 0; + + return ERROR_OK; +} + +int embeddedice_set_reg_w_exec(reg_t *reg, u8 *buf) +{ + embeddedice_set_reg(reg, buf_get_u32(buf, 0, reg->size)); + + if (jtag_execute_queue() != ERROR_OK) + { + ERROR("register write failed"); + exit(-1); + } + return ERROR_OK; +} + +int embeddedice_write_reg(reg_t *reg, u32 value) +{ + embeddedice_reg_t *ice_reg = reg->arch_info; + u8 reg_addr = ice_reg->addr & 0x1f; + scan_field_t fields[3]; + u8 field0_out[4]; + u8 field1_out[1]; + u8 field2_out[1]; + + DEBUG("%i: 0x%8.8x", ice_reg->addr, value); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(ice_reg->jtag_info, 0x2); + + arm_jtag_set_instr(ice_reg->jtag_info, ice_reg->jtag_info->intest_instr, NULL); + + fields[0].device = ice_reg->jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = field0_out; + buf_set_u32(fields[0].out_value, 0, 32, value); + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = ice_reg->jtag_info->chain_pos; + fields[1].num_bits = 5; + fields[1].out_value = field1_out; + buf_set_u32(fields[1].out_value, 0, 5, reg_addr); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = ice_reg->jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = field2_out; + buf_set_u32(fields[2].out_value, 0, 1, 1); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + return ERROR_OK; +} + +int embeddedice_store_reg(reg_t *reg) +{ + return embeddedice_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); +} + +/* send <size> words of 32 bit to the DCC + * we pretend the target is always going to be fast enough + * (relative to the JTAG clock), so we don't need to handshake + */ +int embeddedice_send(arm_jtag_t *jtag_info, u32 *data, u32 size) +{ + scan_field_t fields[3]; + u8 field0_out[4]; + u8 field1_out[1]; + u8 field2_out[1]; + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0x2); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = field0_out; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 5; + fields[1].out_value = field1_out; + buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_DATA]); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = field2_out; + buf_set_u32(fields[2].out_value, 0, 1, 1); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + while (size > 0) + { + buf_set_u32(fields[0].out_value, 0, 32, *data); + jtag_add_dr_scan(3, fields, -1); + + data++; + size--; + } + + /* call to jtag_execute_queue() intentionally omitted */ + return ERROR_OK; +} + +/* wait for DCC control register R/W handshake bit to become active + */ +int embeddedice_handshake(arm_jtag_t *jtag_info, int hsbit, u32 timeout) +{ + scan_field_t fields[3]; + u8 field0_in[4]; + u8 field1_out[1]; + u8 field2_out[1]; + int retval; + int hsact; + struct timeval lap; + struct timeval now; + + if (hsbit == EICE_COMM_CTRL_WBIT) + hsact = 1; + else if (hsbit == EICE_COMM_CTRL_RBIT) + hsact = 0; + else + return ERROR_INVALID_ARGUMENTS; + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0x2); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = field0_in; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 5; + fields[1].out_value = field1_out; + buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = field2_out; + buf_set_u32(fields[2].out_value, 0, 1, 0); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + gettimeofday(&lap, NULL); + do + { + jtag_add_dr_scan(3, fields, -1); + if ((retval = jtag_execute_queue()) != ERROR_OK) + return retval; + + if (buf_get_u32(field0_in, hsbit, 1) == hsact) + return ERROR_OK; + + gettimeofday(&now, NULL); + } + while ((now.tv_sec-lap.tv_sec)*1000 + (now.tv_usec-lap.tv_usec)/1000 <= timeout); + + return ERROR_TARGET_TIMEOUT; +} diff --git a/src/target/etb.c b/src/target/etb.c index 6c9d3a0..ff4113e 100644 --- a/src/target/etb.c +++ b/src/target/etb.c @@ -1,741 +1,741 @@ -/***************************************************************************
- * Copyright (C) 2007 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 <string.h>
-
-#include "arm7_9_common.h"
-#include "etb.h"
-#include "etm.h"
-
-#include "log.h"
-#include "types.h"
-#include "binarybuffer.h"
-#include "target.h"
-#include "register.h"
-#include "jtag.h"
-
-#include <stdlib.h>
-
-char* etb_reg_list[] =
-{
- "ETB_identification",
- "ETB_ram_depth",
- "ETB_ram_width",
- "ETB_status",
- "ETB_ram_data",
- "ETB_ram_read_pointer",
- "ETB_ram_write_pointer",
- "ETB_trigger_counter",
- "ETB_control",
-};
-
-int etb_reg_arch_type = -1;
-
-int etb_get_reg(reg_t *reg);
-int etb_set_reg(reg_t *reg, u32 value);
-int etb_set_reg_w_exec(reg_t *reg, u8 *buf);
-
-int etb_write_reg(reg_t *reg, u32 value);
-int etb_read_reg(reg_t *reg);
-
-int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-int etb_set_instr(etb_t *etb, u32 new_instr)
-{
- jtag_device_t *device = jtag_get_device(etb->chain_pos);
-
- if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr)
- {
- scan_field_t field;
-
- field.device = etb->chain_pos;
- field.num_bits = device->ir_length;
- field.out_value = calloc(CEIL(field.num_bits, 8), 1);
- buf_set_u32(field.out_value, 0, field.num_bits, new_instr);
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- jtag_add_ir_scan(1, &field, -1);
-
- free(field.out_value);
- }
-
- return ERROR_OK;
-}
-
-int etb_scann(etb_t *etb, u32 new_scan_chain)
-{
- if(etb->cur_scan_chain != new_scan_chain)
- {
- scan_field_t field;
-
- field.device = etb->chain_pos;
- field.num_bits = 5;
- field.out_value = calloc(CEIL(field.num_bits, 8), 1);
- buf_set_u32(field.out_value, 0, field.num_bits, new_scan_chain);
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
-
- /* select INTEST instruction */
- etb_set_instr(etb, 0x2);
- jtag_add_dr_scan(1, &field, -1);
-
- etb->cur_scan_chain = new_scan_chain;
-
- free(field.out_value);
- }
-
- return ERROR_OK;
-}
-
-reg_cache_t* etb_build_reg_cache(etb_t *etb)
-{
- reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t));
- reg_t *reg_list = NULL;
- etb_reg_t *arch_info = NULL;
- int num_regs = 9;
- int i;
-
- /* register a register arch-type for etm registers only once */
- if (etb_reg_arch_type == -1)
- etb_reg_arch_type = register_reg_arch_type(etb_get_reg, etb_set_reg_w_exec);
-
- /* the actual registers are kept in two arrays */
- reg_list = calloc(num_regs, sizeof(reg_t));
- arch_info = calloc(num_regs, sizeof(etb_reg_t));
-
- /* fill in values for the reg cache */
- reg_cache->name = "etb registers";
- reg_cache->next = NULL;
- reg_cache->reg_list = reg_list;
- reg_cache->num_regs = num_regs;
-
- /* set up registers */
- for (i = 0; i < num_regs; i++)
- {
- reg_list[i].name = etb_reg_list[i];
- reg_list[i].size = 32;
- reg_list[i].dirty = 0;
- reg_list[i].valid = 0;
- reg_list[i].bitfield_desc = NULL;
- reg_list[i].num_bitfields = 0;
- reg_list[i].value = calloc(1, 4);
- reg_list[i].arch_info = &arch_info[i];
- reg_list[i].arch_type = etb_reg_arch_type;
- reg_list[i].size = 32;
- arch_info[i].addr = i;
- arch_info[i].etb = etb;
- }
-
- return reg_cache;
-}
-
-int etb_get_reg(reg_t *reg)
-{
- if (etb_read_reg(reg) != ERROR_OK)
- {
- ERROR("BUG: error scheduling etm register read");
- exit(-1);
- }
-
- if (jtag_execute_queue() != ERROR_OK)
- {
- ERROR("register read failed");
- }
-
- return ERROR_OK;
-}
-
-int etb_read_ram(etb_t *etb, u32 *data, int num_frames)
-{
- scan_field_t fields[3];
- int i;
-
- jtag_add_end_state(TAP_RTI);
- etb_scann(etb, 0x0);
- etb_set_instr(etb, 0xc);
-
- fields[0].device = etb->chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = NULL;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = etb->chain_pos;
- fields[1].num_bits = 7;
- fields[1].out_value = malloc(1);
- buf_set_u32(fields[1].out_value, 0, 7, 4);
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = etb->chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = malloc(1);
- buf_set_u32(fields[2].out_value, 0, 1, 0);
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- jtag_add_dr_scan(3, fields, -1);
-
- fields[0].in_handler = buf_to_u32_handler;
-
- for (i = 0; i < num_frames; i++)
- {
- /* ensure nR/W reamins set to read */
- buf_set_u32(fields[2].out_value, 0, 1, 0);
-
- /* address remains set to 0x4 (RAM data) until we read the last frame */
- if (i < num_frames - 1)
- buf_set_u32(fields[1].out_value, 0, 7, 4);
- else
- buf_set_u32(fields[1].out_value, 0, 7, 0);
-
- fields[0].in_handler_priv = &data[i];
- jtag_add_dr_scan(3, fields, -1);
- }
-
- jtag_execute_queue();
-
- free(fields[1].out_value);
- free(fields[2].out_value);
-
- return ERROR_OK;
-}
-
-int etb_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask)
-{
- etb_reg_t *etb_reg = reg->arch_info;
- u8 reg_addr = etb_reg->addr & 0x7f;
- scan_field_t fields[3];
-
- DEBUG("%i", etb_reg->addr);
-
- jtag_add_end_state(TAP_RTI);
- etb_scann(etb_reg->etb, 0x0);
- etb_set_instr(etb_reg->etb, 0xc);
-
- fields[0].device = etb_reg->etb->chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = reg->value;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = etb_reg->etb->chain_pos;
- fields[1].num_bits = 7;
- fields[1].out_value = malloc(1);
- buf_set_u32(fields[1].out_value, 0, 7, reg_addr);
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = etb_reg->etb->chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = malloc(1);
- buf_set_u32(fields[2].out_value, 0, 1, 0);
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- jtag_add_dr_scan(3, fields, -1);
-
- /* read the identification register in the second run, to make sure we
- * don't read the ETB data register twice, skipping every second entry
- */
- buf_set_u32(fields[1].out_value, 0, 7, 0x0);
- fields[0].in_value = reg->value;
-
- jtag_set_check_value(fields+0, check_value, check_mask, NULL);
-
- jtag_add_dr_scan(3, fields, -1);
-
- free(fields[1].out_value);
- free(fields[2].out_value);
-
- return ERROR_OK;
-}
-
-int etb_read_reg(reg_t *reg)
-{
- return etb_read_reg_w_check(reg, NULL, NULL);
-}
-
-int etb_set_reg(reg_t *reg, u32 value)
-{
- if (etb_write_reg(reg, value) != ERROR_OK)
- {
- ERROR("BUG: error scheduling etm register write");
- exit(-1);
- }
-
- buf_set_u32(reg->value, 0, reg->size, value);
- reg->valid = 1;
- reg->dirty = 0;
-
- return ERROR_OK;
-}
-
-int etb_set_reg_w_exec(reg_t *reg, u8 *buf)
-{
- etb_set_reg(reg, buf_get_u32(buf, 0, reg->size));
-
- if (jtag_execute_queue() != ERROR_OK)
- {
- ERROR("register write failed");
- exit(-1);
- }
- return ERROR_OK;
-}
-
-int etb_write_reg(reg_t *reg, u32 value)
-{
- etb_reg_t *etb_reg = reg->arch_info;
- u8 reg_addr = etb_reg->addr & 0x7f;
- scan_field_t fields[3];
-
- DEBUG("%i: 0x%8.8x", etb_reg->addr, value);
-
- jtag_add_end_state(TAP_RTI);
- etb_scann(etb_reg->etb, 0x0);
- etb_set_instr(etb_reg->etb, 0xc);
-
- fields[0].device = etb_reg->etb->chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = malloc(4);
- buf_set_u32(fields[0].out_value, 0, 32, value);
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = etb_reg->etb->chain_pos;
- fields[1].num_bits = 7;
- fields[1].out_value = malloc(1);
- buf_set_u32(fields[1].out_value, 0, 7, reg_addr);
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = etb_reg->etb->chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = malloc(1);
- buf_set_u32(fields[2].out_value, 0, 1, 1);
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- jtag_add_dr_scan(3, fields, -1);
-
- free(fields[0].out_value);
- free(fields[1].out_value);
- free(fields[2].out_value);
-
- return ERROR_OK;
-}
-
-int etb_store_reg(reg_t *reg)
-{
- return etb_write_reg(reg, buf_get_u32(reg->value, 0, reg->size));
-}
-
-int etb_register_commands(struct command_context_s *cmd_ctx)
-{
- command_t *etb_cmd;
-
- etb_cmd = register_command(cmd_ctx, NULL, "etb", NULL, COMMAND_ANY, "Embedded Trace Buffer");
-
- register_command(cmd_ctx, etb_cmd, "config", handle_etb_config_command, COMMAND_CONFIG, NULL);
-
- return ERROR_OK;
-}
-
-int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target;
- jtag_device_t *jtag_device;
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
-
- if (argc != 2)
- {
- ERROR("incomplete 'etb config <target> <chain_pos>' command");
- exit(-1);
- }
-
- target = get_target_by_num(strtoul(args[0], NULL, 0));
-
- if (!target)
- {
- ERROR("target number '%s' not defined", args[0]);
- exit(-1);
- }
-
- if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
- return ERROR_OK;
- }
-
- jtag_device = jtag_get_device(strtoul(args[1], NULL, 0));
-
- if (!jtag_device)
- {
- ERROR("jtag device number '%s' not defined", args[1]);
- exit(-1);
- }
-
- if (arm7_9->etm_ctx)
- {
- etb_t *etb = malloc(sizeof(etb_t));
-
- arm7_9->etm_ctx->capture_driver_priv = etb;
-
- etb->chain_pos = strtoul(args[1], NULL, 0);
- etb->cur_scan_chain = -1;
- etb->reg_cache = NULL;
- etb->ram_width = 0;
- etb->ram_depth = 0;
- }
- else
- {
- ERROR("target has no ETM defined, ETB left unconfigured");
- }
-
- return ERROR_OK;
-}
-
-int etb_init(etm_context_t *etm_ctx)
-{
- etb_t *etb = etm_ctx->capture_driver_priv;
-
- etb->etm_ctx = etm_ctx;
-
- /* identify ETB RAM depth and width */
- etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_DEPTH]);
- etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WIDTH]);
- jtag_execute_queue();
-
- etb->ram_depth = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_DEPTH].value, 0, 32);
- etb->ram_width = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WIDTH].value, 0, 32);
-
- return ERROR_OK;
-}
-
-trace_status_t etb_status(etm_context_t *etm_ctx)
-{
- etb_t *etb = etm_ctx->capture_driver_priv;
-
- etb->etm_ctx = etm_ctx;
-
- /* if tracing is currently idle, return this information */
- if (etm_ctx->capture_status == TRACE_IDLE)
- {
- return etm_ctx->capture_status;
- }
- else if (etm_ctx->capture_status & TRACE_RUNNING)
- {
- reg_t *etb_status_reg = &etb->reg_cache->reg_list[ETB_STATUS];
- int etb_timeout = 100;
-
- /* trace is running, check the ETB status flags */
- etb_get_reg(etb_status_reg);
-
- /* check Full bit to identify an overflow */
- if (buf_get_u32(etb_status_reg->value, 0, 1) == 1)
- etm_ctx->capture_status |= TRACE_OVERFLOWED;
-
- /* check Triggered bit to identify trigger condition */
- if (buf_get_u32(etb_status_reg->value, 1, 1) == 1)
- etm_ctx->capture_status |= TRACE_TRIGGERED;
-
- /* check AcqComp to identify trace completion */
- if (buf_get_u32(etb_status_reg->value, 2, 1) == 1)
- {
- while (etb_timeout-- && (buf_get_u32(etb_status_reg->value, 3, 1) == 0))
- {
- /* wait for data formatter idle */
- etb_get_reg(etb_status_reg);
- }
-
- if (etb_timeout == 0)
- {
- ERROR("AcqComp set but DFEmpty won't go high, ETB status: 0x%x",
- buf_get_u32(etb_status_reg->value, 0, etb_status_reg->size));
- }
-
- if (!(etm_ctx->capture_status && TRACE_TRIGGERED))
- {
- ERROR("trace completed, but no trigger condition detected");
- }
-
- etm_ctx->capture_status &= ~TRACE_RUNNING;
- etm_ctx->capture_status |= TRACE_COMPLETED;
- }
- }
-
- return etm_ctx->capture_status;
-}
-
-int etb_read_trace(etm_context_t *etm_ctx)
-{
- etb_t *etb = etm_ctx->capture_driver_priv;
- int first_frame = 0;
- int num_frames = etb->ram_depth;
- u32 *trace_data = NULL;
- int i, j;
-
- etb_read_reg(&etb->reg_cache->reg_list[ETB_STATUS]);
- etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER]);
- jtag_execute_queue();
-
- /* check if we overflowed, and adjust first frame of the trace accordingly
- * if we didn't overflow, read only up to the frame that would be written next,
- * i.e. don't read invalid entries
- */
- if (buf_get_u32(etb->reg_cache->reg_list[ETB_STATUS].value, 0, 1))
- {
- first_frame = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32);
- }
- else
- {
- num_frames = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32);
- }
-
- etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_READ_POINTER], first_frame);
-
- /* read data into temporary array for unpacking */
- trace_data = malloc(sizeof(u32) * num_frames);
- etb_read_ram(etb, trace_data, num_frames);
-
- if (etm_ctx->trace_depth > 0)
- {
- free(etm_ctx->trace_data);
- }
-
- if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT)
- etm_ctx->trace_depth = num_frames * 3;
- else if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT)
- etm_ctx->trace_depth = num_frames * 2;
- else
- etm_ctx->trace_depth = num_frames;
-
- etm_ctx->trace_data = malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth);
-
- for (i = 0, j = 0; i < num_frames; i++)
- {
- if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT)
- {
- /* trace word j */
- etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7;
- etm_ctx->trace_data[j].packet = (trace_data[i] & 0x78) >> 3;
- etm_ctx->trace_data[j].flags = 0;
- if ((trace_data[i] & 0x80) >> 7)
- {
- etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE;
- }
- if (etm_ctx->trace_data[j].pipestat == STAT_TR)
- {
- etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7;
- etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE;
- }
-
- /* trace word j+1 */
- etm_ctx->trace_data[j+1].pipestat = (trace_data[i] & 0x100) >> 8;
- etm_ctx->trace_data[j+1].packet = (trace_data[i] & 0x7800) >> 11;
- etm_ctx->trace_data[j+1].flags = 0;
- if ((trace_data[i] & 0x8000) >> 15)
- {
- etm_ctx->trace_data[j+1].flags |= ETMV1_TRACESYNC_CYCLE;
- }
- if (etm_ctx->trace_data[j+1].pipestat == STAT_TR)
- {
- etm_ctx->trace_data[j+1].pipestat = etm_ctx->trace_data[j+1].packet & 0x7;
- etm_ctx->trace_data[j+1].flags |= ETMV1_TRIGGER_CYCLE;
- }
-
- /* trace word j+2 */
- etm_ctx->trace_data[j+2].pipestat = (trace_data[i] & 0x10000) >> 16;
- etm_ctx->trace_data[j+2].packet = (trace_data[i] & 0x780000) >> 19;
- etm_ctx->trace_data[j+2].flags = 0;
- if ((trace_data[i] & 0x800000) >> 23)
- {
- etm_ctx->trace_data[j+2].flags |= ETMV1_TRACESYNC_CYCLE;
- }
- if (etm_ctx->trace_data[j+2].pipestat == STAT_TR)
- {
- etm_ctx->trace_data[j+2].pipestat = etm_ctx->trace_data[j+2].packet & 0x7;
- etm_ctx->trace_data[j+2].flags |= ETMV1_TRIGGER_CYCLE;
- }
-
- j += 3;
- }
- else if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT)
- {
- /* trace word j */
- etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7;
- etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7f8) >> 3;
- etm_ctx->trace_data[j].flags = 0;
- if ((trace_data[i] & 0x800) >> 11)
- {
- etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE;
- }
- if (etm_ctx->trace_data[j].pipestat == STAT_TR)
- {
- etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7;
- etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE;
- }
-
- /* trace word j+1 */
- etm_ctx->trace_data[j+1].pipestat = (trace_data[i] & 0x7000) >> 12;
- etm_ctx->trace_data[j+1].packet = (trace_data[i] & 0x7f8000) >> 15;
- etm_ctx->trace_data[j+1].flags = 0;
- if ((trace_data[i] & 0x800000) >> 23)
- {
- etm_ctx->trace_data[j+1].flags |= ETMV1_TRACESYNC_CYCLE;
- }
- if (etm_ctx->trace_data[j+1].pipestat == STAT_TR)
- {
- etm_ctx->trace_data[j+1].pipestat = etm_ctx->trace_data[j+1].packet & 0x7;
- etm_ctx->trace_data[j+1].flags |= ETMV1_TRIGGER_CYCLE;
- }
-
- j += 2;
- }
- else
- {
- /* trace word j */
- etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7;
- etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7fff8) >> 3;
- etm_ctx->trace_data[j].flags = 0;
- if ((trace_data[i] & 0x80000) >> 19)
- {
- etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE;
- }
- if (etm_ctx->trace_data[j].pipestat == STAT_TR)
- {
- etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7;
- etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE;
- }
-
- j += 1;
- }
- }
-
- free(trace_data);
-
- return ERROR_OK;
-}
-
-int etb_start_capture(etm_context_t *etm_ctx)
-{
- etb_t *etb = etm_ctx->capture_driver_priv;
- u32 etb_ctrl_value = 0x1;
- u32 trigger_count;
-
- if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED)
- {
- if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) != ETM_PORT_8BIT)
- {
- ERROR("ETB can't run in demultiplexed mode with a 4 or 16 bit port");
- return ERROR_ETM_PORTMODE_NOT_SUPPORTED;
- }
- etb_ctrl_value |= 0x2;
- }
-
- if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_MUXED)
- return ERROR_ETM_PORTMODE_NOT_SUPPORTED;
-
- trigger_count = (etb->ram_depth * etm_ctx->trigger_percent) / 100;
-
- etb_write_reg(&etb->reg_cache->reg_list[ETB_TRIGGER_COUNTER], trigger_count);
- etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER], 0x0);
- etb_write_reg(&etb->reg_cache->reg_list[ETB_CTRL], etb_ctrl_value);
- jtag_execute_queue();
-
- /* we're starting a new trace, initialize capture status */
- etm_ctx->capture_status = TRACE_RUNNING;
-
- return ERROR_OK;
-}
-
-int etb_stop_capture(etm_context_t *etm_ctx)
-{
- etb_t *etb = etm_ctx->capture_driver_priv;
- reg_t *etb_ctrl_reg = &etb->reg_cache->reg_list[ETB_CTRL];
-
- etb_write_reg(etb_ctrl_reg, 0x0);
- jtag_execute_queue();
-
- /* trace stopped, just clear running flag, but preserve others */
- etm_ctx->capture_status &= ~TRACE_RUNNING;
-
- return ERROR_OK;
-}
-
-etm_capture_driver_t etb_capture_driver =
-{
- .name = "etb",
- .register_commands = etb_register_commands,
- .init = etb_init,
- .status = etb_status,
- .start_capture = etb_start_capture,
- .stop_capture = etb_stop_capture,
- .read_trace = etb_read_trace,
-};
+/*************************************************************************** + * Copyright (C) 2007 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 <string.h> + +#include "arm7_9_common.h" +#include "etb.h" +#include "etm.h" + +#include "log.h" +#include "types.h" +#include "binarybuffer.h" +#include "target.h" +#include "register.h" +#include "jtag.h" + +#include <stdlib.h> + +char* etb_reg_list[] = +{ + "ETB_identification", + "ETB_ram_depth", + "ETB_ram_width", + "ETB_status", + "ETB_ram_data", + "ETB_ram_read_pointer", + "ETB_ram_write_pointer", + "ETB_trigger_counter", + "ETB_control", +}; + +int etb_reg_arch_type = -1; + +int etb_get_reg(reg_t *reg); +int etb_set_reg(reg_t *reg, u32 value); +int etb_set_reg_w_exec(reg_t *reg, u8 *buf); + +int etb_write_reg(reg_t *reg, u32 value); +int etb_read_reg(reg_t *reg); + +int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int etb_set_instr(etb_t *etb, u32 new_instr) +{ + jtag_device_t *device = jtag_get_device(etb->chain_pos); + + if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) + { + scan_field_t field; + + field.device = etb->chain_pos; + field.num_bits = device->ir_length; + field.out_value = calloc(CEIL(field.num_bits, 8), 1); + buf_set_u32(field.out_value, 0, field.num_bits, new_instr); + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_ir_scan(1, &field, -1); + + free(field.out_value); + } + + return ERROR_OK; +} + +int etb_scann(etb_t *etb, u32 new_scan_chain) +{ + if(etb->cur_scan_chain != new_scan_chain) + { + scan_field_t field; + + field.device = etb->chain_pos; + field.num_bits = 5; + field.out_value = calloc(CEIL(field.num_bits, 8), 1); + buf_set_u32(field.out_value, 0, field.num_bits, new_scan_chain); + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + /* select INTEST instruction */ + etb_set_instr(etb, 0x2); + jtag_add_dr_scan(1, &field, -1); + + etb->cur_scan_chain = new_scan_chain; + + free(field.out_value); + } + + return ERROR_OK; +} + +reg_cache_t* etb_build_reg_cache(etb_t *etb) +{ + reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t)); + reg_t *reg_list = NULL; + etb_reg_t *arch_info = NULL; + int num_regs = 9; + int i; + + /* register a register arch-type for etm registers only once */ + if (etb_reg_arch_type == -1) + etb_reg_arch_type = register_reg_arch_type(etb_get_reg, etb_set_reg_w_exec); + + /* the actual registers are kept in two arrays */ + reg_list = calloc(num_regs, sizeof(reg_t)); + arch_info = calloc(num_regs, sizeof(etb_reg_t)); + + /* fill in values for the reg cache */ + reg_cache->name = "etb registers"; + reg_cache->next = NULL; + reg_cache->reg_list = reg_list; + reg_cache->num_regs = num_regs; + + /* set up registers */ + for (i = 0; i < num_regs; i++) + { + reg_list[i].name = etb_reg_list[i]; + reg_list[i].size = 32; + reg_list[i].dirty = 0; + reg_list[i].valid = 0; + reg_list[i].bitfield_desc = NULL; + reg_list[i].num_bitfields = 0; + reg_list[i].value = calloc(1, 4); + reg_list[i].arch_info = &arch_info[i]; + reg_list[i].arch_type = etb_reg_arch_type; + reg_list[i].size = 32; + arch_info[i].addr = i; + arch_info[i].etb = etb; + } + + return reg_cache; +} + +int etb_get_reg(reg_t *reg) +{ + if (etb_read_reg(reg) != ERROR_OK) + { + ERROR("BUG: error scheduling etm register read"); + exit(-1); + } + + if (jtag_execute_queue() != ERROR_OK) + { + ERROR("register read failed"); + } + + return ERROR_OK; +} + +int etb_read_ram(etb_t *etb, u32 *data, int num_frames) +{ + scan_field_t fields[3]; + int i; + + jtag_add_end_state(TAP_RTI); + etb_scann(etb, 0x0); + etb_set_instr(etb, 0xc); + + fields[0].device = etb->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = etb->chain_pos; + fields[1].num_bits = 7; + fields[1].out_value = malloc(1); + buf_set_u32(fields[1].out_value, 0, 7, 4); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = etb->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = malloc(1); + buf_set_u32(fields[2].out_value, 0, 1, 0); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + fields[0].in_handler = buf_to_u32_handler; + + for (i = 0; i < num_frames; i++) + { + /* ensure nR/W reamins set to read */ + buf_set_u32(fields[2].out_value, 0, 1, 0); + + /* address remains set to 0x4 (RAM data) until we read the last frame */ + if (i < num_frames - 1) + buf_set_u32(fields[1].out_value, 0, 7, 4); + else + buf_set_u32(fields[1].out_value, 0, 7, 0); + + fields[0].in_handler_priv = &data[i]; + jtag_add_dr_scan(3, fields, -1); + } + + jtag_execute_queue(); + + free(fields[1].out_value); + free(fields[2].out_value); + + return ERROR_OK; +} + +int etb_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask) +{ + etb_reg_t *etb_reg = reg->arch_info; + u8 reg_addr = etb_reg->addr & 0x7f; + scan_field_t fields[3]; + + DEBUG("%i", etb_reg->addr); + + jtag_add_end_state(TAP_RTI); + etb_scann(etb_reg->etb, 0x0); + etb_set_instr(etb_reg->etb, 0xc); + + fields[0].device = etb_reg->etb->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = reg->value; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = etb_reg->etb->chain_pos; + fields[1].num_bits = 7; + fields[1].out_value = malloc(1); + buf_set_u32(fields[1].out_value, 0, 7, reg_addr); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = etb_reg->etb->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = malloc(1); + buf_set_u32(fields[2].out_value, 0, 1, 0); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + /* read the identification register in the second run, to make sure we + * don't read the ETB data register twice, skipping every second entry + */ + buf_set_u32(fields[1].out_value, 0, 7, 0x0); + fields[0].in_value = reg->value; + + jtag_set_check_value(fields+0, check_value, check_mask, NULL); + + jtag_add_dr_scan(3, fields, -1); + + free(fields[1].out_value); + free(fields[2].out_value); + + return ERROR_OK; +} + +int etb_read_reg(reg_t *reg) +{ + return etb_read_reg_w_check(reg, NULL, NULL); +} + +int etb_set_reg(reg_t *reg, u32 value) +{ + if (etb_write_reg(reg, value) != ERROR_OK) + { + ERROR("BUG: error scheduling etm register write"); + exit(-1); + } + + buf_set_u32(reg->value, 0, reg->size, value); + reg->valid = 1; + reg->dirty = 0; + + return ERROR_OK; +} + +int etb_set_reg_w_exec(reg_t *reg, u8 *buf) +{ + etb_set_reg(reg, buf_get_u32(buf, 0, reg->size)); + + if (jtag_execute_queue() != ERROR_OK) + { + ERROR("register write failed"); + exit(-1); + } + return ERROR_OK; +} + +int etb_write_reg(reg_t *reg, u32 value) +{ + etb_reg_t *etb_reg = reg->arch_info; + u8 reg_addr = etb_reg->addr & 0x7f; + scan_field_t fields[3]; + + DEBUG("%i: 0x%8.8x", etb_reg->addr, value); + + jtag_add_end_state(TAP_RTI); + etb_scann(etb_reg->etb, 0x0); + etb_set_instr(etb_reg->etb, 0xc); + + fields[0].device = etb_reg->etb->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = malloc(4); + buf_set_u32(fields[0].out_value, 0, 32, value); + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = etb_reg->etb->chain_pos; + fields[1].num_bits = 7; + fields[1].out_value = malloc(1); + buf_set_u32(fields[1].out_value, 0, 7, reg_addr); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = etb_reg->etb->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = malloc(1); + buf_set_u32(fields[2].out_value, 0, 1, 1); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + free(fields[0].out_value); + free(fields[1].out_value); + free(fields[2].out_value); + + return ERROR_OK; +} + +int etb_store_reg(reg_t *reg) +{ + return etb_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); +} + +int etb_register_commands(struct command_context_s *cmd_ctx) +{ + command_t *etb_cmd; + + etb_cmd = register_command(cmd_ctx, NULL, "etb", NULL, COMMAND_ANY, "Embedded Trace Buffer"); + + register_command(cmd_ctx, etb_cmd, "config", handle_etb_config_command, COMMAND_CONFIG, NULL); + + return ERROR_OK; +} + +int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + jtag_device_t *jtag_device; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + + if (argc != 2) + { + ERROR("incomplete 'etb config <target> <chain_pos>' command"); + exit(-1); + } + + target = get_target_by_num(strtoul(args[0], NULL, 0)); + + if (!target) + { + ERROR("target number '%s' not defined", args[0]); + exit(-1); + } + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + jtag_device = jtag_get_device(strtoul(args[1], NULL, 0)); + + if (!jtag_device) + { + ERROR("jtag device number '%s' not defined", args[1]); + exit(-1); + } + + if (arm7_9->etm_ctx) + { + etb_t *etb = malloc(sizeof(etb_t)); + + arm7_9->etm_ctx->capture_driver_priv = etb; + + etb->chain_pos = strtoul(args[1], NULL, 0); + etb->cur_scan_chain = -1; + etb->reg_cache = NULL; + etb->ram_width = 0; + etb->ram_depth = 0; + } + else + { + ERROR("target has no ETM defined, ETB left unconfigured"); + } + + return ERROR_OK; +} + +int etb_init(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + + etb->etm_ctx = etm_ctx; + + /* identify ETB RAM depth and width */ + etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_DEPTH]); + etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WIDTH]); + jtag_execute_queue(); + + etb->ram_depth = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_DEPTH].value, 0, 32); + etb->ram_width = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WIDTH].value, 0, 32); + + return ERROR_OK; +} + +trace_status_t etb_status(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + + etb->etm_ctx = etm_ctx; + + /* if tracing is currently idle, return this information */ + if (etm_ctx->capture_status == TRACE_IDLE) + { + return etm_ctx->capture_status; + } + else if (etm_ctx->capture_status & TRACE_RUNNING) + { + reg_t *etb_status_reg = &etb->reg_cache->reg_list[ETB_STATUS]; + int etb_timeout = 100; + + /* trace is running, check the ETB status flags */ + etb_get_reg(etb_status_reg); + + /* check Full bit to identify an overflow */ + if (buf_get_u32(etb_status_reg->value, 0, 1) == 1) + etm_ctx->capture_status |= TRACE_OVERFLOWED; + + /* check Triggered bit to identify trigger condition */ + if (buf_get_u32(etb_status_reg->value, 1, 1) == 1) + etm_ctx->capture_status |= TRACE_TRIGGERED; + + /* check AcqComp to identify trace completion */ + if (buf_get_u32(etb_status_reg->value, 2, 1) == 1) + { + while (etb_timeout-- && (buf_get_u32(etb_status_reg->value, 3, 1) == 0)) + { + /* wait for data formatter idle */ + etb_get_reg(etb_status_reg); + } + + if (etb_timeout == 0) + { + ERROR("AcqComp set but DFEmpty won't go high, ETB status: 0x%x", + buf_get_u32(etb_status_reg->value, 0, etb_status_reg->size)); + } + + if (!(etm_ctx->capture_status && TRACE_TRIGGERED)) + { + ERROR("trace completed, but no trigger condition detected"); + } + + etm_ctx->capture_status &= ~TRACE_RUNNING; + etm_ctx->capture_status |= TRACE_COMPLETED; + } + } + + return etm_ctx->capture_status; +} + +int etb_read_trace(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + int first_frame = 0; + int num_frames = etb->ram_depth; + u32 *trace_data = NULL; + int i, j; + + etb_read_reg(&etb->reg_cache->reg_list[ETB_STATUS]); + etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER]); + jtag_execute_queue(); + + /* check if we overflowed, and adjust first frame of the trace accordingly + * if we didn't overflow, read only up to the frame that would be written next, + * i.e. don't read invalid entries + */ + if (buf_get_u32(etb->reg_cache->reg_list[ETB_STATUS].value, 0, 1)) + { + first_frame = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32); + } + else + { + num_frames = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32); + } + + etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_READ_POINTER], first_frame); + + /* read data into temporary array for unpacking */ + trace_data = malloc(sizeof(u32) * num_frames); + etb_read_ram(etb, trace_data, num_frames); + + if (etm_ctx->trace_depth > 0) + { + free(etm_ctx->trace_data); + } + + if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) + etm_ctx->trace_depth = num_frames * 3; + else if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) + etm_ctx->trace_depth = num_frames * 2; + else + etm_ctx->trace_depth = num_frames; + + etm_ctx->trace_data = malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth); + + for (i = 0, j = 0; i < num_frames; i++) + { + if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) + { + /* trace word j */ + etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; + etm_ctx->trace_data[j].packet = (trace_data[i] & 0x78) >> 3; + etm_ctx->trace_data[j].flags = 0; + if ((trace_data[i] & 0x80) >> 7) + { + etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j].pipestat == STAT_TR) + { + etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; + etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; + } + + /* trace word j+1 */ + etm_ctx->trace_data[j+1].pipestat = (trace_data[i] & 0x100) >> 8; + etm_ctx->trace_data[j+1].packet = (trace_data[i] & 0x7800) >> 11; + etm_ctx->trace_data[j+1].flags = 0; + if ((trace_data[i] & 0x8000) >> 15) + { + etm_ctx->trace_data[j+1].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j+1].pipestat == STAT_TR) + { + etm_ctx->trace_data[j+1].pipestat = etm_ctx->trace_data[j+1].packet & 0x7; + etm_ctx->trace_data[j+1].flags |= ETMV1_TRIGGER_CYCLE; + } + + /* trace word j+2 */ + etm_ctx->trace_data[j+2].pipestat = (trace_data[i] & 0x10000) >> 16; + etm_ctx->trace_data[j+2].packet = (trace_data[i] & 0x780000) >> 19; + etm_ctx->trace_data[j+2].flags = 0; + if ((trace_data[i] & 0x800000) >> 23) + { + etm_ctx->trace_data[j+2].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j+2].pipestat == STAT_TR) + { + etm_ctx->trace_data[j+2].pipestat = etm_ctx->trace_data[j+2].packet & 0x7; + etm_ctx->trace_data[j+2].flags |= ETMV1_TRIGGER_CYCLE; + } + + j += 3; + } + else if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) + { + /* trace word j */ + etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; + etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7f8) >> 3; + etm_ctx->trace_data[j].flags = 0; + if ((trace_data[i] & 0x800) >> 11) + { + etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j].pipestat == STAT_TR) + { + etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; + etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; + } + + /* trace word j+1 */ + etm_ctx->trace_data[j+1].pipestat = (trace_data[i] & 0x7000) >> 12; + etm_ctx->trace_data[j+1].packet = (trace_data[i] & 0x7f8000) >> 15; + etm_ctx->trace_data[j+1].flags = 0; + if ((trace_data[i] & 0x800000) >> 23) + { + etm_ctx->trace_data[j+1].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j+1].pipestat == STAT_TR) + { + etm_ctx->trace_data[j+1].pipestat = etm_ctx->trace_data[j+1].packet & 0x7; + etm_ctx->trace_data[j+1].flags |= ETMV1_TRIGGER_CYCLE; + } + + j += 2; + } + else + { + /* trace word j */ + etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; + etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7fff8) >> 3; + etm_ctx->trace_data[j].flags = 0; + if ((trace_data[i] & 0x80000) >> 19) + { + etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j].pipestat == STAT_TR) + { + etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; + etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; + } + + j += 1; + } + } + + free(trace_data); + + return ERROR_OK; +} + +int etb_start_capture(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + u32 etb_ctrl_value = 0x1; + u32 trigger_count; + + if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED) + { + if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) != ETM_PORT_8BIT) + { + ERROR("ETB can't run in demultiplexed mode with a 4 or 16 bit port"); + return ERROR_ETM_PORTMODE_NOT_SUPPORTED; + } + etb_ctrl_value |= 0x2; + } + + if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_MUXED) + return ERROR_ETM_PORTMODE_NOT_SUPPORTED; + + trigger_count = (etb->ram_depth * etm_ctx->trigger_percent) / 100; + + etb_write_reg(&etb->reg_cache->reg_list[ETB_TRIGGER_COUNTER], trigger_count); + etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER], 0x0); + etb_write_reg(&etb->reg_cache->reg_list[ETB_CTRL], etb_ctrl_value); + jtag_execute_queue(); + + /* we're starting a new trace, initialize capture status */ + etm_ctx->capture_status = TRACE_RUNNING; + + return ERROR_OK; +} + +int etb_stop_capture(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + reg_t *etb_ctrl_reg = &etb->reg_cache->reg_list[ETB_CTRL]; + + etb_write_reg(etb_ctrl_reg, 0x0); + jtag_execute_queue(); + + /* trace stopped, just clear running flag, but preserve others */ + etm_ctx->capture_status &= ~TRACE_RUNNING; + + return ERROR_OK; +} + +etm_capture_driver_t etb_capture_driver = +{ + .name = "etb", + .register_commands = etb_register_commands, + .init = etb_init, + .status = etb_status, + .start_capture = etb_start_capture, + .stop_capture = etb_stop_capture, + .read_trace = etb_read_trace, +}; diff --git a/src/target/etb.h b/src/target/etb.h index 1a579cb..e3dcb1d 100644 --- a/src/target/etb.h +++ b/src/target/etb.h @@ -1,75 +1,75 @@ -/***************************************************************************
- * Copyright (C) 2007 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 ETB_H
-#define ETB_H
-
-#include "command.h"
-#include "target.h"
-#include "register.h"
-#include "arm_jtag.h"
-
-#include "etb.h"
-#include "etm.h"
-
-/* ETB registers */
-enum
-{
- ETB_ID = 0x00,
- ETB_RAM_DEPTH = 0x01,
- ETB_RAM_WIDTH = 0x02,
- ETB_STATUS = 0x03,
- ETB_RAM_DATA = 0x04,
- ETB_RAM_READ_POINTER = 0x05,
- ETB_RAM_WRITE_POINTER = 0x06,
- ETB_TRIGGER_COUNTER = 0x07,
- ETB_CTRL = 0x08,
-};
-
-typedef struct etb_s
-{
- etm_context_t *etm_ctx;
- int chain_pos;
- int cur_scan_chain;
- reg_cache_t *reg_cache;
-
- /* ETB parameters */
- int ram_depth;
- int ram_width;
-} etb_t;
-
-typedef struct etb_reg_s
-{
- int addr;
- etb_t *etb;
-} etb_reg_t;
-
-extern etm_capture_driver_t etb_capture_driver;
-
-extern reg_cache_t* etb_build_reg_cache(etb_t *etb);
-extern int etb_read_reg(reg_t *reg);
-extern int etb_write_reg(reg_t *reg, u32 value);
-extern int etb_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask);
-extern int etb_store_reg(reg_t *reg);
-extern int etb_set_reg(reg_t *reg, u32 value);
-extern int etb_set_reg_w_exec(reg_t *reg, u8 *buf);
-
-extern int etb_register_commands(struct command_context_s *cmd_ctx);
-
-#endif /* ETB_H */
+/*************************************************************************** + * Copyright (C) 2007 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 ETB_H +#define ETB_H + +#include "command.h" +#include "target.h" +#include "register.h" +#include "arm_jtag.h" + +#include "etb.h" +#include "etm.h" + +/* ETB registers */ +enum +{ + ETB_ID = 0x00, + ETB_RAM_DEPTH = 0x01, + ETB_RAM_WIDTH = 0x02, + ETB_STATUS = 0x03, + ETB_RAM_DATA = 0x04, + ETB_RAM_READ_POINTER = 0x05, + ETB_RAM_WRITE_POINTER = 0x06, + ETB_TRIGGER_COUNTER = 0x07, + ETB_CTRL = 0x08, +}; + +typedef struct etb_s +{ + etm_context_t *etm_ctx; + int chain_pos; + int cur_scan_chain; + reg_cache_t *reg_cache; + + /* ETB parameters */ + int ram_depth; + int ram_width; +} etb_t; + +typedef struct etb_reg_s +{ + int addr; + etb_t *etb; +} etb_reg_t; + +extern etm_capture_driver_t etb_capture_driver; + +extern reg_cache_t* etb_build_reg_cache(etb_t *etb); +extern int etb_read_reg(reg_t *reg); +extern int etb_write_reg(reg_t *reg, u32 value); +extern int etb_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask); +extern int etb_store_reg(reg_t *reg); +extern int etb_set_reg(reg_t *reg, u32 value); +extern int etb_set_reg_w_exec(reg_t *reg, u8 *buf); + +extern int etb_register_commands(struct command_context_s *cmd_ctx); + +#endif /* ETB_H */ diff --git a/src/target/etm.c b/src/target/etm.c index fe4ac77..8475a99 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -1,1863 +1,1863 @@ -/***************************************************************************
- * 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 <string.h>
-
-#include "etm.h"
-#include "etb.h"
-
-#include "armv4_5.h"
-#include "arm7_9_common.h"
-#include "arm_disassembler.h"
-#include "arm_simulator.h"
-
-#include "log.h"
-#include "arm_jtag.h"
-#include "types.h"
-#include "binarybuffer.h"
-#include "target.h"
-#include "register.h"
-#include "jtag.h"
-#include "fileio.h"
-
-#include <stdlib.h>
-
-/* ETM register access functionality
- *
- */
-
-bitfield_desc_t etm_comms_ctrl_bitfield_desc[] =
-{
- {"R", 1},
- {"W", 1},
- {"reserved", 26},
- {"version", 4}
-};
-
-int etm_reg_arch_info[] =
-{
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
- 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
- 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x67,
- 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
-};
-
-int etm_reg_arch_size_info[] =
-{
- 32, 32, 17, 8, 3, 9, 32, 16,
- 17, 26, 25, 8, 17, 32, 32, 17,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 16, 16, 16, 16, 18, 18, 18, 18,
- 17, 17, 17, 17, 16, 16, 16, 16,
- 17, 17, 17, 17, 17, 17, 2,
- 17, 17, 17, 17, 32, 32, 32, 32
-};
-
-char* etm_reg_list[] =
-{
- "ETM_CTRL",
- "ETM_CONFIG",
- "ETM_TRIG_EVENT",
- "ETM_MMD_CTRL",
- "ETM_STATUS",
- "ETM_SYS_CONFIG",
- "ETM_TRACE_RESOURCE_CTRL",
- "ETM_TRACE_EN_CTRL2",
- "ETM_TRACE_EN_EVENT",
- "ETM_TRACE_EN_CTRL1",
- "ETM_FIFOFULL_REGION",
- "ETM_FIFOFULL_LEVEL",
- "ETM_VIEWDATA_EVENT",
- "ETM_VIEWDATA_CTRL1",
- "ETM_VIEWDATA_CTRL2",
- "ETM_VIEWDATA_CTRL3",
- "ETM_ADDR_COMPARATOR_VALUE1",
- "ETM_ADDR_COMPARATOR_VALUE2",
- "ETM_ADDR_COMPARATOR_VALUE3",
- "ETM_ADDR_COMPARATOR_VALUE4",
- "ETM_ADDR_COMPARATOR_VALUE5",
- "ETM_ADDR_COMPARATOR_VALUE6",
- "ETM_ADDR_COMPARATOR_VALUE7",
- "ETM_ADDR_COMPARATOR_VALUE8",
- "ETM_ADDR_COMPARATOR_VALUE9",
- "ETM_ADDR_COMPARATOR_VALUE10",
- "ETM_ADDR_COMPARATOR_VALUE11",
- "ETM_ADDR_COMPARATOR_VALUE12",
- "ETM_ADDR_COMPARATOR_VALUE13",
- "ETM_ADDR_COMPARATOR_VALUE14",
- "ETM_ADDR_COMPARATOR_VALUE15",
- "ETM_ADDR_COMPARATOR_VALUE16",
- "ETM_ADDR_ACCESS_TYPE1",
- "ETM_ADDR_ACCESS_TYPE2",
- "ETM_ADDR_ACCESS_TYPE3",
- "ETM_ADDR_ACCESS_TYPE4",
- "ETM_ADDR_ACCESS_TYPE5",
- "ETM_ADDR_ACCESS_TYPE6",
- "ETM_ADDR_ACCESS_TYPE7",
- "ETM_ADDR_ACCESS_TYPE8",
- "ETM_ADDR_ACCESS_TYPE9",
- "ETM_ADDR_ACCESS_TYPE10",
- "ETM_ADDR_ACCESS_TYPE11",
- "ETM_ADDR_ACCESS_TYPE12",
- "ETM_ADDR_ACCESS_TYPE13",
- "ETM_ADDR_ACCESS_TYPE14",
- "ETM_ADDR_ACCESS_TYPE15",
- "ETM_ADDR_ACCESS_TYPE16",
- "ETM_DATA_COMPARATOR_VALUE1",
- "ETM_DATA_COMPARATOR_VALUE2",
- "ETM_DATA_COMPARATOR_VALUE3",
- "ETM_DATA_COMPARATOR_VALUE4",
- "ETM_DATA_COMPARATOR_VALUE5",
- "ETM_DATA_COMPARATOR_VALUE6",
- "ETM_DATA_COMPARATOR_VALUE7",
- "ETM_DATA_COMPARATOR_VALUE8",
- "ETM_DATA_COMPARATOR_VALUE9",
- "ETM_DATA_COMPARATOR_VALUE10",
- "ETM_DATA_COMPARATOR_VALUE11",
- "ETM_DATA_COMPARATOR_VALUE12",
- "ETM_DATA_COMPARATOR_VALUE13",
- "ETM_DATA_COMPARATOR_VALUE14",
- "ETM_DATA_COMPARATOR_VALUE15",
- "ETM_DATA_COMPARATOR_VALUE16",
- "ETM_DATA_COMPARATOR_MASK1",
- "ETM_DATA_COMPARATOR_MASK2",
- "ETM_DATA_COMPARATOR_MASK3",
- "ETM_DATA_COMPARATOR_MASK4",
- "ETM_DATA_COMPARATOR_MASK5",
- "ETM_DATA_COMPARATOR_MASK6",
- "ETM_DATA_COMPARATOR_MASK7",
- "ETM_DATA_COMPARATOR_MASK8",
- "ETM_DATA_COMPARATOR_MASK9",
- "ETM_DATA_COMPARATOR_MASK10",
- "ETM_DATA_COMPARATOR_MASK11",
- "ETM_DATA_COMPARATOR_MASK12",
- "ETM_DATA_COMPARATOR_MASK13",
- "ETM_DATA_COMPARATOR_MASK14",
- "ETM_DATA_COMPARATOR_MASK15",
- "ETM_DATA_COMPARATOR_MASK16",
- "ETM_COUNTER_INITAL_VALUE1",
- "ETM_COUNTER_INITAL_VALUE2",
- "ETM_COUNTER_INITAL_VALUE3",
- "ETM_COUNTER_INITAL_VALUE4",
- "ETM_COUNTER_ENABLE1",
- "ETM_COUNTER_ENABLE2",
- "ETM_COUNTER_ENABLE3",
- "ETM_COUNTER_ENABLE4",
- "ETM_COUNTER_RELOAD_VALUE1",
- "ETM_COUNTER_RELOAD_VALUE2",
- "ETM_COUNTER_RELOAD_VALUE3",
- "ETM_COUNTER_RELOAD_VALUE4",
- "ETM_COUNTER_VALUE1",
- "ETM_COUNTER_VALUE2",
- "ETM_COUNTER_VALUE3",
- "ETM_COUNTER_VALUE4",
- "ETM_SEQUENCER_CTRL1",
- "ETM_SEQUENCER_CTRL2",
- "ETM_SEQUENCER_CTRL3",
- "ETM_SEQUENCER_CTRL4",
- "ETM_SEQUENCER_CTRL5",
- "ETM_SEQUENCER_CTRL6",
- "ETM_SEQUENCER_STATE",
- "ETM_EXTERNAL_OUTPUT1",
- "ETM_EXTERNAL_OUTPUT2",
- "ETM_EXTERNAL_OUTPUT3",
- "ETM_EXTERNAL_OUTPUT4",
- "ETM_CONTEXTID_COMPARATOR_VALUE1",
- "ETM_CONTEXTID_COMPARATOR_VALUE2",
- "ETM_CONTEXTID_COMPARATOR_VALUE3",
- "ETM_CONTEXTID_COMPARATOR_MASK"
-};
-
-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);
-
-command_t *etm_cmd = NULL;
-
-reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_context_t *etm_ctx)
-{
- reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t));
- reg_t *reg_list = NULL;
- etm_reg_t *arch_info = NULL;
- int num_regs = sizeof(etm_reg_arch_info)/sizeof(int);
- int i;
- u32 etm_ctrl_value;
-
- /* register a register arch-type for etm registers only once */
- if (etm_reg_arch_type == -1)
- etm_reg_arch_type = register_reg_arch_type(etm_get_reg, etm_set_reg_w_exec);
-
- /* the actual registers are kept in two arrays */
- reg_list = calloc(num_regs, sizeof(reg_t));
- arch_info = calloc(num_regs, sizeof(etm_reg_t));
-
- /* fill in values for the reg cache */
- reg_cache->name = "etm registers";
- reg_cache->next = NULL;
- reg_cache->reg_list = reg_list;
- reg_cache->num_regs = num_regs;
-
- /* set up registers */
- for (i = 0; i < num_regs; i++)
- {
- reg_list[i].name = etm_reg_list[i];
- reg_list[i].size = 32;
- reg_list[i].dirty = 0;
- reg_list[i].valid = 0;
- reg_list[i].bitfield_desc = NULL;
- reg_list[i].num_bitfields = 0;
- reg_list[i].value = calloc(1, 4);
- reg_list[i].arch_info = &arch_info[i];
- reg_list[i].arch_type = etm_reg_arch_type;
- reg_list[i].size = etm_reg_arch_size_info[i];
- arch_info[i].addr = etm_reg_arch_info[i];
- arch_info[i].jtag_info = jtag_info;
- }
-
- /* initialize some ETM control register settings */
- etm_get_reg(®_list[ETM_CTRL]);
- etm_ctrl_value = buf_get_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size);
-
- /* clear the ETM powerdown bit (0) */
- etm_ctrl_value &= ~0x1;
-
- /* configure port width (6:4), mode (17:16) and clocking (13) */
- etm_ctrl_value = (etm_ctrl_value &
- ~ETM_PORT_WIDTH_MASK & ~ETM_PORT_MODE_MASK & ~ETM_PORT_CLOCK_MASK)
- | etm_ctx->portmode;
-
- buf_set_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size, etm_ctrl_value);
- etm_store_reg(®_list[ETM_CTRL]);
-
- /* the ETM might have an ETB connected */
- if (strcmp(etm_ctx->capture_driver->name, "etb") == 0)
- {
- etb_t *etb = etm_ctx->capture_driver_priv;
-
- if (!etb)
- {
- ERROR("etb selected as etm capture driver, but no ETB configured");
- return ERROR_OK;
- }
-
- reg_cache->next = etb_build_reg_cache(etb);
-
- etb->reg_cache = reg_cache->next;
- }
-
- if (etm_ctx->capture_driver->init(etm_ctx) != ERROR_OK)
- {
- ERROR("ETM capture driver initialization failed");
- exit(-1);
- }
-
- return reg_cache;
-}
-
-int etm_get_reg(reg_t *reg)
-{
- if (etm_read_reg(reg) != ERROR_OK)
- {
- ERROR("BUG: error scheduling etm register read");
- exit(-1);
- }
-
- if (jtag_execute_queue() != ERROR_OK)
- {
- ERROR("register read failed");
- }
-
- return ERROR_OK;
-}
-
-int etm_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask)
-{
- etm_reg_t *etm_reg = reg->arch_info;
- u8 reg_addr = etm_reg->addr & 0x7f;
- scan_field_t fields[3];
-
- DEBUG("%i", etm_reg->addr);
-
- jtag_add_end_state(TAP_RTI);
- arm_jtag_scann(etm_reg->jtag_info, 0x6);
- arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr, NULL);
-
- fields[0].device = etm_reg->jtag_info->chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = reg->value;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = etm_reg->jtag_info->chain_pos;
- fields[1].num_bits = 7;
- fields[1].out_value = malloc(1);
- buf_set_u32(fields[1].out_value, 0, 7, reg_addr);
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = etm_reg->jtag_info->chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = malloc(1);
- buf_set_u32(fields[2].out_value, 0, 1, 0);
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- jtag_add_dr_scan(3, fields, -1);
-
- fields[0].in_value = reg->value;
- jtag_set_check_value(fields+0, check_value, check_mask, NULL);
-
- jtag_add_dr_scan(3, fields, -1);
-
- free(fields[1].out_value);
- free(fields[2].out_value);
-
- return ERROR_OK;
-}
-
-int etm_read_reg(reg_t *reg)
-{
- return etm_read_reg_w_check(reg, NULL, NULL);
-}
-
-int etm_set_reg(reg_t *reg, u32 value)
-{
- if (etm_write_reg(reg, value) != ERROR_OK)
- {
- ERROR("BUG: error scheduling etm register write");
- exit(-1);
- }
-
- buf_set_u32(reg->value, 0, reg->size, value);
- reg->valid = 1;
- reg->dirty = 0;
-
- return ERROR_OK;
-}
-
-int etm_set_reg_w_exec(reg_t *reg, u8 *buf)
-{
- etm_set_reg(reg, buf_get_u32(buf, 0, reg->size));
-
- if (jtag_execute_queue() != ERROR_OK)
- {
- ERROR("register write failed");
- exit(-1);
- }
- return ERROR_OK;
-}
-
-int etm_write_reg(reg_t *reg, u32 value)
-{
- etm_reg_t *etm_reg = reg->arch_info;
- u8 reg_addr = etm_reg->addr & 0x7f;
- scan_field_t fields[3];
-
- DEBUG("%i: 0x%8.8x", etm_reg->addr, value);
-
- jtag_add_end_state(TAP_RTI);
- arm_jtag_scann(etm_reg->jtag_info, 0x6);
- arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr, NULL);
-
- fields[0].device = etm_reg->jtag_info->chain_pos;
- fields[0].num_bits = 32;
- fields[0].out_value = malloc(4);
- buf_set_u32(fields[0].out_value, 0, 32, value);
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = etm_reg->jtag_info->chain_pos;
- fields[1].num_bits = 7;
- fields[1].out_value = malloc(1);
- buf_set_u32(fields[1].out_value, 0, 7, reg_addr);
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- fields[2].device = etm_reg->jtag_info->chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = malloc(1);
- buf_set_u32(fields[2].out_value, 0, 1, 1);
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_check_value = NULL;
- fields[2].in_check_mask = NULL;
- fields[2].in_handler = NULL;
- fields[2].in_handler_priv = NULL;
-
- jtag_add_dr_scan(3, fields, -1);
-
- free(fields[0].out_value);
- free(fields[1].out_value);
- free(fields[2].out_value);
-
- return ERROR_OK;
-}
-
-int etm_store_reg(reg_t *reg)
-{
- return etm_write_reg(reg, buf_get_u32(reg->value, 0, reg->size));
-}
-
-/* ETM trace analysis functionality
- *
- */
-extern etm_capture_driver_t etb_capture_driver;
-extern etm_capture_driver_t etm_dummy_capture_driver;
-#if BUILD_OOCD_TRACE == 1
-extern etm_capture_driver_t oocd_trace_capture_driver;
-#endif
-
-etm_capture_driver_t *etm_capture_drivers[] =
-{
- &etb_capture_driver,
- &etm_dummy_capture_driver,
-#if BUILD_OOCD_TRACE == 1
- &oocd_trace_capture_driver,
-#endif
- NULL
-};
-
-char *etmv1v1_branch_reason_strings[] =
-{
- "normal PC change",
- "tracing enabled",
- "trace restarted after overflow",
- "exit from debug",
- "periodic synchronization",
- "reserved",
- "reserved",
- "reserved",
-};
-
-int etm_read_instruction(etm_context_t *ctx, arm_instruction_t *instruction)
-{
- int i;
- int section = -1;
- u32 size_read;
- u32 opcode;
- int retval;
-
- if (!ctx->image)
- return ERROR_TRACE_IMAGE_UNAVAILABLE;
-
- /* search for the section the current instruction belongs to */
- for (i = 0; i < ctx->image->num_sections; i++)
- {
- if ((ctx->image->sections[i].base_address <= ctx->current_pc) &&
- (ctx->image->sections[i].base_address + ctx->image->sections[i].size > ctx->current_pc))
- {
- section = i;
- break;
- }
- }
-
- if (section == -1)
- {
- /* current instruction couldn't be found in the image */
- return ERROR_TRACE_INSTRUCTION_UNAVAILABLE;
- }
-
- if (ctx->core_state == ARMV4_5_STATE_ARM)
- {
- u8 buf[4];
- if ((retval = image_read_section(ctx->image, section,
- ctx->current_pc - ctx->image->sections[section].base_address,
- 4, buf, &size_read)) != ERROR_OK)
- {
- ERROR("error while reading instruction: %i", retval);
- return ERROR_TRACE_INSTRUCTION_UNAVAILABLE;
- }
- opcode = target_buffer_get_u32(ctx->target, buf);
- arm_evaluate_opcode(opcode, ctx->current_pc, instruction);
- }
- else if (ctx->core_state == ARMV4_5_STATE_THUMB)
- {
- u8 buf[2];
- if ((retval = image_read_section(ctx->image, section,
- ctx->current_pc - ctx->image->sections[section].base_address,
- 2, buf, &size_read)) != ERROR_OK)
- {
- ERROR("error while reading instruction: %i", retval);
- return ERROR_TRACE_INSTRUCTION_UNAVAILABLE;
- }
- opcode = target_buffer_get_u16(ctx->target, buf);
- thumb_evaluate_opcode(opcode, ctx->current_pc, instruction);
- }
- else if (ctx->core_state == ARMV4_5_STATE_JAZELLE)
- {
- ERROR("BUG: tracing of jazelle code not supported");
- exit(-1);
- }
- else
- {
- ERROR("BUG: unknown core state encountered");
- exit(-1);
- }
-
- return ERROR_OK;
-}
-
-int etmv1_next_packet(etm_context_t *ctx, u8 *packet, int apo)
-{
- while (ctx->data_index < ctx->trace_depth)
- {
- /* if the caller specified an address packet offset, skip until the
- * we reach the n-th cycle marked with tracesync */
- if (apo > 0)
- {
- if (ctx->trace_data[ctx->data_index].flags & ETMV1_TRACESYNC_CYCLE)
- apo--;
-
- if (apo > 0)
- {
- ctx->data_index++;
- ctx->data_half = 0;
- }
- continue;
- }
-
- /* no tracedata output during a TD cycle
- * or in a trigger cycle */
- if ((ctx->trace_data[ctx->data_index].pipestat == STAT_TD)
- || (ctx->trace_data[ctx->data_index].flags & ETMV1_TRIGGER_CYCLE))
- {
- ctx->data_index++;
- ctx->data_half = 0;
- continue;
- }
-
- if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_16BIT)
- {
- if (ctx->data_half == 0)
- {
- *packet = ctx->trace_data[ctx->data_index].packet & 0xff;
- ctx->data_half = 1;
- }
- else
- {
- *packet = (ctx->trace_data[ctx->data_index].packet & 0xff00) >> 8;
- ctx->data_half = 0;
- ctx->data_index++;
- }
- }
- else if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT)
- {
- *packet = ctx->trace_data[ctx->data_index].packet & 0xff;
- ctx->data_index++;
- }
- else
- {
- /* on a 4-bit port, a packet will be output during two consecutive cycles */
- if (ctx->data_index > (ctx->trace_depth - 2))
- return -1;
-
- *packet = ctx->trace_data[ctx->data_index].packet & 0xf;
- *packet |= (ctx->trace_data[ctx->data_index + 1].packet & 0xf) << 4;
- ctx->data_index += 2;
- }
-
- return 0;
- }
-
- return -1;
-}
-
-int etmv1_branch_address(etm_context_t *ctx)
-{
- int retval;
- u8 packet;
- int shift = 0;
- int apo;
- int i;
-
- /* quit analysis if less than two cycles are left in the trace
- * because we can't extract the APO */
- if (ctx->data_index > (ctx->trace_depth - 2))
- return -1;
-
- /* a BE could be output during an APO cycle, skip the current
- * and continue with the new one */
- if (ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x4)
- return 1;
- if (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x4)
- return 2;
-
- /* address packet offset encoded in the next two cycles' pipestat bits */
- apo = ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x3;
- apo |= (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x3) << 2;
-
- /* count number of tracesync cycles between current pipe_index and data_index
- * i.e. the number of tracesyncs that data_index already passed by
- * to subtract them from the APO */
- for (i = ctx->pipe_index; i < ctx->data_index; i++)
- {
- if (ctx->trace_data[ctx->pipe_index + 1].pipestat & ETMV1_TRACESYNC_CYCLE)
- apo--;
- }
-
- /* extract up to four 7-bit packets */
- do {
- if ((retval = etmv1_next_packet(ctx, &packet, (shift == 0) ? apo + 1 : 0)) != 0)
- return -1;
- ctx->last_branch &= ~(0x7f << shift);
- ctx->last_branch |= (packet & 0x7f) << shift;
- shift += 7;
- } while ((packet & 0x80) && (shift < 28));
-
- /* one last packet holding 4 bits of the address, plus the branch reason code */
- if ((shift == 28) && (packet & 0x80))
- {
- if ((retval = etmv1_next_packet(ctx, &packet, 0)) != 0)
- return -1;
- ctx->last_branch &= 0x0fffffff;
- ctx->last_branch |= (packet & 0x0f) << 28;
- ctx->last_branch_reason = (packet & 0x70) >> 4;
- shift += 4;
- }
- else
- {
- ctx->last_branch_reason = 0;
- }
-
- if (shift == 32)
- {
- ctx->pc_ok = 1;
- }
-
- /* if a full address was output, we might have branched into Jazelle state */
- if ((shift == 32) && (packet & 0x80))
- {
- ctx->core_state = ARMV4_5_STATE_JAZELLE;
- }
- else
- {
- /* if we didn't branch into Jazelle state, the current processor state is
- * encoded in bit 0 of the branch target address */
- if (ctx->last_branch & 0x1)
- {
- ctx->core_state = ARMV4_5_STATE_THUMB;
- ctx->last_branch &= ~0x1;
- }
- else
- {
- ctx->core_state = ARMV4_5_STATE_ARM;
- ctx->last_branch &= ~0x3;
- }
- }
-
- return 0;
-}
-
-int etmv1_data(etm_context_t *ctx, int size, u32 *data)
-{
- int j;
- u8 buf[4];
- int retval;
-
- for (j = 0; j < size; j++)
- {
- if ((retval = etmv1_next_packet(ctx, &buf[j], 0)) != 0)
- return -1;
- }
-
- if (size == 8)
- ERROR("TODO: add support for 64-bit values");
- else if (size == 4)
- *data = target_buffer_get_u32(ctx->target, buf);
- else if (size == 2)
- *data = target_buffer_get_u16(ctx->target, buf);
- else if (size == 1)
- *data = buf[0];
-
- return 0;
-}
-
-int etmv1_analyze_trace(etm_context_t *ctx, struct command_context_s *cmd_ctx)
-{
- int retval;
- arm_instruction_t instruction;
-
- /* read the trace data if it wasn't read already */
- if (ctx->trace_depth == 0)
- ctx->capture_driver->read_trace(ctx);
-
- /* start at the beginning of the captured trace */
- ctx->pipe_index = 0;
- ctx->data_index = 0;
- ctx->data_half = 0;
-
- /* neither the PC nor the data pointer are valid */
- ctx->pc_ok = 0;
- ctx->ptr_ok = 0;
-
- while (ctx->pipe_index < ctx->trace_depth)
- {
- u8 pipestat = ctx->trace_data[ctx->pipe_index].pipestat;
- u32 next_pc = ctx->current_pc;
- u32 old_data_index = ctx->data_index;
- u32 old_data_half = ctx->data_half;
- u32 old_index = ctx->pipe_index;
- u32 last_instruction = ctx->last_instruction;
- u32 cycles = 0;
- int current_pc_ok = ctx->pc_ok;
-
- if (ctx->trace_data[ctx->pipe_index].flags & ETMV1_TRIGGER_CYCLE)
- {
- command_print(cmd_ctx, "--- trigger ---");
- }
-
- /* instructions execute in IE/D or BE/D cycles */
- if ((pipestat == STAT_IE) || (pipestat == STAT_ID))
- ctx->last_instruction = ctx->pipe_index;
-
- /* if we don't have a valid pc skip until we reach an indirect branch */
- if ((!ctx->pc_ok) && (pipestat != STAT_BE))
- {
- ctx->pipe_index++;
- continue;
- }
-
- /* any indirect branch could have interrupted instruction flow
- * - the branch reason code could indicate a trace discontinuity
- * - a branch to the exception vectors indicates an exception
- */
- if ((pipestat == STAT_BE) || (pipestat == STAT_BD))
- {
- /* backup current data index, to be able to consume the branch address
- * before examining data address and values
- */
- old_data_index = ctx->data_index;
- old_data_half = ctx->data_half;
-
- ctx->last_instruction = ctx->pipe_index;
-
- if ((retval = etmv1_branch_address(ctx)) != 0)
- {
- /* negative return value from etmv1_branch_address means we ran out of packets,
- * quit analysing the trace */
- if (retval < 0)
- break;
-
- /* a positive return values means the current branch was abandoned,
- * and a new branch was encountered in cycle ctx->pipe_index + retval;
- */
- WARNING("abandoned branch encountered, correctnes of analysis uncertain");
- ctx->pipe_index += retval;
- continue;
- }
-
- /* skip over APO cycles */
- ctx->pipe_index += 2;
-
- switch (ctx->last_branch_reason)
- {
- case 0x0: /* normal PC change */
- next_pc = ctx->last_branch;
- break;
- case 0x1: /* tracing enabled */
- command_print(cmd_ctx, "--- tracing enabled at 0x%8.8x ---", ctx->last_branch);
- ctx->current_pc = ctx->last_branch;
- ctx->pipe_index++;
- continue;
- break;
- case 0x2: /* trace restarted after FIFO overflow */
- command_print(cmd_ctx, "--- trace restarted after FIFO overflow at 0x%8.8x ---", ctx->last_branch);
- ctx->current_pc = ctx->last_branch;
- ctx->pipe_index++;
- continue;
- break;
- case 0x3: /* exit from debug state */
- command_print(cmd_ctx, "--- exit from debug state at 0x%8.8x ---", ctx->last_branch);
- ctx->current_pc = ctx->last_branch;
- ctx->pipe_index++;
- continue;
- break;
- case 0x4: /* periodic synchronization point */
- next_pc = ctx->last_branch;
- /* if we had no valid PC prior to this synchronization point,
- * we have to move on with the next trace cycle
- */
- if (!current_pc_ok)
- {
- command_print(cmd_ctx, "--- periodic synchronization point at 0x%8.8x ---", next_pc);
- ctx->current_pc = next_pc;
- ctx->pipe_index++;
- continue;
- }
- break;
- default: /* reserved */
- ERROR("BUG: branch reason code 0x%x is reserved", ctx->last_branch_reason);
- exit(-1);
- break;
- }
-
- /* if we got here the branch was a normal PC change
- * (or a periodic synchronization point, which means the same for that matter)
- * if we didn't accquire a complete PC continue with the next cycle
- */
- if (!ctx->pc_ok)
- continue;
-
- /* indirect branch to the exception vector means an exception occured */
- if (((ctx->last_branch >= 0x0) && (ctx->last_branch <= 0x20))
- || ((ctx->last_branch >= 0xffff0000) && (ctx->last_branch <= 0xffff0020)))
- {
- if ((ctx->last_branch & 0xff) == 0x10)
- {
- command_print(cmd_ctx, "data abort");
- }
- else
- {
- command_print(cmd_ctx, "exception vector 0x%2.2x", ctx->last_branch);
- ctx->current_pc = ctx->last_branch;
- ctx->pipe_index++;
- continue;
- }
- }
- }
-
- /* an instruction was executed (or not, depending on the condition flags)
- * retrieve it from the image for displaying */
- if (ctx->pc_ok && (pipestat != STAT_WT) && (pipestat != STAT_TD) &&
- !(((pipestat == STAT_BE) || (pipestat == STAT_BD)) &&
- ((ctx->last_branch_reason != 0x0) && (ctx->last_branch_reason != 0x4))))
- {
- if ((retval = etm_read_instruction(ctx, &instruction)) != ERROR_OK)
- {
- /* can't continue tracing with no image available */
- if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE)
- {
- return retval;
- }
- else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE)
- {
- /* TODO: handle incomplete images
- * for now we just quit the analsysis*/
- return retval;
- }
- }
-
- cycles = old_index - last_instruction;
- }
-
- if ((pipestat == STAT_ID) || (pipestat == STAT_BD))
- {
- u32 new_data_index = ctx->data_index;
- u32 new_data_half = ctx->data_half;
-
- /* in case of a branch with data, the branch target address was consumed before
- * we temporarily go back to the saved data index */
- if (pipestat == STAT_BD)
- {
- ctx->data_index = old_data_index;
- ctx->data_half = old_data_half;
- }
-
- if (ctx->tracemode & ETMV1_TRACE_ADDR)
- {
- u8 packet;
- int shift = 0;
-
- do {
- if ((retval = etmv1_next_packet(ctx, &packet, 0)) != 0)
- return ERROR_ETM_ANALYSIS_FAILED;
- ctx->last_ptr &= ~(0x7f << shift);
- ctx->last_ptr |= (packet & 0x7f) << shift;
- shift += 7;
- } while ((packet & 0x80) && (shift < 32));
-
- if (shift >= 32)
- ctx->ptr_ok = 1;
-
- if (ctx->ptr_ok)
- {
- command_print(cmd_ctx, "address: 0x%8.8x", ctx->last_ptr);
- }
- }
-
- if (ctx->tracemode & ETMV1_TRACE_DATA)
- {
- if ((instruction.type == ARM_LDM) || (instruction.type == ARM_STM))
- {
- int i;
- for (i = 0; i < 16; i++)
- {
- if (instruction.info.load_store_multiple.register_list & (1 << i))
- {
- u32 data;
- if (etmv1_data(ctx, 4, &data) != 0)
- return ERROR_ETM_ANALYSIS_FAILED;
- command_print(cmd_ctx, "data: 0x%8.8x", data);
- }
- }
- }
- else if ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_STRH))
- {
- u32 data;
- if (etmv1_data(ctx, arm_access_size(&instruction), &data) != 0)
- return ERROR_ETM_ANALYSIS_FAILED;
- command_print(cmd_ctx, "data: 0x%8.8x", data);
- }
- }
-
- /* restore data index after consuming BD address and data */
- if (pipestat == STAT_BD)
- {
- ctx->data_index = new_data_index;
- ctx->data_half = new_data_half;
- }
- }
-
- /* adjust PC */
- if ((pipestat == STAT_IE) || (pipestat == STAT_ID))
- {
- if (((instruction.type == ARM_B) ||
- (instruction.type == ARM_BL) ||
- (instruction.type == ARM_BLX)) &&
- (instruction.info.b_bl_bx_blx.target_address != -1))
- {
- next_pc = instruction.info.b_bl_bx_blx.target_address;
- }
- else
- {
- next_pc += (ctx->core_state == ARMV4_5_STATE_ARM) ? 4 : 2;
- }
- }
- else if (pipestat == STAT_IN)
- {
- next_pc += (ctx->core_state == ARMV4_5_STATE_ARM) ? 4 : 2;
- }
-
- if ((pipestat != STAT_TD) && (pipestat != STAT_WT))
- {
- char cycles_text[32] = "";
-
- /* if the trace was captured with cycle accurate tracing enabled,
- * output the number of cycles since the last executed instruction
- */
- if (ctx->tracemode & ETMV1_CYCLE_ACCURATE)
- {
- snprintf(cycles_text, 32, " (%i %s)",
- cycles,
- (cycles == 1) ? "cycle" : "cycles");
- }
-
- command_print(cmd_ctx, "%s%s%s",
- instruction.text,
- (pipestat == STAT_IN) ? " (not executed)" : "",
- cycles_text);
-
- ctx->current_pc = next_pc;
-
- /* packets for an instruction don't start on or before the preceding
- * functional pipestat (i.e. other than WT or TD)
- */
- if (ctx->data_index <= ctx->pipe_index)
- {
- ctx->data_index = ctx->pipe_index + 1;
- ctx->data_half = 0;
- }
- }
-
- ctx->pipe_index += 1;
- }
-
- return ERROR_OK;
-}
-
-int handle_etm_tracemode_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target;
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- etmv1_tracemode_t tracemode;
-
- target = get_current_target(cmd_ctx);
-
- if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
- return ERROR_OK;
- }
-
- if (!arm7_9->etm_ctx)
- {
- command_print(cmd_ctx, "current target doesn't have an ETM configured");
- return ERROR_OK;
- }
-
- tracemode = arm7_9->etm_ctx->tracemode;
-
- if (argc == 4)
- {
- if (strcmp(args[0], "none") == 0)
- {
- tracemode = ETMV1_TRACE_NONE;
- }
- else if (strcmp(args[0], "data") == 0)
- {
- tracemode = ETMV1_TRACE_DATA;
- }
- else if (strcmp(args[0], "address") == 0)
- {
- tracemode = ETMV1_TRACE_ADDR;
- }
- else if (strcmp(args[0], "all") == 0)
- {
- tracemode = ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR;
- }
- else
- {
- command_print(cmd_ctx, "invalid option '%s'", args[0]);
- return ERROR_OK;
- }
-
- switch (strtol(args[1], NULL, 0))
- {
- case 0:
- tracemode |= ETMV1_CONTEXTID_NONE;
- break;
- case 8:
- tracemode |= ETMV1_CONTEXTID_8;
- break;
- case 16:
- tracemode |= ETMV1_CONTEXTID_16;
- break;
- case 32:
- tracemode |= ETMV1_CONTEXTID_32;
- break;
- default:
- command_print(cmd_ctx, "invalid option '%s'", args[1]);
- return ERROR_OK;
- }
-
- if (strcmp(args[2], "enable") == 0)
- {
- tracemode |= ETMV1_CYCLE_ACCURATE;
- }
- else if (strcmp(args[2], "disable") == 0)
- {
- tracemode |= 0;
- }
- else
- {
- command_print(cmd_ctx, "invalid option '%s'", args[2]);
- return ERROR_OK;
- }
-
- if (strcmp(args[3], "enable") == 0)
- {
- tracemode |= ETMV1_BRANCH_OUTPUT;
- }
- else if (strcmp(args[3], "disable") == 0)
- {
- tracemode |= 0;
- }
- else
- {
- command_print(cmd_ctx, "invalid option '%s'", args[2]);
- return ERROR_OK;
- }
- }
- else if (argc != 0)
- {
- command_print(cmd_ctx, "usage: configure trace mode <none|data|address|all> <context id bits> <cycle accurate> <branch output>");
- return ERROR_OK;
- }
-
- command_print(cmd_ctx, "current tracemode configuration:");
-
- switch (tracemode & ETMV1_TRACE_MASK)
- {
- case ETMV1_TRACE_NONE:
- command_print(cmd_ctx, "data tracing: none");
- break;
- case ETMV1_TRACE_DATA:
- command_print(cmd_ctx, "data tracing: data only");
- break;
- case ETMV1_TRACE_ADDR:
- command_print(cmd_ctx, "data tracing: address only");
- break;
- case ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR:
- command_print(cmd_ctx, "data tracing: address and data");
- break;
- }
-
- switch (tracemode & ETMV1_CONTEXTID_MASK)
- {
- case ETMV1_CONTEXTID_NONE:
- command_print(cmd_ctx, "contextid tracing: none");
- break;
- case ETMV1_CONTEXTID_8:
- command_print(cmd_ctx, "contextid tracing: 8 bit");
- break;
- case ETMV1_CONTEXTID_16:
- command_print(cmd_ctx, "contextid tracing: 16 bit");
- break;
- case ETMV1_CONTEXTID_32:
- command_print(cmd_ctx, "contextid tracing: 32 bit");
- break;
- }
-
- if (tracemode & ETMV1_CYCLE_ACCURATE)
- {
- command_print(cmd_ctx, "cycle-accurate tracing enabled");
- }
- else
- {
- command_print(cmd_ctx, "cycle-accurate tracing disabled");
- }
-
- if (tracemode & ETMV1_BRANCH_OUTPUT)
- {
- command_print(cmd_ctx, "full branch address output enabled");
- }
- else
- {
- command_print(cmd_ctx, "full branch address output disabled");
- }
-
- /* only update ETM_CTRL register if tracemode changed */
- if (arm7_9->etm_ctx->tracemode != tracemode)
- {
- reg_t *etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL];
-
- etm_get_reg(etm_ctrl_reg);
-
- buf_set_u32(etm_ctrl_reg->value, 2, 2, tracemode & ETMV1_TRACE_MASK);
- buf_set_u32(etm_ctrl_reg->value, 14, 2, (tracemode & ETMV1_CONTEXTID_MASK) >> 4);
- buf_set_u32(etm_ctrl_reg->value, 12, 1, (tracemode & ETMV1_CYCLE_ACCURATE) >> 8);
- buf_set_u32(etm_ctrl_reg->value, 8, 1, (tracemode & ETMV1_BRANCH_OUTPUT) >> 9);
- etm_store_reg(etm_ctrl_reg);
-
- arm7_9->etm_ctx->tracemode = tracemode;
-
- /* invalidate old trace data */
- arm7_9->etm_ctx->capture_status = TRACE_IDLE;
- if (arm7_9->etm_ctx->trace_depth > 0)
- {
- free(arm7_9->etm_ctx->trace_data);
- arm7_9->etm_ctx->trace_data = NULL;
- }
- arm7_9->etm_ctx->trace_depth = 0;
- }
-
- return ERROR_OK;
-}
-
-int handle_etm_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target;
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- etm_portmode_t portmode = 0x0;
- etm_context_t *etm_ctx = malloc(sizeof(etm_context_t));
- int i;
-
- if (argc != 5)
- {
- ERROR("incomplete 'etm config <target> <port_width> <port_mode> <clocking> <capture_driver>' command");
- exit(-1);
- }
-
- target = get_target_by_num(strtoul(args[0], NULL, 0));
-
- if (!target)
- {
- ERROR("target number '%s' not defined", args[0]);
- exit(-1);
- }
-
- if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
- return ERROR_OK;
- }
-
- switch (strtoul(args[1], NULL, 0))
- {
- case 4:
- portmode |= ETM_PORT_4BIT;
- break;
- case 8:
- portmode |= ETM_PORT_8BIT;
- break;
- case 16:
- portmode |= ETM_PORT_16BIT;
- break;
- default:
- command_print(cmd_ctx, "unsupported ETM port width '%s', must be 4, 8 or 16", args[1]);
- return ERROR_OK;
- }
-
- if (strcmp("normal", args[2]) == 0)
- {
- portmode |= ETM_PORT_NORMAL;
- }
- else if (strcmp("multiplexed", args[2]) == 0)
- {
- portmode |= ETM_PORT_MUXED;
- }
- else if (strcmp("demultiplexed", args[2]) == 0)
- {
- portmode |= ETM_PORT_DEMUXED;
- }
- else
- {
- command_print(cmd_ctx, "unsupported ETM port mode '%s', must be 'normal', 'multiplexed' or 'demultiplexed'", args[2]);
- return ERROR_OK;
- }
-
- if (strcmp("half", args[3]) == 0)
- {
- portmode |= ETM_PORT_HALF_CLOCK;
- }
- else if (strcmp("full", args[3]) == 0)
- {
- portmode |= ETM_PORT_FULL_CLOCK;
- }
- else
- {
- command_print(cmd_ctx, "unsupported ETM port clocking '%s', must be 'full' or 'half'", args[3]);
- return ERROR_OK;
- }
-
- for (i=0; etm_capture_drivers[i]; i++)
- {
- if (strcmp(args[4], etm_capture_drivers[i]->name) == 0)
- {
- if (etm_capture_drivers[i]->register_commands(cmd_ctx) != ERROR_OK)
- {
- free(etm_ctx);
- exit(-1);
- }
-
- etm_ctx->capture_driver = etm_capture_drivers[i];
-
- break;
- }
- }
-
- if (!etm_capture_drivers[i])
- {
- /* no supported capture driver found, don't register an ETM */
- free(etm_ctx);
- ERROR("trace capture driver '%s' not found", args[4]);
- return ERROR_OK;
- }
-
- etm_ctx->target = target;
- etm_ctx->trigger_percent = 50;
- etm_ctx->trace_data = NULL;
- etm_ctx->trace_depth = 0;
- etm_ctx->portmode = portmode;
- etm_ctx->tracemode = 0x0;
- etm_ctx->core_state = ARMV4_5_STATE_ARM;
- etm_ctx->image = NULL;
- etm_ctx->pipe_index = 0;
- etm_ctx->data_index = 0;
- etm_ctx->current_pc = 0x0;
- etm_ctx->pc_ok = 0;
- etm_ctx->last_branch = 0x0;
- etm_ctx->last_branch_reason = 0x0;
- etm_ctx->last_ptr = 0x0;
- etm_ctx->ptr_ok = 0x0;
- etm_ctx->context_id = 0x0;
- etm_ctx->last_instruction = 0;
-
- arm7_9->etm_ctx = etm_ctx;
-
- etm_register_user_commands(cmd_ctx);
-
- return ERROR_OK;
-}
-
-int handle_etm_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target;
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- reg_t *etm_config_reg;
- reg_t *etm_sys_config_reg;
-
- int max_port_size;
-
- target = get_current_target(cmd_ctx);
-
- if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
- return ERROR_OK;
- }
-
- if (!arm7_9->etm_ctx)
- {
- command_print(cmd_ctx, "current target doesn't have an ETM configured");
- return ERROR_OK;
- }
-
- etm_config_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CONFIG];
- etm_sys_config_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_SYS_CONFIG];
-
- etm_get_reg(etm_config_reg);
- command_print(cmd_ctx, "pairs of address comparators: %i", buf_get_u32(etm_config_reg->value, 0, 4));
- command_print(cmd_ctx, "pairs of data comparators: %i", buf_get_u32(etm_config_reg->value, 4, 4));
- command_print(cmd_ctx, "memory map decoders: %i", buf_get_u32(etm_config_reg->value, 8, 5));
- command_print(cmd_ctx, "number of counters: %i", buf_get_u32(etm_config_reg->value, 13, 3));
- command_print(cmd_ctx, "sequencer %spresent",
- (buf_get_u32(etm_config_reg->value, 16, 1) == 1) ? "" : "not ");
- command_print(cmd_ctx, "number of ext. inputs: %i", buf_get_u32(etm_config_reg->value, 17, 3));
- command_print(cmd_ctx, "number of ext. outputs: %i", buf_get_u32(etm_config_reg->value, 20, 3));
- command_print(cmd_ctx, "FIFO full %spresent",
- (buf_get_u32(etm_config_reg->value, 23, 1) == 1) ? "" : "not ");
- command_print(cmd_ctx, "protocol version: %i", buf_get_u32(etm_config_reg->value, 28, 3));
-
- etm_get_reg(etm_sys_config_reg);
-
- switch (buf_get_u32(etm_sys_config_reg->value, 0, 3))
- {
- case 0:
- max_port_size = 4;
- break;
- case 1:
- max_port_size = 8;
- break;
- case 2:
- max_port_size = 16;
- break;
- }
- command_print(cmd_ctx, "max. port size: %i", max_port_size);
-
- command_print(cmd_ctx, "half-rate clocking %ssupported",
- (buf_get_u32(etm_sys_config_reg->value, 3, 1) == 1) ? "" : "not ");
- command_print(cmd_ctx, "full-rate clocking %ssupported",
- (buf_get_u32(etm_sys_config_reg->value, 4, 1) == 1) ? "" : "not ");
- command_print(cmd_ctx, "normal trace format %ssupported",
- (buf_get_u32(etm_sys_config_reg->value, 5, 1) == 1) ? "" : "not ");
- command_print(cmd_ctx, "multiplex trace format %ssupported",
- (buf_get_u32(etm_sys_config_reg->value, 6, 1) == 1) ? "" : "not ");
- command_print(cmd_ctx, "demultiplex trace format %ssupported",
- (buf_get_u32(etm_sys_config_reg->value, 7, 1) == 1) ? "" : "not ");
- command_print(cmd_ctx, "FIFO full %ssupported",
- (buf_get_u32(etm_sys_config_reg->value, 8, 1) == 1) ? "" : "not ");
-
- return ERROR_OK;
-}
-
-int handle_etm_status_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target;
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- trace_status_t trace_status;
-
- target = get_current_target(cmd_ctx);
-
- if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
- return ERROR_OK;
- }
-
- if (!arm7_9->etm_ctx)
- {
- command_print(cmd_ctx, "current target doesn't have an ETM configured");
- return ERROR_OK;
- }
-
- trace_status = arm7_9->etm_ctx->capture_driver->status(arm7_9->etm_ctx);
-
- if (trace_status == TRACE_IDLE)
- {
- command_print(cmd_ctx, "tracing is idle");
- }
- else
- {
- static char *completed = " completed";
- static char *running = " is running";
- static char *overflowed = ", trace overflowed";
- static char *triggered = ", trace triggered";
-
- command_print(cmd_ctx, "trace collection%s%s%s",
- (trace_status & TRACE_RUNNING) ? running : completed,
- (trace_status & TRACE_OVERFLOWED) ? overflowed : "",
- (trace_status & TRACE_TRIGGERED) ? triggered : "");
-
- if (arm7_9->etm_ctx->trace_depth > 0)
- {
- command_print(cmd_ctx, "%i frames of trace data read", arm7_9->etm_ctx->trace_depth);
- }
- }
-
- return ERROR_OK;
-}
-
-int handle_etm_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target;
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- etm_context_t *etm_ctx;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "usage: etm image <file> [base address] [type]");
- return ERROR_OK;
- }
-
- target = get_current_target(cmd_ctx);
-
- if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
- return ERROR_OK;
- }
-
- if (!(etm_ctx = arm7_9->etm_ctx))
- {
- command_print(cmd_ctx, "current target doesn't have an ETM configured");
- return ERROR_OK;
- }
-
- if (etm_ctx->image)
- {
- image_close(etm_ctx->image);
- free(etm_ctx->image);
- command_print(cmd_ctx, "previously loaded image found and closed");
- }
-
- etm_ctx->image = malloc(sizeof(image_t));
- etm_ctx->image->base_address_set = 0;
- etm_ctx->image->start_address_set = 0;
-
- /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */
- if (argc >= 2)
- {
- etm_ctx->image->base_address_set = 1;
- etm_ctx->image->base_address = strtoul(args[1], NULL, 0);
- }
- else
- {
- etm_ctx->image->base_address_set = 0;
- }
-
- if (image_open(etm_ctx->image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK)
- {
- command_print(cmd_ctx, "image opening error: %s", etm_ctx->image->error_str);
- free(etm_ctx->image);
- etm_ctx->image = NULL;
- return ERROR_OK;
- }
-
- return ERROR_OK;
-}
-
-int handle_etm_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- fileio_t file;
- target_t *target;
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- etm_context_t *etm_ctx;
- int i;
-
- if (argc != 1)
- {
- command_print(cmd_ctx, "usage: etm dump <file>");
- return ERROR_OK;
- }
-
- target = get_current_target(cmd_ctx);
-
- if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
- return ERROR_OK;
- }
-
- if (!(etm_ctx = arm7_9->etm_ctx))
- {
- command_print(cmd_ctx, "current target doesn't have an ETM configured");
- return ERROR_OK;
- }
-
- if (etm_ctx->capture_driver->status == TRACE_IDLE)
- {
- command_print(cmd_ctx, "trace capture wasn't enabled, no trace data captured");
- return ERROR_OK;
- }
-
- if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING)
- {
- /* TODO: if on-the-fly capture is to be supported, this needs to be changed */
- command_print(cmd_ctx, "trace capture not completed");
- return ERROR_OK;
- }
-
- /* read the trace data if it wasn't read already */
- if (etm_ctx->trace_depth == 0)
- etm_ctx->capture_driver->read_trace(etm_ctx);
-
- if (fileio_open(&file, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK)
- {
- command_print(cmd_ctx, "file open error: %s", file.error_str);
- return ERROR_OK;
- }
-
- fileio_write_u32(&file, etm_ctx->capture_status);
- fileio_write_u32(&file, etm_ctx->portmode);
- fileio_write_u32(&file, etm_ctx->tracemode);
- fileio_write_u32(&file, etm_ctx->trace_depth);
-
- for (i = 0; i < etm_ctx->trace_depth; i++)
- {
- fileio_write_u32(&file, etm_ctx->trace_data[i].pipestat);
- fileio_write_u32(&file, etm_ctx->trace_data[i].packet);
- fileio_write_u32(&file, etm_ctx->trace_data[i].flags);
- }
-
- fileio_close(&file);
-
- return ERROR_OK;
-}
-
-int handle_etm_load_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- fileio_t file;
- target_t *target;
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- etm_context_t *etm_ctx;
- int i;
-
- if (argc != 1)
- {
- command_print(cmd_ctx, "usage: etm load <file>");
- return ERROR_OK;
- }
-
- target = get_current_target(cmd_ctx);
-
- if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
- return ERROR_OK;
- }
-
- if (!(etm_ctx = arm7_9->etm_ctx))
- {
- command_print(cmd_ctx, "current target doesn't have an ETM configured");
- return ERROR_OK;
- }
-
- if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING)
- {
- command_print(cmd_ctx, "trace capture running, stop first");
- return ERROR_OK;
- }
-
- if (fileio_open(&file, args[0], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
- {
- command_print(cmd_ctx, "file open error: %s", file.error_str);
- return ERROR_OK;
- }
-
- if (file.size % 4)
- {
- command_print(cmd_ctx, "size isn't a multiple of 4, no valid trace data");
- return ERROR_OK;
- }
-
- if (etm_ctx->trace_depth > 0)
- {
- free(etm_ctx->trace_data);
- }
-
- fileio_read_u32(&file, &etm_ctx->capture_status);
- fileio_read_u32(&file, &etm_ctx->portmode);
- fileio_read_u32(&file, &etm_ctx->tracemode);
- fileio_read_u32(&file, &etm_ctx->trace_depth);
-
- etm_ctx->trace_data = malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth);
-
- for (i = 0; i < etm_ctx->trace_depth; i++)
- {
- u32 pipestat, packet, flags;
- fileio_read_u32(&file, &pipestat);
- fileio_read_u32(&file, &packet);
- fileio_read_u32(&file, &flags);
- etm_ctx->trace_data[i].pipestat = pipestat & 0xff;
- etm_ctx->trace_data[i].packet = packet & 0xffff;
- etm_ctx->trace_data[i].flags = flags;
- }
-
- fileio_close(&file);
-
- return ERROR_OK;
-}
-
-int handle_etm_trigger_percent_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target;
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- etm_context_t *etm_ctx;
-
- target = get_current_target(cmd_ctx);
-
- if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
- return ERROR_OK;
- }
-
- if (!(etm_ctx = arm7_9->etm_ctx))
- {
- command_print(cmd_ctx, "current target doesn't have an ETM configured");
- return ERROR_OK;
- }
-
- if (argc > 0)
- {
- u32 new_value = strtoul(args[0], NULL, 0);
-
- if ((new_value < 2) || (new_value > 100))
- {
- command_print(cmd_ctx, "valid settings are 2% to 100%");
- }
- else
- {
- etm_ctx->trigger_percent = new_value;
- }
- }
-
- command_print(cmd_ctx, "%i percent of the tracebuffer reserved for after the trigger", etm_ctx->trigger_percent);
-
- return ERROR_OK;
-}
-
-int handle_etm_start_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target;
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- etm_context_t *etm_ctx;
- reg_t *etm_ctrl_reg;
-
- target = get_current_target(cmd_ctx);
-
- if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
- return ERROR_OK;
- }
-
- if (!(etm_ctx = arm7_9->etm_ctx))
- {
- command_print(cmd_ctx, "current target doesn't have an ETM configured");
- return ERROR_OK;
- }
-
- /* invalidate old tracing data */
- arm7_9->etm_ctx->capture_status = TRACE_IDLE;
- if (arm7_9->etm_ctx->trace_depth > 0)
- {
- free(arm7_9->etm_ctx->trace_data);
- arm7_9->etm_ctx->trace_data = NULL;
- }
- arm7_9->etm_ctx->trace_depth = 0;
-
- etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL];
- etm_get_reg(etm_ctrl_reg);
-
- /* Clear programming bit (10), set port selection bit (11) */
- buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x2);
-
- etm_store_reg(etm_ctrl_reg);
- jtag_execute_queue();
-
- etm_ctx->capture_driver->start_capture(etm_ctx);
-
- return ERROR_OK;
-}
-
-int handle_etm_stop_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target;
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- etm_context_t *etm_ctx;
- reg_t *etm_ctrl_reg;
-
- target = get_current_target(cmd_ctx);
-
- if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
- return ERROR_OK;
- }
-
- if (!(etm_ctx = arm7_9->etm_ctx))
- {
- command_print(cmd_ctx, "current target doesn't have an ETM configured");
- return ERROR_OK;
- }
-
- etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL];
- etm_get_reg(etm_ctrl_reg);
-
- /* Set programming bit (10), clear port selection bit (11) */
- buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x1);
-
- etm_store_reg(etm_ctrl_reg);
- jtag_execute_queue();
-
- etm_ctx->capture_driver->stop_capture(etm_ctx);
-
- return ERROR_OK;
-}
-
-int handle_etm_analyze_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target;
- armv4_5_common_t *armv4_5;
- arm7_9_common_t *arm7_9;
- etm_context_t *etm_ctx;
- int retval;
-
- target = get_current_target(cmd_ctx);
-
- if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
- {
- command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
- return ERROR_OK;
- }
-
- if (!(etm_ctx = arm7_9->etm_ctx))
- {
- command_print(cmd_ctx, "current target doesn't have an ETM configured");
- return ERROR_OK;
- }
-
- if ((retval = etmv1_analyze_trace(etm_ctx, cmd_ctx)) != ERROR_OK)
- {
- switch(retval)
- {
- case ERROR_ETM_ANALYSIS_FAILED:
- command_print(cmd_ctx, "further analysis failed (corrupted trace data or just end of data");
- break;
- case ERROR_TRACE_INSTRUCTION_UNAVAILABLE:
- command_print(cmd_ctx, "no instruction for current address available, analysis aborted");
- break;
- case ERROR_TRACE_IMAGE_UNAVAILABLE:
- command_print(cmd_ctx, "no image available for trace analysis");
- break;
- default:
- command_print(cmd_ctx, "unknown error: %i", retval);
- }
- }
-
- return ERROR_OK;
-}
-
-int etm_register_commands(struct command_context_s *cmd_ctx)
-{
- etm_cmd = register_command(cmd_ctx, NULL, "etm", NULL, COMMAND_ANY, "Embedded Trace Macrocell");
-
- register_command(cmd_ctx, etm_cmd, "config", handle_etm_config_command, COMMAND_CONFIG, NULL);
-
- return ERROR_OK;
-}
-
-int etm_register_user_commands(struct command_context_s *cmd_ctx)
-{
- register_command(cmd_ctx, etm_cmd, "tracemode", handle_etm_tracemode_command,
- COMMAND_EXEC, "configure trace mode <none|data|address|all> <context id bits> <cycle accurate> <branch output");
-
- register_command(cmd_ctx, etm_cmd, "info", handle_etm_info_command,
- COMMAND_EXEC, "display info about the current target's ETM");
-
- register_command(cmd_ctx, etm_cmd, "trigger_percent <percent>", handle_etm_trigger_percent_command,
- COMMAND_EXEC, "amount (<percent>) of trace buffer to be filled after the trigger occured");
- register_command(cmd_ctx, etm_cmd, "status", handle_etm_status_command,
- COMMAND_EXEC, "display current target's ETM status");
- register_command(cmd_ctx, etm_cmd, "start", handle_etm_start_command,
- COMMAND_EXEC, "start ETM trace collection");
- register_command(cmd_ctx, etm_cmd, "stop", handle_etm_stop_command,
- COMMAND_EXEC, "stop ETM trace collection");
-
- register_command(cmd_ctx, etm_cmd, "analyze", handle_etm_analyze_command,
- COMMAND_EXEC, "anaylze collected ETM trace");
-
- register_command(cmd_ctx, etm_cmd, "image", handle_etm_image_command,
- COMMAND_EXEC, "load image from <file> [base address]");
-
- register_command(cmd_ctx, etm_cmd, "dump", handle_etm_dump_command,
- COMMAND_EXEC, "dump captured trace data <file>");
- register_command(cmd_ctx, etm_cmd, "load", handle_etm_load_command,
- COMMAND_EXEC, "load trace data for analysis <file>");
-
- return ERROR_OK;
-}
+/*************************************************************************** + * 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 <string.h> + +#include "etm.h" +#include "etb.h" + +#include "armv4_5.h" +#include "arm7_9_common.h" +#include "arm_disassembler.h" +#include "arm_simulator.h" + +#include "log.h" +#include "arm_jtag.h" +#include "types.h" +#include "binarybuffer.h" +#include "target.h" +#include "register.h" +#include "jtag.h" +#include "fileio.h" + +#include <stdlib.h> + +/* ETM register access functionality + * + */ + +bitfield_desc_t etm_comms_ctrl_bitfield_desc[] = +{ + {"R", 1}, + {"W", 1}, + {"reserved", 26}, + {"version", 4} +}; + +int etm_reg_arch_info[] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, +}; + +int etm_reg_arch_size_info[] = +{ + 32, 32, 17, 8, 3, 9, 32, 16, + 17, 26, 25, 8, 17, 32, 32, 17, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 16, 16, 16, 16, 18, 18, 18, 18, + 17, 17, 17, 17, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 2, + 17, 17, 17, 17, 32, 32, 32, 32 +}; + +char* etm_reg_list[] = +{ + "ETM_CTRL", + "ETM_CONFIG", + "ETM_TRIG_EVENT", + "ETM_MMD_CTRL", + "ETM_STATUS", + "ETM_SYS_CONFIG", + "ETM_TRACE_RESOURCE_CTRL", + "ETM_TRACE_EN_CTRL2", + "ETM_TRACE_EN_EVENT", + "ETM_TRACE_EN_CTRL1", + "ETM_FIFOFULL_REGION", + "ETM_FIFOFULL_LEVEL", + "ETM_VIEWDATA_EVENT", + "ETM_VIEWDATA_CTRL1", + "ETM_VIEWDATA_CTRL2", + "ETM_VIEWDATA_CTRL3", + "ETM_ADDR_COMPARATOR_VALUE1", + "ETM_ADDR_COMPARATOR_VALUE2", + "ETM_ADDR_COMPARATOR_VALUE3", + "ETM_ADDR_COMPARATOR_VALUE4", + "ETM_ADDR_COMPARATOR_VALUE5", + "ETM_ADDR_COMPARATOR_VALUE6", + "ETM_ADDR_COMPARATOR_VALUE7", + "ETM_ADDR_COMPARATOR_VALUE8", + "ETM_ADDR_COMPARATOR_VALUE9", + "ETM_ADDR_COMPARATOR_VALUE10", + "ETM_ADDR_COMPARATOR_VALUE11", + "ETM_ADDR_COMPARATOR_VALUE12", + "ETM_ADDR_COMPARATOR_VALUE13", + "ETM_ADDR_COMPARATOR_VALUE14", + "ETM_ADDR_COMPARATOR_VALUE15", + "ETM_ADDR_COMPARATOR_VALUE16", + "ETM_ADDR_ACCESS_TYPE1", + "ETM_ADDR_ACCESS_TYPE2", + "ETM_ADDR_ACCESS_TYPE3", + "ETM_ADDR_ACCESS_TYPE4", + "ETM_ADDR_ACCESS_TYPE5", + "ETM_ADDR_ACCESS_TYPE6", + "ETM_ADDR_ACCESS_TYPE7", + "ETM_ADDR_ACCESS_TYPE8", + "ETM_ADDR_ACCESS_TYPE9", + "ETM_ADDR_ACCESS_TYPE10", + "ETM_ADDR_ACCESS_TYPE11", + "ETM_ADDR_ACCESS_TYPE12", + "ETM_ADDR_ACCESS_TYPE13", + "ETM_ADDR_ACCESS_TYPE14", + "ETM_ADDR_ACCESS_TYPE15", + "ETM_ADDR_ACCESS_TYPE16", + "ETM_DATA_COMPARATOR_VALUE1", + "ETM_DATA_COMPARATOR_VALUE2", + "ETM_DATA_COMPARATOR_VALUE3", + "ETM_DATA_COMPARATOR_VALUE4", + "ETM_DATA_COMPARATOR_VALUE5", + "ETM_DATA_COMPARATOR_VALUE6", + "ETM_DATA_COMPARATOR_VALUE7", + "ETM_DATA_COMPARATOR_VALUE8", + "ETM_DATA_COMPARATOR_VALUE9", + "ETM_DATA_COMPARATOR_VALUE10", + "ETM_DATA_COMPARATOR_VALUE11", + "ETM_DATA_COMPARATOR_VALUE12", + "ETM_DATA_COMPARATOR_VALUE13", + "ETM_DATA_COMPARATOR_VALUE14", + "ETM_DATA_COMPARATOR_VALUE15", + "ETM_DATA_COMPARATOR_VALUE16", + "ETM_DATA_COMPARATOR_MASK1", + "ETM_DATA_COMPARATOR_MASK2", + "ETM_DATA_COMPARATOR_MASK3", + "ETM_DATA_COMPARATOR_MASK4", + "ETM_DATA_COMPARATOR_MASK5", + "ETM_DATA_COMPARATOR_MASK6", + "ETM_DATA_COMPARATOR_MASK7", + "ETM_DATA_COMPARATOR_MASK8", + "ETM_DATA_COMPARATOR_MASK9", + "ETM_DATA_COMPARATOR_MASK10", + "ETM_DATA_COMPARATOR_MASK11", + "ETM_DATA_COMPARATOR_MASK12", + "ETM_DATA_COMPARATOR_MASK13", + "ETM_DATA_COMPARATOR_MASK14", + "ETM_DATA_COMPARATOR_MASK15", + "ETM_DATA_COMPARATOR_MASK16", + "ETM_COUNTER_INITAL_VALUE1", + "ETM_COUNTER_INITAL_VALUE2", + "ETM_COUNTER_INITAL_VALUE3", + "ETM_COUNTER_INITAL_VALUE4", + "ETM_COUNTER_ENABLE1", + "ETM_COUNTER_ENABLE2", + "ETM_COUNTER_ENABLE3", + "ETM_COUNTER_ENABLE4", + "ETM_COUNTER_RELOAD_VALUE1", + "ETM_COUNTER_RELOAD_VALUE2", + "ETM_COUNTER_RELOAD_VALUE3", + "ETM_COUNTER_RELOAD_VALUE4", + "ETM_COUNTER_VALUE1", + "ETM_COUNTER_VALUE2", + "ETM_COUNTER_VALUE3", + "ETM_COUNTER_VALUE4", + "ETM_SEQUENCER_CTRL1", + "ETM_SEQUENCER_CTRL2", + "ETM_SEQUENCER_CTRL3", + "ETM_SEQUENCER_CTRL4", + "ETM_SEQUENCER_CTRL5", + "ETM_SEQUENCER_CTRL6", + "ETM_SEQUENCER_STATE", + "ETM_EXTERNAL_OUTPUT1", + "ETM_EXTERNAL_OUTPUT2", + "ETM_EXTERNAL_OUTPUT3", + "ETM_EXTERNAL_OUTPUT4", + "ETM_CONTEXTID_COMPARATOR_VALUE1", + "ETM_CONTEXTID_COMPARATOR_VALUE2", + "ETM_CONTEXTID_COMPARATOR_VALUE3", + "ETM_CONTEXTID_COMPARATOR_MASK" +}; + +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); + +command_t *etm_cmd = NULL; + +reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_context_t *etm_ctx) +{ + reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t)); + reg_t *reg_list = NULL; + etm_reg_t *arch_info = NULL; + int num_regs = sizeof(etm_reg_arch_info)/sizeof(int); + int i; + u32 etm_ctrl_value; + + /* register a register arch-type for etm registers only once */ + if (etm_reg_arch_type == -1) + etm_reg_arch_type = register_reg_arch_type(etm_get_reg, etm_set_reg_w_exec); + + /* the actual registers are kept in two arrays */ + reg_list = calloc(num_regs, sizeof(reg_t)); + arch_info = calloc(num_regs, sizeof(etm_reg_t)); + + /* fill in values for the reg cache */ + reg_cache->name = "etm registers"; + reg_cache->next = NULL; + reg_cache->reg_list = reg_list; + reg_cache->num_regs = num_regs; + + /* set up registers */ + for (i = 0; i < num_regs; i++) + { + reg_list[i].name = etm_reg_list[i]; + reg_list[i].size = 32; + reg_list[i].dirty = 0; + reg_list[i].valid = 0; + reg_list[i].bitfield_desc = NULL; + reg_list[i].num_bitfields = 0; + reg_list[i].value = calloc(1, 4); + reg_list[i].arch_info = &arch_info[i]; + reg_list[i].arch_type = etm_reg_arch_type; + reg_list[i].size = etm_reg_arch_size_info[i]; + arch_info[i].addr = etm_reg_arch_info[i]; + arch_info[i].jtag_info = jtag_info; + } + + /* initialize some ETM control register settings */ + etm_get_reg(®_list[ETM_CTRL]); + etm_ctrl_value = buf_get_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size); + + /* clear the ETM powerdown bit (0) */ + etm_ctrl_value &= ~0x1; + + /* configure port width (6:4), mode (17:16) and clocking (13) */ + etm_ctrl_value = (etm_ctrl_value & + ~ETM_PORT_WIDTH_MASK & ~ETM_PORT_MODE_MASK & ~ETM_PORT_CLOCK_MASK) + | etm_ctx->portmode; + + buf_set_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size, etm_ctrl_value); + etm_store_reg(®_list[ETM_CTRL]); + + /* the ETM might have an ETB connected */ + if (strcmp(etm_ctx->capture_driver->name, "etb") == 0) + { + etb_t *etb = etm_ctx->capture_driver_priv; + + if (!etb) + { + ERROR("etb selected as etm capture driver, but no ETB configured"); + return ERROR_OK; + } + + reg_cache->next = etb_build_reg_cache(etb); + + etb->reg_cache = reg_cache->next; + } + + if (etm_ctx->capture_driver->init(etm_ctx) != ERROR_OK) + { + ERROR("ETM capture driver initialization failed"); + exit(-1); + } + + return reg_cache; +} + +int etm_get_reg(reg_t *reg) +{ + if (etm_read_reg(reg) != ERROR_OK) + { + ERROR("BUG: error scheduling etm register read"); + exit(-1); + } + + if (jtag_execute_queue() != ERROR_OK) + { + ERROR("register read failed"); + } + + return ERROR_OK; +} + +int etm_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask) +{ + etm_reg_t *etm_reg = reg->arch_info; + u8 reg_addr = etm_reg->addr & 0x7f; + scan_field_t fields[3]; + + DEBUG("%i", etm_reg->addr); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(etm_reg->jtag_info, 0x6); + arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr, NULL); + + fields[0].device = etm_reg->jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = reg->value; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = etm_reg->jtag_info->chain_pos; + fields[1].num_bits = 7; + fields[1].out_value = malloc(1); + buf_set_u32(fields[1].out_value, 0, 7, reg_addr); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = etm_reg->jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = malloc(1); + buf_set_u32(fields[2].out_value, 0, 1, 0); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + fields[0].in_value = reg->value; + jtag_set_check_value(fields+0, check_value, check_mask, NULL); + + jtag_add_dr_scan(3, fields, -1); + + free(fields[1].out_value); + free(fields[2].out_value); + + return ERROR_OK; +} + +int etm_read_reg(reg_t *reg) +{ + return etm_read_reg_w_check(reg, NULL, NULL); +} + +int etm_set_reg(reg_t *reg, u32 value) +{ + if (etm_write_reg(reg, value) != ERROR_OK) + { + ERROR("BUG: error scheduling etm register write"); + exit(-1); + } + + buf_set_u32(reg->value, 0, reg->size, value); + reg->valid = 1; + reg->dirty = 0; + + return ERROR_OK; +} + +int etm_set_reg_w_exec(reg_t *reg, u8 *buf) +{ + etm_set_reg(reg, buf_get_u32(buf, 0, reg->size)); + + if (jtag_execute_queue() != ERROR_OK) + { + ERROR("register write failed"); + exit(-1); + } + return ERROR_OK; +} + +int etm_write_reg(reg_t *reg, u32 value) +{ + etm_reg_t *etm_reg = reg->arch_info; + u8 reg_addr = etm_reg->addr & 0x7f; + scan_field_t fields[3]; + + DEBUG("%i: 0x%8.8x", etm_reg->addr, value); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(etm_reg->jtag_info, 0x6); + arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr, NULL); + + fields[0].device = etm_reg->jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = malloc(4); + buf_set_u32(fields[0].out_value, 0, 32, value); + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = etm_reg->jtag_info->chain_pos; + fields[1].num_bits = 7; + fields[1].out_value = malloc(1); + buf_set_u32(fields[1].out_value, 0, 7, reg_addr); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = etm_reg->jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = malloc(1); + buf_set_u32(fields[2].out_value, 0, 1, 1); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + free(fields[0].out_value); + free(fields[1].out_value); + free(fields[2].out_value); + + return ERROR_OK; +} + +int etm_store_reg(reg_t *reg) +{ + return etm_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); +} + +/* ETM trace analysis functionality + * + */ +extern etm_capture_driver_t etb_capture_driver; +extern etm_capture_driver_t etm_dummy_capture_driver; +#if BUILD_OOCD_TRACE == 1 +extern etm_capture_driver_t oocd_trace_capture_driver; +#endif + +etm_capture_driver_t *etm_capture_drivers[] = +{ + &etb_capture_driver, + &etm_dummy_capture_driver, +#if BUILD_OOCD_TRACE == 1 + &oocd_trace_capture_driver, +#endif + NULL +}; + +char *etmv1v1_branch_reason_strings[] = +{ + "normal PC change", + "tracing enabled", + "trace restarted after overflow", + "exit from debug", + "periodic synchronization", + "reserved", + "reserved", + "reserved", +}; + +int etm_read_instruction(etm_context_t *ctx, arm_instruction_t *instruction) +{ + int i; + int section = -1; + u32 size_read; + u32 opcode; + int retval; + + if (!ctx->image) + return ERROR_TRACE_IMAGE_UNAVAILABLE; + + /* search for the section the current instruction belongs to */ + for (i = 0; i < ctx->image->num_sections; i++) + { + if ((ctx->image->sections[i].base_address <= ctx->current_pc) && + (ctx->image->sections[i].base_address + ctx->image->sections[i].size > ctx->current_pc)) + { + section = i; + break; + } + } + + if (section == -1) + { + /* current instruction couldn't be found in the image */ + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + + if (ctx->core_state == ARMV4_5_STATE_ARM) + { + u8 buf[4]; + if ((retval = image_read_section(ctx->image, section, + ctx->current_pc - ctx->image->sections[section].base_address, + 4, buf, &size_read)) != ERROR_OK) + { + ERROR("error while reading instruction: %i", retval); + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + opcode = target_buffer_get_u32(ctx->target, buf); + arm_evaluate_opcode(opcode, ctx->current_pc, instruction); + } + else if (ctx->core_state == ARMV4_5_STATE_THUMB) + { + u8 buf[2]; + if ((retval = image_read_section(ctx->image, section, + ctx->current_pc - ctx->image->sections[section].base_address, + 2, buf, &size_read)) != ERROR_OK) + { + ERROR("error while reading instruction: %i", retval); + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + opcode = target_buffer_get_u16(ctx->target, buf); + thumb_evaluate_opcode(opcode, ctx->current_pc, instruction); + } + else if (ctx->core_state == ARMV4_5_STATE_JAZELLE) + { + ERROR("BUG: tracing of jazelle code not supported"); + exit(-1); + } + else + { + ERROR("BUG: unknown core state encountered"); + exit(-1); + } + + return ERROR_OK; +} + +int etmv1_next_packet(etm_context_t *ctx, u8 *packet, int apo) +{ + while (ctx->data_index < ctx->trace_depth) + { + /* if the caller specified an address packet offset, skip until the + * we reach the n-th cycle marked with tracesync */ + if (apo > 0) + { + if (ctx->trace_data[ctx->data_index].flags & ETMV1_TRACESYNC_CYCLE) + apo--; + + if (apo > 0) + { + ctx->data_index++; + ctx->data_half = 0; + } + continue; + } + + /* no tracedata output during a TD cycle + * or in a trigger cycle */ + if ((ctx->trace_data[ctx->data_index].pipestat == STAT_TD) + || (ctx->trace_data[ctx->data_index].flags & ETMV1_TRIGGER_CYCLE)) + { + ctx->data_index++; + ctx->data_half = 0; + continue; + } + + if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_16BIT) + { + if (ctx->data_half == 0) + { + *packet = ctx->trace_data[ctx->data_index].packet & 0xff; + ctx->data_half = 1; + } + else + { + *packet = (ctx->trace_data[ctx->data_index].packet & 0xff00) >> 8; + ctx->data_half = 0; + ctx->data_index++; + } + } + else if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) + { + *packet = ctx->trace_data[ctx->data_index].packet & 0xff; + ctx->data_index++; + } + else + { + /* on a 4-bit port, a packet will be output during two consecutive cycles */ + if (ctx->data_index > (ctx->trace_depth - 2)) + return -1; + + *packet = ctx->trace_data[ctx->data_index].packet & 0xf; + *packet |= (ctx->trace_data[ctx->data_index + 1].packet & 0xf) << 4; + ctx->data_index += 2; + } + + return 0; + } + + return -1; +} + +int etmv1_branch_address(etm_context_t *ctx) +{ + int retval; + u8 packet; + int shift = 0; + int apo; + int i; + + /* quit analysis if less than two cycles are left in the trace + * because we can't extract the APO */ + if (ctx->data_index > (ctx->trace_depth - 2)) + return -1; + + /* a BE could be output during an APO cycle, skip the current + * and continue with the new one */ + if (ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x4) + return 1; + if (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x4) + return 2; + + /* address packet offset encoded in the next two cycles' pipestat bits */ + apo = ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x3; + apo |= (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x3) << 2; + + /* count number of tracesync cycles between current pipe_index and data_index + * i.e. the number of tracesyncs that data_index already passed by + * to subtract them from the APO */ + for (i = ctx->pipe_index; i < ctx->data_index; i++) + { + if (ctx->trace_data[ctx->pipe_index + 1].pipestat & ETMV1_TRACESYNC_CYCLE) + apo--; + } + + /* extract up to four 7-bit packets */ + do { + if ((retval = etmv1_next_packet(ctx, &packet, (shift == 0) ? apo + 1 : 0)) != 0) + return -1; + ctx->last_branch &= ~(0x7f << shift); + ctx->last_branch |= (packet & 0x7f) << shift; + shift += 7; + } while ((packet & 0x80) && (shift < 28)); + + /* one last packet holding 4 bits of the address, plus the branch reason code */ + if ((shift == 28) && (packet & 0x80)) + { + if ((retval = etmv1_next_packet(ctx, &packet, 0)) != 0) + return -1; + ctx->last_branch &= 0x0fffffff; + ctx->last_branch |= (packet & 0x0f) << 28; + ctx->last_branch_reason = (packet & 0x70) >> 4; + shift += 4; + } + else + { + ctx->last_branch_reason = 0; + } + + if (shift == 32) + { + ctx->pc_ok = 1; + } + + /* if a full address was output, we might have branched into Jazelle state */ + if ((shift == 32) && (packet & 0x80)) + { + ctx->core_state = ARMV4_5_STATE_JAZELLE; + } + else + { + /* if we didn't branch into Jazelle state, the current processor state is + * encoded in bit 0 of the branch target address */ + if (ctx->last_branch & 0x1) + { + ctx->core_state = ARMV4_5_STATE_THUMB; + ctx->last_branch &= ~0x1; + } + else + { + ctx->core_state = ARMV4_5_STATE_ARM; + ctx->last_branch &= ~0x3; + } + } + + return 0; +} + +int etmv1_data(etm_context_t *ctx, int size, u32 *data) +{ + int j; + u8 buf[4]; + int retval; + + for (j = 0; j < size; j++) + { + if ((retval = etmv1_next_packet(ctx, &buf[j], 0)) != 0) + return -1; + } + + if (size == 8) + ERROR("TODO: add support for 64-bit values"); + else if (size == 4) + *data = target_buffer_get_u32(ctx->target, buf); + else if (size == 2) + *data = target_buffer_get_u16(ctx->target, buf); + else if (size == 1) + *data = buf[0]; + + return 0; +} + +int etmv1_analyze_trace(etm_context_t *ctx, struct command_context_s *cmd_ctx) +{ + int retval; + arm_instruction_t instruction; + + /* read the trace data if it wasn't read already */ + if (ctx->trace_depth == 0) + ctx->capture_driver->read_trace(ctx); + + /* start at the beginning of the captured trace */ + ctx->pipe_index = 0; + ctx->data_index = 0; + ctx->data_half = 0; + + /* neither the PC nor the data pointer are valid */ + ctx->pc_ok = 0; + ctx->ptr_ok = 0; + + while (ctx->pipe_index < ctx->trace_depth) + { + u8 pipestat = ctx->trace_data[ctx->pipe_index].pipestat; + u32 next_pc = ctx->current_pc; + u32 old_data_index = ctx->data_index; + u32 old_data_half = ctx->data_half; + u32 old_index = ctx->pipe_index; + u32 last_instruction = ctx->last_instruction; + u32 cycles = 0; + int current_pc_ok = ctx->pc_ok; + + if (ctx->trace_data[ctx->pipe_index].flags & ETMV1_TRIGGER_CYCLE) + { + command_print(cmd_ctx, "--- trigger ---"); + } + + /* instructions execute in IE/D or BE/D cycles */ + if ((pipestat == STAT_IE) || (pipestat == STAT_ID)) + ctx->last_instruction = ctx->pipe_index; + + /* if we don't have a valid pc skip until we reach an indirect branch */ + if ((!ctx->pc_ok) && (pipestat != STAT_BE)) + { + ctx->pipe_index++; + continue; + } + + /* any indirect branch could have interrupted instruction flow + * - the branch reason code could indicate a trace discontinuity + * - a branch to the exception vectors indicates an exception + */ + if ((pipestat == STAT_BE) || (pipestat == STAT_BD)) + { + /* backup current data index, to be able to consume the branch address + * before examining data address and values + */ + old_data_index = ctx->data_index; + old_data_half = ctx->data_half; + + ctx->last_instruction = ctx->pipe_index; + + if ((retval = etmv1_branch_address(ctx)) != 0) + { + /* negative return value from etmv1_branch_address means we ran out of packets, + * quit analysing the trace */ + if (retval < 0) + break; + + /* a positive return values means the current branch was abandoned, + * and a new branch was encountered in cycle ctx->pipe_index + retval; + */ + WARNING("abandoned branch encountered, correctnes of analysis uncertain"); + ctx->pipe_index += retval; + continue; + } + + /* skip over APO cycles */ + ctx->pipe_index += 2; + + switch (ctx->last_branch_reason) + { + case 0x0: /* normal PC change */ + next_pc = ctx->last_branch; + break; + case 0x1: /* tracing enabled */ + command_print(cmd_ctx, "--- tracing enabled at 0x%8.8x ---", ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + break; + case 0x2: /* trace restarted after FIFO overflow */ + command_print(cmd_ctx, "--- trace restarted after FIFO overflow at 0x%8.8x ---", ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + break; + case 0x3: /* exit from debug state */ + command_print(cmd_ctx, "--- exit from debug state at 0x%8.8x ---", ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + break; + case 0x4: /* periodic synchronization point */ + next_pc = ctx->last_branch; + /* if we had no valid PC prior to this synchronization point, + * we have to move on with the next trace cycle + */ + if (!current_pc_ok) + { + command_print(cmd_ctx, "--- periodic synchronization point at 0x%8.8x ---", next_pc); + ctx->current_pc = next_pc; + ctx->pipe_index++; + continue; + } + break; + default: /* reserved */ + ERROR("BUG: branch reason code 0x%x is reserved", ctx->last_branch_reason); + exit(-1); + break; + } + + /* if we got here the branch was a normal PC change + * (or a periodic synchronization point, which means the same for that matter) + * if we didn't accquire a complete PC continue with the next cycle + */ + if (!ctx->pc_ok) + continue; + + /* indirect branch to the exception vector means an exception occured */ + if (((ctx->last_branch >= 0x0) && (ctx->last_branch <= 0x20)) + || ((ctx->last_branch >= 0xffff0000) && (ctx->last_branch <= 0xffff0020))) + { + if ((ctx->last_branch & 0xff) == 0x10) + { + command_print(cmd_ctx, "data abort"); + } + else + { + command_print(cmd_ctx, "exception vector 0x%2.2x", ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + } + } + } + + /* an instruction was executed (or not, depending on the condition flags) + * retrieve it from the image for displaying */ + if (ctx->pc_ok && (pipestat != STAT_WT) && (pipestat != STAT_TD) && + !(((pipestat == STAT_BE) || (pipestat == STAT_BD)) && + ((ctx->last_branch_reason != 0x0) && (ctx->last_branch_reason != 0x4)))) + { + if ((retval = etm_read_instruction(ctx, &instruction)) != ERROR_OK) + { + /* can't continue tracing with no image available */ + if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE) + { + return retval; + } + else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) + { + /* TODO: handle incomplete images + * for now we just quit the analsysis*/ + return retval; + } + } + + cycles = old_index - last_instruction; + } + + if ((pipestat == STAT_ID) || (pipestat == STAT_BD)) + { + u32 new_data_index = ctx->data_index; + u32 new_data_half = ctx->data_half; + + /* in case of a branch with data, the branch target address was consumed before + * we temporarily go back to the saved data index */ + if (pipestat == STAT_BD) + { + ctx->data_index = old_data_index; + ctx->data_half = old_data_half; + } + + if (ctx->tracemode & ETMV1_TRACE_ADDR) + { + u8 packet; + int shift = 0; + + do { + if ((retval = etmv1_next_packet(ctx, &packet, 0)) != 0) + return ERROR_ETM_ANALYSIS_FAILED; + ctx->last_ptr &= ~(0x7f << shift); + ctx->last_ptr |= (packet & 0x7f) << shift; + shift += 7; + } while ((packet & 0x80) && (shift < 32)); + + if (shift >= 32) + ctx->ptr_ok = 1; + + if (ctx->ptr_ok) + { + command_print(cmd_ctx, "address: 0x%8.8x", ctx->last_ptr); + } + } + + if (ctx->tracemode & ETMV1_TRACE_DATA) + { + if ((instruction.type == ARM_LDM) || (instruction.type == ARM_STM)) + { + int i; + for (i = 0; i < 16; i++) + { + if (instruction.info.load_store_multiple.register_list & (1 << i)) + { + u32 data; + if (etmv1_data(ctx, 4, &data) != 0) + return ERROR_ETM_ANALYSIS_FAILED; + command_print(cmd_ctx, "data: 0x%8.8x", data); + } + } + } + else if ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_STRH)) + { + u32 data; + if (etmv1_data(ctx, arm_access_size(&instruction), &data) != 0) + return ERROR_ETM_ANALYSIS_FAILED; + command_print(cmd_ctx, "data: 0x%8.8x", data); + } + } + + /* restore data index after consuming BD address and data */ + if (pipestat == STAT_BD) + { + ctx->data_index = new_data_index; + ctx->data_half = new_data_half; + } + } + + /* adjust PC */ + if ((pipestat == STAT_IE) || (pipestat == STAT_ID)) + { + if (((instruction.type == ARM_B) || + (instruction.type == ARM_BL) || + (instruction.type == ARM_BLX)) && + (instruction.info.b_bl_bx_blx.target_address != -1)) + { + next_pc = instruction.info.b_bl_bx_blx.target_address; + } + else + { + next_pc += (ctx->core_state == ARMV4_5_STATE_ARM) ? 4 : 2; + } + } + else if (pipestat == STAT_IN) + { + next_pc += (ctx->core_state == ARMV4_5_STATE_ARM) ? 4 : 2; + } + + if ((pipestat != STAT_TD) && (pipestat != STAT_WT)) + { + char cycles_text[32] = ""; + + /* if the trace was captured with cycle accurate tracing enabled, + * output the number of cycles since the last executed instruction + */ + if (ctx->tracemode & ETMV1_CYCLE_ACCURATE) + { + snprintf(cycles_text, 32, " (%i %s)", + cycles, + (cycles == 1) ? "cycle" : "cycles"); + } + + command_print(cmd_ctx, "%s%s%s", + instruction.text, + (pipestat == STAT_IN) ? " (not executed)" : "", + cycles_text); + + ctx->current_pc = next_pc; + + /* packets for an instruction don't start on or before the preceding + * functional pipestat (i.e. other than WT or TD) + */ + if (ctx->data_index <= ctx->pipe_index) + { + ctx->data_index = ctx->pipe_index + 1; + ctx->data_half = 0; + } + } + + ctx->pipe_index += 1; + } + + return ERROR_OK; +} + +int handle_etm_tracemode_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etmv1_tracemode_t tracemode; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!arm7_9->etm_ctx) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + tracemode = arm7_9->etm_ctx->tracemode; + + if (argc == 4) + { + if (strcmp(args[0], "none") == 0) + { + tracemode = ETMV1_TRACE_NONE; + } + else if (strcmp(args[0], "data") == 0) + { + tracemode = ETMV1_TRACE_DATA; + } + else if (strcmp(args[0], "address") == 0) + { + tracemode = ETMV1_TRACE_ADDR; + } + else if (strcmp(args[0], "all") == 0) + { + tracemode = ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR; + } + else + { + command_print(cmd_ctx, "invalid option '%s'", args[0]); + return ERROR_OK; + } + + switch (strtol(args[1], NULL, 0)) + { + case 0: + tracemode |= ETMV1_CONTEXTID_NONE; + break; + case 8: + tracemode |= ETMV1_CONTEXTID_8; + break; + case 16: + tracemode |= ETMV1_CONTEXTID_16; + break; + case 32: + tracemode |= ETMV1_CONTEXTID_32; + break; + default: + command_print(cmd_ctx, "invalid option '%s'", args[1]); + return ERROR_OK; + } + + if (strcmp(args[2], "enable") == 0) + { + tracemode |= ETMV1_CYCLE_ACCURATE; + } + else if (strcmp(args[2], "disable") == 0) + { + tracemode |= 0; + } + else + { + command_print(cmd_ctx, "invalid option '%s'", args[2]); + return ERROR_OK; + } + + if (strcmp(args[3], "enable") == 0) + { + tracemode |= ETMV1_BRANCH_OUTPUT; + } + else if (strcmp(args[3], "disable") == 0) + { + tracemode |= 0; + } + else + { + command_print(cmd_ctx, "invalid option '%s'", args[2]); + return ERROR_OK; + } + } + else if (argc != 0) + { + command_print(cmd_ctx, "usage: configure trace mode <none|data|address|all> <context id bits> <cycle accurate> <branch output>"); + return ERROR_OK; + } + + command_print(cmd_ctx, "current tracemode configuration:"); + + switch (tracemode & ETMV1_TRACE_MASK) + { + case ETMV1_TRACE_NONE: + command_print(cmd_ctx, "data tracing: none"); + break; + case ETMV1_TRACE_DATA: + command_print(cmd_ctx, "data tracing: data only"); + break; + case ETMV1_TRACE_ADDR: + command_print(cmd_ctx, "data tracing: address only"); + break; + case ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR: + command_print(cmd_ctx, "data tracing: address and data"); + break; + } + + switch (tracemode & ETMV1_CONTEXTID_MASK) + { + case ETMV1_CONTEXTID_NONE: + command_print(cmd_ctx, "contextid tracing: none"); + break; + case ETMV1_CONTEXTID_8: + command_print(cmd_ctx, "contextid tracing: 8 bit"); + break; + case ETMV1_CONTEXTID_16: + command_print(cmd_ctx, "contextid tracing: 16 bit"); + break; + case ETMV1_CONTEXTID_32: + command_print(cmd_ctx, "contextid tracing: 32 bit"); + break; + } + + if (tracemode & ETMV1_CYCLE_ACCURATE) + { + command_print(cmd_ctx, "cycle-accurate tracing enabled"); + } + else + { + command_print(cmd_ctx, "cycle-accurate tracing disabled"); + } + + if (tracemode & ETMV1_BRANCH_OUTPUT) + { + command_print(cmd_ctx, "full branch address output enabled"); + } + else + { + command_print(cmd_ctx, "full branch address output disabled"); + } + + /* only update ETM_CTRL register if tracemode changed */ + if (arm7_9->etm_ctx->tracemode != tracemode) + { + reg_t *etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; + + etm_get_reg(etm_ctrl_reg); + + buf_set_u32(etm_ctrl_reg->value, 2, 2, tracemode & ETMV1_TRACE_MASK); + buf_set_u32(etm_ctrl_reg->value, 14, 2, (tracemode & ETMV1_CONTEXTID_MASK) >> 4); + buf_set_u32(etm_ctrl_reg->value, 12, 1, (tracemode & ETMV1_CYCLE_ACCURATE) >> 8); + buf_set_u32(etm_ctrl_reg->value, 8, 1, (tracemode & ETMV1_BRANCH_OUTPUT) >> 9); + etm_store_reg(etm_ctrl_reg); + + arm7_9->etm_ctx->tracemode = tracemode; + + /* invalidate old trace data */ + arm7_9->etm_ctx->capture_status = TRACE_IDLE; + if (arm7_9->etm_ctx->trace_depth > 0) + { + free(arm7_9->etm_ctx->trace_data); + arm7_9->etm_ctx->trace_data = NULL; + } + arm7_9->etm_ctx->trace_depth = 0; + } + + return ERROR_OK; +} + +int handle_etm_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_portmode_t portmode = 0x0; + etm_context_t *etm_ctx = malloc(sizeof(etm_context_t)); + int i; + + if (argc != 5) + { + ERROR("incomplete 'etm config <target> <port_width> <port_mode> <clocking> <capture_driver>' command"); + exit(-1); + } + + target = get_target_by_num(strtoul(args[0], NULL, 0)); + + if (!target) + { + ERROR("target number '%s' not defined", args[0]); + exit(-1); + } + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + switch (strtoul(args[1], NULL, 0)) + { + case 4: + portmode |= ETM_PORT_4BIT; + break; + case 8: + portmode |= ETM_PORT_8BIT; + break; + case 16: + portmode |= ETM_PORT_16BIT; + break; + default: + command_print(cmd_ctx, "unsupported ETM port width '%s', must be 4, 8 or 16", args[1]); + return ERROR_OK; + } + + if (strcmp("normal", args[2]) == 0) + { + portmode |= ETM_PORT_NORMAL; + } + else if (strcmp("multiplexed", args[2]) == 0) + { + portmode |= ETM_PORT_MUXED; + } + else if (strcmp("demultiplexed", args[2]) == 0) + { + portmode |= ETM_PORT_DEMUXED; + } + else + { + command_print(cmd_ctx, "unsupported ETM port mode '%s', must be 'normal', 'multiplexed' or 'demultiplexed'", args[2]); + return ERROR_OK; + } + + if (strcmp("half", args[3]) == 0) + { + portmode |= ETM_PORT_HALF_CLOCK; + } + else if (strcmp("full", args[3]) == 0) + { + portmode |= ETM_PORT_FULL_CLOCK; + } + else + { + command_print(cmd_ctx, "unsupported ETM port clocking '%s', must be 'full' or 'half'", args[3]); + return ERROR_OK; + } + + for (i=0; etm_capture_drivers[i]; i++) + { + if (strcmp(args[4], etm_capture_drivers[i]->name) == 0) + { + if (etm_capture_drivers[i]->register_commands(cmd_ctx) != ERROR_OK) + { + free(etm_ctx); + exit(-1); + } + + etm_ctx->capture_driver = etm_capture_drivers[i]; + + break; + } + } + + if (!etm_capture_drivers[i]) + { + /* no supported capture driver found, don't register an ETM */ + free(etm_ctx); + ERROR("trace capture driver '%s' not found", args[4]); + return ERROR_OK; + } + + etm_ctx->target = target; + etm_ctx->trigger_percent = 50; + etm_ctx->trace_data = NULL; + etm_ctx->trace_depth = 0; + etm_ctx->portmode = portmode; + etm_ctx->tracemode = 0x0; + etm_ctx->core_state = ARMV4_5_STATE_ARM; + etm_ctx->image = NULL; + etm_ctx->pipe_index = 0; + etm_ctx->data_index = 0; + etm_ctx->current_pc = 0x0; + etm_ctx->pc_ok = 0; + etm_ctx->last_branch = 0x0; + etm_ctx->last_branch_reason = 0x0; + etm_ctx->last_ptr = 0x0; + etm_ctx->ptr_ok = 0x0; + etm_ctx->context_id = 0x0; + etm_ctx->last_instruction = 0; + + arm7_9->etm_ctx = etm_ctx; + + etm_register_user_commands(cmd_ctx); + + return ERROR_OK; +} + +int handle_etm_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + reg_t *etm_config_reg; + reg_t *etm_sys_config_reg; + + int max_port_size; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!arm7_9->etm_ctx) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + etm_config_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CONFIG]; + etm_sys_config_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_SYS_CONFIG]; + + etm_get_reg(etm_config_reg); + command_print(cmd_ctx, "pairs of address comparators: %i", buf_get_u32(etm_config_reg->value, 0, 4)); + command_print(cmd_ctx, "pairs of data comparators: %i", buf_get_u32(etm_config_reg->value, 4, 4)); + command_print(cmd_ctx, "memory map decoders: %i", buf_get_u32(etm_config_reg->value, 8, 5)); + command_print(cmd_ctx, "number of counters: %i", buf_get_u32(etm_config_reg->value, 13, 3)); + command_print(cmd_ctx, "sequencer %spresent", + (buf_get_u32(etm_config_reg->value, 16, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "number of ext. inputs: %i", buf_get_u32(etm_config_reg->value, 17, 3)); + command_print(cmd_ctx, "number of ext. outputs: %i", buf_get_u32(etm_config_reg->value, 20, 3)); + command_print(cmd_ctx, "FIFO full %spresent", + (buf_get_u32(etm_config_reg->value, 23, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "protocol version: %i", buf_get_u32(etm_config_reg->value, 28, 3)); + + etm_get_reg(etm_sys_config_reg); + + switch (buf_get_u32(etm_sys_config_reg->value, 0, 3)) + { + case 0: + max_port_size = 4; + break; + case 1: + max_port_size = 8; + break; + case 2: + max_port_size = 16; + break; + } + command_print(cmd_ctx, "max. port size: %i", max_port_size); + + command_print(cmd_ctx, "half-rate clocking %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 3, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "full-rate clocking %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 4, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "normal trace format %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 5, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "multiplex trace format %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 6, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "demultiplex trace format %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 7, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "FIFO full %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 8, 1) == 1) ? "" : "not "); + + return ERROR_OK; +} + +int handle_etm_status_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + trace_status_t trace_status; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!arm7_9->etm_ctx) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + trace_status = arm7_9->etm_ctx->capture_driver->status(arm7_9->etm_ctx); + + if (trace_status == TRACE_IDLE) + { + command_print(cmd_ctx, "tracing is idle"); + } + else + { + static char *completed = " completed"; + static char *running = " is running"; + static char *overflowed = ", trace overflowed"; + static char *triggered = ", trace triggered"; + + command_print(cmd_ctx, "trace collection%s%s%s", + (trace_status & TRACE_RUNNING) ? running : completed, + (trace_status & TRACE_OVERFLOWED) ? overflowed : "", + (trace_status & TRACE_TRIGGERED) ? triggered : ""); + + if (arm7_9->etm_ctx->trace_depth > 0) + { + command_print(cmd_ctx, "%i frames of trace data read", arm7_9->etm_ctx->trace_depth); + } + } + + return ERROR_OK; +} + +int handle_etm_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + + if (argc < 1) + { + command_print(cmd_ctx, "usage: etm image <file> [base address] [type]"); + return ERROR_OK; + } + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if (etm_ctx->image) + { + image_close(etm_ctx->image); + free(etm_ctx->image); + command_print(cmd_ctx, "previously loaded image found and closed"); + } + + etm_ctx->image = malloc(sizeof(image_t)); + etm_ctx->image->base_address_set = 0; + etm_ctx->image->start_address_set = 0; + + /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ + if (argc >= 2) + { + etm_ctx->image->base_address_set = 1; + etm_ctx->image->base_address = strtoul(args[1], NULL, 0); + } + else + { + etm_ctx->image->base_address_set = 0; + } + + if (image_open(etm_ctx->image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK) + { + command_print(cmd_ctx, "image opening error: %s", etm_ctx->image->error_str); + free(etm_ctx->image); + etm_ctx->image = NULL; + return ERROR_OK; + } + + return ERROR_OK; +} + +int handle_etm_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + fileio_t file; + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + int i; + + if (argc != 1) + { + command_print(cmd_ctx, "usage: etm dump <file>"); + return ERROR_OK; + } + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if (etm_ctx->capture_driver->status == TRACE_IDLE) + { + command_print(cmd_ctx, "trace capture wasn't enabled, no trace data captured"); + return ERROR_OK; + } + + if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING) + { + /* TODO: if on-the-fly capture is to be supported, this needs to be changed */ + command_print(cmd_ctx, "trace capture not completed"); + return ERROR_OK; + } + + /* read the trace data if it wasn't read already */ + if (etm_ctx->trace_depth == 0) + etm_ctx->capture_driver->read_trace(etm_ctx); + + if (fileio_open(&file, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) + { + command_print(cmd_ctx, "file open error: %s", file.error_str); + return ERROR_OK; + } + + fileio_write_u32(&file, etm_ctx->capture_status); + fileio_write_u32(&file, etm_ctx->portmode); + fileio_write_u32(&file, etm_ctx->tracemode); + fileio_write_u32(&file, etm_ctx->trace_depth); + + for (i = 0; i < etm_ctx->trace_depth; i++) + { + fileio_write_u32(&file, etm_ctx->trace_data[i].pipestat); + fileio_write_u32(&file, etm_ctx->trace_data[i].packet); + fileio_write_u32(&file, etm_ctx->trace_data[i].flags); + } + + fileio_close(&file); + + return ERROR_OK; +} + +int handle_etm_load_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + fileio_t file; + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + int i; + + if (argc != 1) + { + command_print(cmd_ctx, "usage: etm load <file>"); + return ERROR_OK; + } + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING) + { + command_print(cmd_ctx, "trace capture running, stop first"); + return ERROR_OK; + } + + if (fileio_open(&file, args[0], FILEIO_READ, FILEIO_BINARY) != ERROR_OK) + { + command_print(cmd_ctx, "file open error: %s", file.error_str); + return ERROR_OK; + } + + if (file.size % 4) + { + command_print(cmd_ctx, "size isn't a multiple of 4, no valid trace data"); + return ERROR_OK; + } + + if (etm_ctx->trace_depth > 0) + { + free(etm_ctx->trace_data); + } + + fileio_read_u32(&file, &etm_ctx->capture_status); + fileio_read_u32(&file, &etm_ctx->portmode); + fileio_read_u32(&file, &etm_ctx->tracemode); + fileio_read_u32(&file, &etm_ctx->trace_depth); + + etm_ctx->trace_data = malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth); + + for (i = 0; i < etm_ctx->trace_depth; i++) + { + u32 pipestat, packet, flags; + fileio_read_u32(&file, &pipestat); + fileio_read_u32(&file, &packet); + fileio_read_u32(&file, &flags); + etm_ctx->trace_data[i].pipestat = pipestat & 0xff; + etm_ctx->trace_data[i].packet = packet & 0xffff; + etm_ctx->trace_data[i].flags = flags; + } + + fileio_close(&file); + + return ERROR_OK; +} + +int handle_etm_trigger_percent_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if (argc > 0) + { + u32 new_value = strtoul(args[0], NULL, 0); + + if ((new_value < 2) || (new_value > 100)) + { + command_print(cmd_ctx, "valid settings are 2% to 100%"); + } + else + { + etm_ctx->trigger_percent = new_value; + } + } + + command_print(cmd_ctx, "%i percent of the tracebuffer reserved for after the trigger", etm_ctx->trigger_percent); + + return ERROR_OK; +} + +int handle_etm_start_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + reg_t *etm_ctrl_reg; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + /* invalidate old tracing data */ + arm7_9->etm_ctx->capture_status = TRACE_IDLE; + if (arm7_9->etm_ctx->trace_depth > 0) + { + free(arm7_9->etm_ctx->trace_data); + arm7_9->etm_ctx->trace_data = NULL; + } + arm7_9->etm_ctx->trace_depth = 0; + + etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; + etm_get_reg(etm_ctrl_reg); + + /* Clear programming bit (10), set port selection bit (11) */ + buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x2); + + etm_store_reg(etm_ctrl_reg); + jtag_execute_queue(); + + etm_ctx->capture_driver->start_capture(etm_ctx); + + return ERROR_OK; +} + +int handle_etm_stop_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + reg_t *etm_ctrl_reg; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; + etm_get_reg(etm_ctrl_reg); + + /* Set programming bit (10), clear port selection bit (11) */ + buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x1); + + etm_store_reg(etm_ctrl_reg); + jtag_execute_queue(); + + etm_ctx->capture_driver->stop_capture(etm_ctx); + + return ERROR_OK; +} + +int handle_etm_analyze_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + int retval; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if ((retval = etmv1_analyze_trace(etm_ctx, cmd_ctx)) != ERROR_OK) + { + switch(retval) + { + case ERROR_ETM_ANALYSIS_FAILED: + command_print(cmd_ctx, "further analysis failed (corrupted trace data or just end of data"); + break; + case ERROR_TRACE_INSTRUCTION_UNAVAILABLE: + command_print(cmd_ctx, "no instruction for current address available, analysis aborted"); + break; + case ERROR_TRACE_IMAGE_UNAVAILABLE: + command_print(cmd_ctx, "no image available for trace analysis"); + break; + default: + command_print(cmd_ctx, "unknown error: %i", retval); + } + } + + return ERROR_OK; +} + +int etm_register_commands(struct command_context_s *cmd_ctx) +{ + etm_cmd = register_command(cmd_ctx, NULL, "etm", NULL, COMMAND_ANY, "Embedded Trace Macrocell"); + + register_command(cmd_ctx, etm_cmd, "config", handle_etm_config_command, COMMAND_CONFIG, NULL); + + return ERROR_OK; +} + +int etm_register_user_commands(struct command_context_s *cmd_ctx) +{ + register_command(cmd_ctx, etm_cmd, "tracemode", handle_etm_tracemode_command, + COMMAND_EXEC, "configure trace mode <none|data|address|all> <context id bits> <cycle accurate> <branch output"); + + register_command(cmd_ctx, etm_cmd, "info", handle_etm_info_command, + COMMAND_EXEC, "display info about the current target's ETM"); + + register_command(cmd_ctx, etm_cmd, "trigger_percent <percent>", handle_etm_trigger_percent_command, + COMMAND_EXEC, "amount (<percent>) of trace buffer to be filled after the trigger occured"); + register_command(cmd_ctx, etm_cmd, "status", handle_etm_status_command, + COMMAND_EXEC, "display current target's ETM status"); + register_command(cmd_ctx, etm_cmd, "start", handle_etm_start_command, + COMMAND_EXEC, "start ETM trace collection"); + register_command(cmd_ctx, etm_cmd, "stop", handle_etm_stop_command, + COMMAND_EXEC, "stop ETM trace collection"); + + register_command(cmd_ctx, etm_cmd, "analyze", handle_etm_analyze_command, + COMMAND_EXEC, "anaylze collected ETM trace"); + + register_command(cmd_ctx, etm_cmd, "image", handle_etm_image_command, + COMMAND_EXEC, "load image from <file> [base address]"); + + register_command(cmd_ctx, etm_cmd, "dump", handle_etm_dump_command, + COMMAND_EXEC, "dump captured trace data <file>"); + register_command(cmd_ctx, etm_cmd, "load", handle_etm_load_command, + COMMAND_EXEC, "load trace data for analysis <file>"); + + return ERROR_OK; +} diff --git a/src/target/etm.h b/src/target/etm.h index bfa1252..da47ff1 100644 --- a/src/target/etm.h +++ b/src/target/etm.h @@ -1,214 +1,214 @@ -/***************************************************************************
- * Copyright (C) 2005, 2007 by Dominic Rath *
- * Dominic.Rath@gmx.de *
- * *
- * Copyright (C) 2007 by Vincent Palatin *
- * vincent.palatin_openocd@m4x.org *
- * *
- * 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 ETM_H
-#define ETM_H
-
-#include "image.h"
-#include "trace.h"
-#include "target.h"
-#include "register.h"
-#include "arm_jtag.h"
-
-#include "armv4_5.h"
-
-/* ETM registers (V1.3 protocol) */
-enum
-{
- ETM_CTRL = 0x00,
- ETM_CONFIG = 0x01,
- ETM_TRIG_EVENT = 0x02,
- ETM_MMD_CTRL = 0x03,
- ETM_STATUS = 0x04,
- ETM_SYS_CONFIG = 0x05,
- ETM_TRACE_RESOURCE_CTRL = 0x06,
- ETM_TRACE_EN_CTRL2 = 0x07,
- ETM_TRACE_EN_EVENT = 0x08,
- ETM_TRACE_EN_CTRL1 = 0x09,
- ETM_FIFOFULL_REGION = 0x0a,
- ETM_FIFOFULL_LEVEL = 0x0b,
- ETM_VIEWDATA_EVENT = 0x0c,
- ETM_VIEWDATA_CTRL1 = 0x0d,
- ETM_VIEWDATA_CTRL2 = 0x0e,
- ETM_VIEWDATA_CTRL3 = 0x0f,
- ETM_ADDR_COMPARATOR_VALUE = 0x10,
- ETM_ADDR_ACCESS_TYPE = 0x20,
- ETM_DATA_COMPARATOR_VALUE = 0x30,
- ETM_DATA_COMPARATOR_MASK = 0x40,
- ETM_COUNTER_INITAL_VALUE = 0x50,
- ETM_COUNTER_ENABLE = 0x54,
- ETM_COUNTER_RELOAD_VALUE = 0x58,
- ETM_COUNTER_VALUE = 0x5c,
- ETM_SEQUENCER_CTRL = 0x60,
- ETM_SEQUENCER_STATE = 0x67,
- ETM_EXTERNAL_OUTPUT = 0x68,
- ETM_CONTEXTID_COMPARATOR_VALUE = 0x6c,
- ETM_CONTEXTID_COMPARATOR_MASK = 0x6f,
-};
-
-typedef struct etm_reg_s
-{
- int addr;
- arm_jtag_t *jtag_info;
-} etm_reg_t;
-
-typedef enum
-{
- /* Port width */
- ETM_PORT_4BIT = 0x00,
- ETM_PORT_8BIT = 0x10,
- ETM_PORT_16BIT = 0x20,
- ETM_PORT_WIDTH_MASK = 0x70,
- /* Port modes */
- ETM_PORT_NORMAL = 0x00000,
- ETM_PORT_MUXED = 0x10000,
- ETM_PORT_DEMUXED = 0x20000,
- ETM_PORT_MODE_MASK = 0x30000,
- /* Clocking modes */
- ETM_PORT_FULL_CLOCK = 0x0000,
- ETM_PORT_HALF_CLOCK = 0x1000,
- ETM_PORT_CLOCK_MASK = 0x1000,
-} etm_portmode_t;
-
-typedef enum
-{
- /* Data trace */
- ETMV1_TRACE_NONE = 0x00,
- ETMV1_TRACE_DATA = 0x01,
- ETMV1_TRACE_ADDR = 0x02,
- ETMV1_TRACE_MASK = 0x03,
- /* ContextID */
- ETMV1_CONTEXTID_NONE = 0x00,
- ETMV1_CONTEXTID_8 = 0x10,
- ETMV1_CONTEXTID_16 = 0x20,
- ETMV1_CONTEXTID_32 = 0x30,
- ETMV1_CONTEXTID_MASK = 0x30,
- /* Misc */
- ETMV1_CYCLE_ACCURATE = 0x100,
- ETMV1_BRANCH_OUTPUT = 0x200
-} etmv1_tracemode_t;
-
-/* forward-declare ETM context */
-struct etm_context_s;
-
-typedef struct etm_capture_driver_s
-{
- char *name;
- int (*register_commands)(struct command_context_s *cmd_ctx);
- int (*init)(struct etm_context_s *etm_ctx);
- trace_status_t (*status)(struct etm_context_s *etm_ctx);
- int (*read_trace)(struct etm_context_s *etm_ctx);
- int (*start_capture)(struct etm_context_s *etm_ctx);
- int (*stop_capture)(struct etm_context_s *etm_ctx);
-} etm_capture_driver_t;
-
-enum
-{
- ETMV1_TRACESYNC_CYCLE = 0x1,
- ETMV1_TRIGGER_CYCLE = 0x2,
-};
-
-typedef struct etmv1_trace_data_s
-{
- u8 pipestat; /* bits 0-2 pipeline status */
- u16 packet; /* packet data (4, 8 or 16 bit) */
- int flags; /* ETMV1_TRACESYNC_CYCLE, ETMV1_TRIGGER_CYCLE */
-} etmv1_trace_data_t;
-
-/* describe a trace context
- * if support for ETMv2 or ETMv3 is to be implemented,
- * this will have to be split into version independent elements
- * and a version specific part
- */
-typedef struct etm_context_s
-{
- target_t *target; /* target this ETM is connected to */
- reg_cache_t *reg_cache; /* ETM register cache */
- etm_capture_driver_t *capture_driver; /* driver used to access ETM data */
- void *capture_driver_priv; /* capture driver private data */
- u32 trigger_percent; /* percent of trace buffer to be filled after the trigger */
- trace_status_t capture_status; /* current state of capture run */
- etmv1_trace_data_t *trace_data; /* trace data */
- u32 trace_depth; /* number of trace cycles to be analyzed, 0 if no trace data available */
- etm_portmode_t portmode; /* normal, multiplexed or demultiplexed */
- etmv1_tracemode_t tracemode; /* type of information the trace contains (data, addres, contextID, ...) */
- armv4_5_state_t core_state; /* current core state (ARM, Thumb, Jazelle) */
- image_t *image; /* source for target opcodes */
- u32 pipe_index; /* current trace cycle */
- u32 data_index; /* cycle holding next data packet */
- int data_half; /* port half on a 16 bit port */
- u32 current_pc; /* current program counter */
- u32 pc_ok; /* full PC has been acquired */
- u32 last_branch; /* last branch address output */
- u32 last_branch_reason; /* branch reason code for the last branch encountered */
- u32 last_ptr; /* address of the last data access */
- u32 ptr_ok; /* whether last_ptr is valid */
- u32 context_id; /* context ID of the code being traced */
- u32 last_instruction; /* index of last instruction executed (to calculate cycle timings) */
-} etm_context_t;
-
-/* PIPESTAT values */
-typedef enum
-{
- STAT_IE = 0x0,
- STAT_ID = 0x1,
- STAT_IN = 0x2,
- STAT_WT = 0x3,
- STAT_BE = 0x4,
- STAT_BD = 0x5,
- STAT_TR = 0x6,
- STAT_TD = 0x7
-} etmv1_pipestat_t;
-
-/* branch reason values */
-typedef enum
-{
- BR_NORMAL = 0x0, /* Normal PC change : periodic synchro (ETMv1.1) */
- BR_ENABLE = 0x1, /* Trace has been enabled */
- BR_RESTART = 0x2, /* Trace restarted after a FIFO overflow */
- BR_NODEBUG = 0x3, /* ARM has exited for debug state */
- BR_PERIOD = 0x4, /* Peridioc synchronization point (ETM>=v1.2)*/
- BR_RSVD5 = 0x5, /* reserved */
- BR_RSVD6 = 0x6, /* reserved */
- BR_RSVD7 = 0x7, /* reserved */
-} etmv1_branch_reason_t;
-
-extern char *etmv1v1_branch_reason_strings[];
-
-extern reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_context_t *etm_ctx);
-extern int etm_read_reg(reg_t *reg);
-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);
-extern int etm_store_reg(reg_t *reg);
-extern int etm_set_reg(reg_t *reg, u32 value);
-extern int etm_set_reg_w_exec(reg_t *reg, u8 *buf);
-
-int etm_register_commands(struct command_context_s *cmd_ctx);
-int etm_register_user_commands(struct command_context_s *cmd_ctx);
-extern etm_context_t* etm_create_context(etm_portmode_t portmode, char *capture_driver_name);
-
-#define ERROR_ETM_INVALID_DRIVER (-1300)
-#define ERROR_ETM_PORTMODE_NOT_SUPPORTED (-1301)
-#define ERROR_ETM_CAPTURE_INIT_FAILED (-1302)
-#define ERROR_ETM_ANALYSIS_FAILED (-1303)
-
-#endif /* ETM_H */
+/*************************************************************************** + * Copyright (C) 2005, 2007 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * Copyright (C) 2007 by Vincent Palatin * + * vincent.palatin_openocd@m4x.org * + * * + * 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 ETM_H +#define ETM_H + +#include "image.h" +#include "trace.h" +#include "target.h" +#include "register.h" +#include "arm_jtag.h" + +#include "armv4_5.h" + +/* ETM registers (V1.3 protocol) */ +enum +{ + ETM_CTRL = 0x00, + ETM_CONFIG = 0x01, + ETM_TRIG_EVENT = 0x02, + ETM_MMD_CTRL = 0x03, + ETM_STATUS = 0x04, + ETM_SYS_CONFIG = 0x05, + ETM_TRACE_RESOURCE_CTRL = 0x06, + ETM_TRACE_EN_CTRL2 = 0x07, + ETM_TRACE_EN_EVENT = 0x08, + ETM_TRACE_EN_CTRL1 = 0x09, + ETM_FIFOFULL_REGION = 0x0a, + ETM_FIFOFULL_LEVEL = 0x0b, + ETM_VIEWDATA_EVENT = 0x0c, + ETM_VIEWDATA_CTRL1 = 0x0d, + ETM_VIEWDATA_CTRL2 = 0x0e, + ETM_VIEWDATA_CTRL3 = 0x0f, + ETM_ADDR_COMPARATOR_VALUE = 0x10, + ETM_ADDR_ACCESS_TYPE = 0x20, + ETM_DATA_COMPARATOR_VALUE = 0x30, + ETM_DATA_COMPARATOR_MASK = 0x40, + ETM_COUNTER_INITAL_VALUE = 0x50, + ETM_COUNTER_ENABLE = 0x54, + ETM_COUNTER_RELOAD_VALUE = 0x58, + ETM_COUNTER_VALUE = 0x5c, + ETM_SEQUENCER_CTRL = 0x60, + ETM_SEQUENCER_STATE = 0x67, + ETM_EXTERNAL_OUTPUT = 0x68, + ETM_CONTEXTID_COMPARATOR_VALUE = 0x6c, + ETM_CONTEXTID_COMPARATOR_MASK = 0x6f, +}; + +typedef struct etm_reg_s +{ + int addr; + arm_jtag_t *jtag_info; +} etm_reg_t; + +typedef enum +{ + /* Port width */ + ETM_PORT_4BIT = 0x00, + ETM_PORT_8BIT = 0x10, + ETM_PORT_16BIT = 0x20, + ETM_PORT_WIDTH_MASK = 0x70, + /* Port modes */ + ETM_PORT_NORMAL = 0x00000, + ETM_PORT_MUXED = 0x10000, + ETM_PORT_DEMUXED = 0x20000, + ETM_PORT_MODE_MASK = 0x30000, + /* Clocking modes */ + ETM_PORT_FULL_CLOCK = 0x0000, + ETM_PORT_HALF_CLOCK = 0x1000, + ETM_PORT_CLOCK_MASK = 0x1000, +} etm_portmode_t; + +typedef enum +{ + /* Data trace */ + ETMV1_TRACE_NONE = 0x00, + ETMV1_TRACE_DATA = 0x01, + ETMV1_TRACE_ADDR = 0x02, + ETMV1_TRACE_MASK = 0x03, + /* ContextID */ + ETMV1_CONTEXTID_NONE = 0x00, + ETMV1_CONTEXTID_8 = 0x10, + ETMV1_CONTEXTID_16 = 0x20, + ETMV1_CONTEXTID_32 = 0x30, + ETMV1_CONTEXTID_MASK = 0x30, + /* Misc */ + ETMV1_CYCLE_ACCURATE = 0x100, + ETMV1_BRANCH_OUTPUT = 0x200 +} etmv1_tracemode_t; + +/* forward-declare ETM context */ +struct etm_context_s; + +typedef struct etm_capture_driver_s +{ + char *name; + int (*register_commands)(struct command_context_s *cmd_ctx); + int (*init)(struct etm_context_s *etm_ctx); + trace_status_t (*status)(struct etm_context_s *etm_ctx); + int (*read_trace)(struct etm_context_s *etm_ctx); + int (*start_capture)(struct etm_context_s *etm_ctx); + int (*stop_capture)(struct etm_context_s *etm_ctx); +} etm_capture_driver_t; + +enum +{ + ETMV1_TRACESYNC_CYCLE = 0x1, + ETMV1_TRIGGER_CYCLE = 0x2, +}; + +typedef struct etmv1_trace_data_s +{ + u8 pipestat; /* bits 0-2 pipeline status */ + u16 packet; /* packet data (4, 8 or 16 bit) */ + int flags; /* ETMV1_TRACESYNC_CYCLE, ETMV1_TRIGGER_CYCLE */ +} etmv1_trace_data_t; + +/* describe a trace context + * if support for ETMv2 or ETMv3 is to be implemented, + * this will have to be split into version independent elements + * and a version specific part + */ +typedef struct etm_context_s +{ + target_t *target; /* target this ETM is connected to */ + reg_cache_t *reg_cache; /* ETM register cache */ + etm_capture_driver_t *capture_driver; /* driver used to access ETM data */ + void *capture_driver_priv; /* capture driver private data */ + u32 trigger_percent; /* percent of trace buffer to be filled after the trigger */ + trace_status_t capture_status; /* current state of capture run */ + etmv1_trace_data_t *trace_data; /* trace data */ + u32 trace_depth; /* number of trace cycles to be analyzed, 0 if no trace data available */ + etm_portmode_t portmode; /* normal, multiplexed or demultiplexed */ + etmv1_tracemode_t tracemode; /* type of information the trace contains (data, addres, contextID, ...) */ + armv4_5_state_t core_state; /* current core state (ARM, Thumb, Jazelle) */ + image_t *image; /* source for target opcodes */ + u32 pipe_index; /* current trace cycle */ + u32 data_index; /* cycle holding next data packet */ + int data_half; /* port half on a 16 bit port */ + u32 current_pc; /* current program counter */ + u32 pc_ok; /* full PC has been acquired */ + u32 last_branch; /* last branch address output */ + u32 last_branch_reason; /* branch reason code for the last branch encountered */ + u32 last_ptr; /* address of the last data access */ + u32 ptr_ok; /* whether last_ptr is valid */ + u32 context_id; /* context ID of the code being traced */ + u32 last_instruction; /* index of last instruction executed (to calculate cycle timings) */ +} etm_context_t; + +/* PIPESTAT values */ +typedef enum +{ + STAT_IE = 0x0, + STAT_ID = 0x1, + STAT_IN = 0x2, + STAT_WT = 0x3, + STAT_BE = 0x4, + STAT_BD = 0x5, + STAT_TR = 0x6, + STAT_TD = 0x7 +} etmv1_pipestat_t; + +/* branch reason values */ +typedef enum +{ + BR_NORMAL = 0x0, /* Normal PC change : periodic synchro (ETMv1.1) */ + BR_ENABLE = 0x1, /* Trace has been enabled */ + BR_RESTART = 0x2, /* Trace restarted after a FIFO overflow */ + BR_NODEBUG = 0x3, /* ARM has exited for debug state */ + BR_PERIOD = 0x4, /* Peridioc synchronization point (ETM>=v1.2)*/ + BR_RSVD5 = 0x5, /* reserved */ + BR_RSVD6 = 0x6, /* reserved */ + BR_RSVD7 = 0x7, /* reserved */ +} etmv1_branch_reason_t; + +extern char *etmv1v1_branch_reason_strings[]; + +extern reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_context_t *etm_ctx); +extern int etm_read_reg(reg_t *reg); +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); +extern int etm_store_reg(reg_t *reg); +extern int etm_set_reg(reg_t *reg, u32 value); +extern int etm_set_reg_w_exec(reg_t *reg, u8 *buf); + +int etm_register_commands(struct command_context_s *cmd_ctx); +int etm_register_user_commands(struct command_context_s *cmd_ctx); +extern etm_context_t* etm_create_context(etm_portmode_t portmode, char *capture_driver_name); + +#define ERROR_ETM_INVALID_DRIVER (-1300) +#define ERROR_ETM_PORTMODE_NOT_SUPPORTED (-1301) +#define ERROR_ETM_CAPTURE_INIT_FAILED (-1302) +#define ERROR_ETM_ANALYSIS_FAILED (-1303) + +#endif /* ETM_H */ diff --git a/src/target/etm_dummy.h b/src/target/etm_dummy.h index 31afeff..006db01 100644 --- a/src/target/etm_dummy.h +++ b/src/target/etm_dummy.h @@ -1,33 +1,33 @@ -/***************************************************************************
- * Copyright (C) 2007 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 ETM_DUMMY_H
-#define ETM_DUMMY_H
-
-#include "command.h"
-#include "target.h"
-#include "register.h"
-#include "arm_jtag.h"
-
-#include "etm.h"
-
-extern etm_capture_driver_t etm_dummy_capture_driver;
-extern int etm_dummy_register_commands(struct command_context_s *cmd_ctx);
-
-#endif /* ETB_H */
+/*************************************************************************** + * Copyright (C) 2007 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 ETM_DUMMY_H +#define ETM_DUMMY_H + +#include "command.h" +#include "target.h" +#include "register.h" +#include "arm_jtag.h" + +#include "etm.h" + +extern etm_capture_driver_t etm_dummy_capture_driver; +extern int etm_dummy_register_commands(struct command_context_s *cmd_ctx); + +#endif /* ETB_H */ diff --git a/src/target/oocd_trace.h b/src/target/oocd_trace.h index c80a7ce..77e985f 100644 --- a/src/target/oocd_trace.h +++ b/src/target/oocd_trace.h @@ -1,64 +1,64 @@ -/***************************************************************************
- * Copyright (C) 2007 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 OOCD_TRACE_H
-#define OOCD_TRACE_H
-
-#include "command.h"
-
-#include "etm.h"
-
-#include <termios.h>
-#include <unistd.h>
-
-/* registers */
-enum
-{
- OOCD_TRACE_ID = 0x7,
- OOCD_TRACE_ADDRESS = 0x0,
- OOCD_TRACE_TRIGGER_COUNTER = 0x01,
- OOCD_TRACE_CONTROL = 0x2,
- OOCD_TRACE_STATUS = 0x3,
- OOCD_TRACE_SDRAM_COUNTER = 0x4,
-};
-
-/* commands */
-enum
-{
- OOCD_TRACE_NOP = 0x0,
- OOCD_TRACE_READ_REG = 0x10,
- OOCD_TRACE_WRITE_REG = 0x18,
- OOCD_TRACE_READ_RAM = 0x20,
-/* OOCD_TRACE_WRITE_RAM = 0x28, */
- OOCD_TRACE_RESYNC = 0xf0,
-};
-
-typedef struct oocd_trace_s
-{
- etm_context_t *etm_ctx;
- char *tty;
- int tty_fd;
- struct termios oldtio, newtio;
-} oocd_trace_t;
-
-extern etm_capture_driver_t oocd_trace_capture_driver;
-
-extern int oocd_trace_register_commands(struct command_context_s *cmd_ctx);
-
-#endif /* OOCD_TRACE_TRACE_H */
+/*************************************************************************** + * Copyright (C) 2007 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 OOCD_TRACE_H +#define OOCD_TRACE_H + +#include "command.h" + +#include "etm.h" + +#include <termios.h> +#include <unistd.h> + +/* registers */ +enum +{ + OOCD_TRACE_ID = 0x7, + OOCD_TRACE_ADDRESS = 0x0, + OOCD_TRACE_TRIGGER_COUNTER = 0x01, + OOCD_TRACE_CONTROL = 0x2, + OOCD_TRACE_STATUS = 0x3, + OOCD_TRACE_SDRAM_COUNTER = 0x4, +}; + +/* commands */ +enum +{ + OOCD_TRACE_NOP = 0x0, + OOCD_TRACE_READ_REG = 0x10, + OOCD_TRACE_WRITE_REG = 0x18, + OOCD_TRACE_READ_RAM = 0x20, +/* OOCD_TRACE_WRITE_RAM = 0x28, */ + OOCD_TRACE_RESYNC = 0xf0, +}; + +typedef struct oocd_trace_s +{ + etm_context_t *etm_ctx; + char *tty; + int tty_fd; + struct termios oldtio, newtio; +} oocd_trace_t; + +extern etm_capture_driver_t oocd_trace_capture_driver; + +extern int oocd_trace_register_commands(struct command_context_s *cmd_ctx); + +#endif /* OOCD_TRACE_TRACE_H */ diff --git a/src/target/target.c b/src/target/target.c index a9f7c10..27df12f 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1,2332 +1,2332 @@ -/***************************************************************************
- * 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 "target.h"
-#include "target_request.h"
-
-#include "log.h"
-#include "configuration.h"
-#include "binarybuffer.h"
-#include "jtag.h"
-
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include <sys/time.h>
-#include <time.h>
-
-#include <time_support.h>
-
-#include <fileio.h>
-#include <image.h>
-
-int cli_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv);
-
-
-int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-int handle_target_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_run_and_halt_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_soft_reset_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_step_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_verify_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_bp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_rbp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_rwp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc);
-
-/* targets
- */
-extern target_type_t arm7tdmi_target;
-extern target_type_t arm720t_target;
-extern target_type_t arm9tdmi_target;
-extern target_type_t arm920t_target;
-extern target_type_t arm966e_target;
-extern target_type_t arm926ejs_target;
-extern target_type_t feroceon_target;
-extern target_type_t xscale_target;
-extern target_type_t cortexm3_target;
-
-target_type_t *target_types[] =
-{
- &arm7tdmi_target,
- &arm9tdmi_target,
- &arm920t_target,
- &arm720t_target,
- &arm966e_target,
- &arm926ejs_target,
- &feroceon_target,
- &xscale_target,
- &cortexm3_target,
- NULL,
-};
-
-target_t *targets = NULL;
-target_event_callback_t *target_event_callbacks = NULL;
-target_timer_callback_t *target_timer_callbacks = NULL;
-
-char *target_state_strings[] =
-{
- "unknown",
- "running",
- "halted",
- "reset",
- "debug_running",
-};
-
-char *target_debug_reason_strings[] =
-{
- "debug request", "breakpoint", "watchpoint",
- "watchpoint and breakpoint", "single step",
- "target not halted"
-};
-
-char *target_endianess_strings[] =
-{
- "big endian",
- "little endian",
-};
-
-enum daemon_startup_mode startup_mode = DAEMON_ATTACH;
-
-static int target_continous_poll = 1;
-
-/* read a u32 from a buffer in target memory endianness */
-u32 target_buffer_get_u32(target_t *target, u8 *buffer)
-{
- if (target->endianness == TARGET_LITTLE_ENDIAN)
- return le_to_h_u32(buffer);
- else
- return be_to_h_u32(buffer);
-}
-
-/* read a u16 from a buffer in target memory endianness */
-u16 target_buffer_get_u16(target_t *target, u8 *buffer)
-{
- if (target->endianness == TARGET_LITTLE_ENDIAN)
- return le_to_h_u16(buffer);
- else
- return be_to_h_u16(buffer);
-}
-
-/* write a u32 to a buffer in target memory endianness */
-void target_buffer_set_u32(target_t *target, u8 *buffer, u32 value)
-{
- if (target->endianness == TARGET_LITTLE_ENDIAN)
- h_u32_to_le(buffer, value);
- else
- h_u32_to_be(buffer, value);
-}
-
-/* write a u16 to a buffer in target memory endianness */
-void target_buffer_set_u16(target_t *target, u8 *buffer, u16 value)
-{
- if (target->endianness == TARGET_LITTLE_ENDIAN)
- h_u16_to_le(buffer, value);
- else
- h_u16_to_be(buffer, value);
-}
-
-/* returns a pointer to the n-th configured target */
-target_t* get_target_by_num(int num)
-{
- target_t *target = targets;
- int i = 0;
-
- while (target)
- {
- if (num == i)
- return target;
- target = target->next;
- i++;
- }
-
- return NULL;
-}
-
-int get_num_by_target(target_t *query_target)
-{
- target_t *target = targets;
- int i = 0;
-
- while (target)
- {
- if (target == query_target)
- return i;
- target = target->next;
- i++;
- }
-
- return -1;
-}
-
-target_t* get_current_target(command_context_t *cmd_ctx)
-{
- target_t *target = get_target_by_num(cmd_ctx->current_target);
-
- if (target == NULL)
- {
- ERROR("BUG: current_target out of bounds");
- exit(-1);
- }
-
- return target;
-}
-
-/* Process target initialization, when target entered debug out of reset
- * the handler is unregistered at the end of this function, so it's only called once
- */
-int target_init_handler(struct target_s *target, enum target_event event, void *priv)
-{
- FILE *script;
- struct command_context_s *cmd_ctx = priv;
-
- if ((event == TARGET_EVENT_HALTED) && (target->reset_script))
- {
- target_unregister_event_callback(target_init_handler, priv);
-
- script = open_file_from_path(cmd_ctx, target->reset_script, "r");
- if (!script)
- {
- ERROR("couldn't open script file %s", target->reset_script);
- return ERROR_OK;
- }
-
- INFO("executing reset script '%s'", target->reset_script);
- command_run_file(cmd_ctx, script, COMMAND_EXEC);
- fclose(script);
-
- jtag_execute_queue();
- }
-
- return ERROR_OK;
-}
-
-int target_run_and_halt_handler(void *priv)
-{
- target_t *target = priv;
-
- target->type->halt(target);
-
- return ERROR_OK;
-}
-
-int target_process_reset(struct command_context_s *cmd_ctx)
-{
- int retval = ERROR_OK;
- target_t *target;
- struct timeval timeout, now;
-
- /* prepare reset_halt where necessary */
- target = targets;
- while (target)
- {
- if (jtag_reset_config & RESET_SRST_PULLS_TRST)
- {
- switch (target->reset_mode)
- {
- case RESET_HALT:
- command_print(cmd_ctx, "nSRST pulls nTRST, falling back to RESET_RUN_AND_HALT");
- target->reset_mode = RESET_RUN_AND_HALT;
- break;
- case RESET_INIT:
- command_print(cmd_ctx, "nSRST pulls nTRST, falling back to RESET_RUN_AND_INIT");
- target->reset_mode = RESET_RUN_AND_INIT;
- break;
- default:
- break;
- }
- }
- switch (target->reset_mode)
- {
- case RESET_HALT:
- case RESET_INIT:
- target->type->prepare_reset_halt(target);
- break;
- default:
- break;
- }
- target = target->next;
- }
-
- target = targets;
- while (target)
- {
- target->type->assert_reset(target);
- target = target->next;
- }
- jtag_execute_queue();
-
- /* request target halt if necessary, and schedule further action */
- target = targets;
- while (target)
- {
- switch (target->reset_mode)
- {
- case RESET_RUN:
- /* nothing to do if target just wants to be run */
- break;
- case RESET_RUN_AND_HALT:
- /* schedule halt */
- target_register_timer_callback(target_run_and_halt_handler, target->run_and_halt_time, 0, target);
- break;
- case RESET_RUN_AND_INIT:
- /* schedule halt */
- target_register_timer_callback(target_run_and_halt_handler, target->run_and_halt_time, 0, target);
- target_register_event_callback(target_init_handler, cmd_ctx);
- break;
- case RESET_HALT:
- target->type->halt(target);
- break;
- case RESET_INIT:
- target->type->halt(target);
- target_register_event_callback(target_init_handler, cmd_ctx);
- break;
- default:
- ERROR("BUG: unknown target->reset_mode");
- }
- target = target->next;
- }
-
- target = targets;
- while (target)
- {
- target->type->deassert_reset(target);
- target = target->next;
- }
- jtag_execute_queue();
-
- /* Wait for reset to complete, maximum 5 seconds. */
- gettimeofday(&timeout, NULL);
- timeval_add_time(&timeout, 5, 0);
- for(;;)
- {
- gettimeofday(&now, NULL);
-
- target_call_timer_callbacks();
-
- target = targets;
- while (target)
- {
- target->type->poll(target);
- if ((target->reset_mode == RESET_RUN_AND_INIT) || (target->reset_mode == RESET_RUN_AND_HALT))
- {
- if (target->state != TARGET_HALTED)
- {
- if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec)))
- {
- command_print(cmd_ctx, "Timed out waiting for reset");
- goto done;
- }
- usleep(100*1000); /* Do not eat all cpu */
- goto again;
- }
- }
- target = target->next;
- }
- /* All targets we're waiting for are halted */
- break;
-
- again:;
- }
- done:
-
-
- /* We want any events to be processed before the prompt */
- target_call_timer_callbacks();
-
- return retval;
-}
-
-static int default_virt2phys(struct target_s *target, u32 virtual, u32 *physical)
-{
- *physical = virtual;
- return ERROR_OK;
-}
-
-static int default_mmu(struct target_s *target, int *enabled)
-{
- *enabled = 0;
- return ERROR_OK;
-}
-
-int target_init(struct command_context_s *cmd_ctx)
-{
- target_t *target = targets;
-
- while (target)
- {
- if (target->type->init_target(cmd_ctx, target) != ERROR_OK)
- {
- ERROR("target '%s' init failed", target->type->name);
- exit(-1);
- }
-
- /* Set up default functions if none are provided by target */
- if (target->type->virt2phys == NULL)
- {
- target->type->virt2phys = default_virt2phys;
- }
- if (target->type->mmu == NULL)
- {
- target->type->mmu = default_mmu;
- }
- target = target->next;
- }
-
- if (targets)
- {
- target_register_user_commands(cmd_ctx);
- target_register_timer_callback(handle_target, 100, 1, NULL);
- }
-
- return ERROR_OK;
-}
-
-int target_init_reset(struct command_context_s *cmd_ctx)
-{
- if (startup_mode == DAEMON_RESET)
- target_process_reset(cmd_ctx);
-
- return ERROR_OK;
-}
-
-int target_register_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv)
-{
- target_event_callback_t **callbacks_p = &target_event_callbacks;
-
- if (callback == NULL)
- {
- return ERROR_INVALID_ARGUMENTS;
- }
-
- if (*callbacks_p)
- {
- while ((*callbacks_p)->next)
- callbacks_p = &((*callbacks_p)->next);
- callbacks_p = &((*callbacks_p)->next);
- }
-
- (*callbacks_p) = malloc(sizeof(target_event_callback_t));
- (*callbacks_p)->callback = callback;
- (*callbacks_p)->priv = priv;
- (*callbacks_p)->next = NULL;
-
- return ERROR_OK;
-}
-
-int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv)
-{
- target_timer_callback_t **callbacks_p = &target_timer_callbacks;
- struct timeval now;
-
- if (callback == NULL)
- {
- return ERROR_INVALID_ARGUMENTS;
- }
-
- if (*callbacks_p)
- {
- while ((*callbacks_p)->next)
- callbacks_p = &((*callbacks_p)->next);
- callbacks_p = &((*callbacks_p)->next);
- }
-
- (*callbacks_p) = malloc(sizeof(target_timer_callback_t));
- (*callbacks_p)->callback = callback;
- (*callbacks_p)->periodic = periodic;
- (*callbacks_p)->time_ms = time_ms;
-
- gettimeofday(&now, NULL);
- (*callbacks_p)->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000;
- time_ms -= (time_ms % 1000);
- (*callbacks_p)->when.tv_sec = now.tv_sec + (time_ms / 1000);
- if ((*callbacks_p)->when.tv_usec > 1000000)
- {
- (*callbacks_p)->when.tv_usec = (*callbacks_p)->when.tv_usec - 1000000;
- (*callbacks_p)->when.tv_sec += 1;
- }
-
- (*callbacks_p)->priv = priv;
- (*callbacks_p)->next = NULL;
-
- return ERROR_OK;
-}
-
-int target_unregister_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv)
-{
- target_event_callback_t **p = &target_event_callbacks;
- target_event_callback_t *c = target_event_callbacks;
-
- if (callback == NULL)
- {
- return ERROR_INVALID_ARGUMENTS;
- }
-
- while (c)
- {
- target_event_callback_t *next = c->next;
- if ((c->callback == callback) && (c->priv == priv))
- {
- *p = next;
- free(c);
- return ERROR_OK;
- }
- else
- p = &(c->next);
- c = next;
- }
-
- return ERROR_OK;
-}
-
-int target_unregister_timer_callback(int (*callback)(void *priv), void *priv)
-{
- target_timer_callback_t **p = &target_timer_callbacks;
- target_timer_callback_t *c = target_timer_callbacks;
-
- if (callback == NULL)
- {
- return ERROR_INVALID_ARGUMENTS;
- }
-
- while (c)
- {
- target_timer_callback_t *next = c->next;
- if ((c->callback == callback) && (c->priv == priv))
- {
- *p = next;
- free(c);
- return ERROR_OK;
- }
- else
- p = &(c->next);
- c = next;
- }
-
- return ERROR_OK;
-}
-
-int target_call_event_callbacks(target_t *target, enum target_event event)
-{
- target_event_callback_t *callback = target_event_callbacks;
- target_event_callback_t *next_callback;
-
- DEBUG("target event %i", event);
-
- while (callback)
- {
- next_callback = callback->next;
- callback->callback(target, event, callback->priv);
- callback = next_callback;
- }
-
- return ERROR_OK;
-}
-
-int target_call_timer_callbacks()
-{
- target_timer_callback_t *callback = target_timer_callbacks;
- target_timer_callback_t *next_callback;
- struct timeval now;
-
- gettimeofday(&now, NULL);
-
- while (callback)
- {
- next_callback = callback->next;
-
- if (((now.tv_sec >= callback->when.tv_sec) && (now.tv_usec >= callback->when.tv_usec))
- || (now.tv_sec > callback->when.tv_sec))
- {
- callback->callback(callback->priv);
- if (callback->periodic)
- {
- int time_ms = callback->time_ms;
- callback->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000;
- time_ms -= (time_ms % 1000);
- callback->when.tv_sec = now.tv_sec + time_ms / 1000;
- if (callback->when.tv_usec > 1000000)
- {
- callback->when.tv_usec = callback->when.tv_usec - 1000000;
- callback->when.tv_sec += 1;
- }
- }
- else
- target_unregister_timer_callback(callback->callback, callback->priv);
- }
-
- callback = next_callback;
- }
-
- return ERROR_OK;
-}
-
-int target_alloc_working_area(struct target_s *target, u32 size, working_area_t **area)
-{
- working_area_t *c = target->working_areas;
- working_area_t *new_wa = NULL;
-
- /* Reevaluate working area address based on MMU state*/
- if (target->working_areas == NULL)
- {
- int retval;
- int enabled;
- retval = target->type->mmu(target, &enabled);
- if (retval != ERROR_OK)
- {
- return retval;
- }
- if (enabled)
- {
- target->working_area = target->working_area_virt;
- }
- else
- {
- target->working_area = target->working_area_phys;
- }
- }
-
- /* only allocate multiples of 4 byte */
- if (size % 4)
- {
- ERROR("BUG: code tried to allocate unaligned number of bytes, padding");
- size = CEIL(size, 4);
- }
-
- /* see if there's already a matching working area */
- while (c)
- {
- if ((c->free) && (c->size == size))
- {
- new_wa = c;
- break;
- }
- c = c->next;
- }
-
- /* if not, allocate a new one */
- if (!new_wa)
- {
- working_area_t **p = &target->working_areas;
- u32 first_free = target->working_area;
- u32 free_size = target->working_area_size;
-
- DEBUG("allocating new working area");
-
- c = target->working_areas;
- while (c)
- {
- first_free += c->size;
- free_size -= c->size;
- p = &c->next;
- c = c->next;
- }
-
- if (free_size < size)
- {
- WARNING("not enough working area available(requested %d, free %d)", size, free_size);
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
-
- new_wa = malloc(sizeof(working_area_t));
- new_wa->next = NULL;
- new_wa->size = size;
- new_wa->address = first_free;
-
- if (target->backup_working_area)
- {
- new_wa->backup = malloc(new_wa->size);
- target->type->read_memory(target, new_wa->address, 4, new_wa->size / 4, new_wa->backup);
- }
- else
- {
- new_wa->backup = NULL;
- }
-
- /* put new entry in list */
- *p = new_wa;
- }
-
- /* mark as used, and return the new (reused) area */
- new_wa->free = 0;
- *area = new_wa;
-
- /* user pointer */
- new_wa->user = area;
-
- return ERROR_OK;
-}
-
-int target_free_working_area(struct target_s *target, working_area_t *area)
-{
- if (area->free)
- return ERROR_OK;
-
- if (target->backup_working_area)
- target->type->write_memory(target, area->address, 4, area->size / 4, area->backup);
-
- area->free = 1;
-
- /* mark user pointer invalid */
- *area->user = NULL;
- area->user = NULL;
-
- return ERROR_OK;
-}
-
-int target_free_all_working_areas(struct target_s *target)
-{
- working_area_t *c = target->working_areas;
-
- while (c)
- {
- working_area_t *next = c->next;
- target_free_working_area(target, c);
-
- if (c->backup)
- free(c->backup);
-
- free(c);
-
- c = next;
- }
-
- target->working_areas = NULL;
-
- return ERROR_OK;
-}
-
-int target_register_commands(struct command_context_s *cmd_ctx)
-{
- register_command(cmd_ctx, NULL, "target", handle_target_command, COMMAND_CONFIG, NULL);
- register_command(cmd_ctx, NULL, "targets", handle_targets_command, COMMAND_EXEC, NULL);
- register_command(cmd_ctx, NULL, "daemon_startup", handle_daemon_startup_command, COMMAND_CONFIG, NULL);
- register_command(cmd_ctx, NULL, "target_script", handle_target_script_command, COMMAND_CONFIG, NULL);
- register_command(cmd_ctx, NULL, "run_and_halt_time", handle_run_and_halt_time_command, COMMAND_CONFIG, NULL);
- register_command(cmd_ctx, NULL, "working_area", handle_working_area_command, COMMAND_ANY, "working_area <target#> <address> <size> <'backup'|'nobackup'> [virtual address]");
- register_command(cmd_ctx, NULL, "virt2phys", handle_virt2phys_command, COMMAND_ANY, "virt2phys <virtual address>");
-
- return ERROR_OK;
-}
-
-int target_arch_state(struct target_s *target)
-{
- int retval;
- if (target==NULL)
- {
- USER("No target has been configured");
- return ERROR_OK;
- }
-
- USER("target state: %s", target_state_strings[target->state]);
-
- if (target->state!=TARGET_HALTED)
- return ERROR_OK;
-
- retval=target->type->arch_state(target);
- return retval;
-}
-
-/* Single aligned words are guaranteed to use 16 or 32 bit access
- * mode respectively, otherwise data is handled as quickly as
- * possible
- */
-int target_write_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer)
-{
- int retval;
-
- DEBUG("writing buffer of %i byte at 0x%8.8x", size, address);
-
- if (((address % 2) == 0) && (size == 2))
- {
- return target->type->write_memory(target, address, 2, 1, buffer);
- }
-
- /* handle unaligned head bytes */
- if (address % 4)
- {
- int unaligned = 4 - (address % 4);
-
- if (unaligned > size)
- unaligned = size;
-
- if ((retval = target->type->write_memory(target, address, 1, unaligned, buffer)) != ERROR_OK)
- return retval;
-
- buffer += unaligned;
- address += unaligned;
- size -= unaligned;
- }
-
- /* handle aligned words */
- if (size >= 4)
- {
- int aligned = size - (size % 4);
-
- /* use bulk writes above a certain limit. This may have to be changed */
- if (aligned > 128)
- {
- if ((retval = target->type->bulk_write_memory(target, address, aligned / 4, buffer)) != ERROR_OK)
- return retval;
- }
- else
- {
- if ((retval = target->type->write_memory(target, address, 4, aligned / 4, buffer)) != ERROR_OK)
- return retval;
- }
-
- buffer += aligned;
- address += aligned;
- size -= aligned;
- }
-
- /* handle tail writes of less than 4 bytes */
- if (size > 0)
- {
- if ((retval = target->type->write_memory(target, address, 1, size, buffer)) != ERROR_OK)
- return retval;
- }
-
- return ERROR_OK;
-}
-
-
-/* Single aligned words are guaranteed to use 16 or 32 bit access
- * mode respectively, otherwise data is handled as quickly as
- * possible
- */
-int target_read_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer)
-{
- int retval;
-
- DEBUG("reading buffer of %i byte at 0x%8.8x", size, address);
-
- if (((address % 2) == 0) && (size == 2))
- {
- return target->type->read_memory(target, address, 2, 1, buffer);
- }
-
- /* handle unaligned head bytes */
- if (address % 4)
- {
- int unaligned = 4 - (address % 4);
-
- if (unaligned > size)
- unaligned = size;
-
- if ((retval = target->type->read_memory(target, address, 1, unaligned, buffer)) != ERROR_OK)
- return retval;
-
- buffer += unaligned;
- address += unaligned;
- size -= unaligned;
- }
-
- /* handle aligned words */
- if (size >= 4)
- {
- int aligned = size - (size % 4);
-
- if ((retval = target->type->read_memory(target, address, 4, aligned / 4, buffer)) != ERROR_OK)
- return retval;
-
- buffer += aligned;
- address += aligned;
- size -= aligned;
- }
-
- /* handle tail writes of less than 4 bytes */
- if (size > 0)
- {
- if ((retval = target->type->read_memory(target, address, 1, size, buffer)) != ERROR_OK)
- return retval;
- }
-
- return ERROR_OK;
-}
-
-int target_checksum_memory(struct target_s *target, u32 address, u32 size, u32* crc)
-{
- u8 *buffer;
- int retval;
- int i;
- u32 checksum = 0;
-
- if ((retval = target->type->checksum_memory(target, address,
- size, &checksum)) == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
- {
- buffer = malloc(size);
- if (buffer == NULL)
- {
- ERROR("error allocating buffer for section (%d bytes)", size);
- return ERROR_INVALID_ARGUMENTS;
- }
- retval = target_read_buffer(target, address, size, buffer);
- if (retval != ERROR_OK)
- {
- free(buffer);
- return retval;
- }
-
- /* convert to target endianess */
- for (i = 0; i < (size/sizeof(u32)); i++)
- {
- u32 target_data;
- target_data = target_buffer_get_u32(target, &buffer[i*sizeof(u32)]);
- target_buffer_set_u32(target, &buffer[i*sizeof(u32)], target_data);
- }
-
- retval = image_calculate_checksum( buffer, size, &checksum );
- free(buffer);
- }
-
- *crc = checksum;
-
- return retval;
-}
-
-int target_read_u32(struct target_s *target, u32 address, u32 *value)
-{
- u8 value_buf[4];
-
- int retval = target->type->read_memory(target, address, 4, 1, value_buf);
-
- if (retval == ERROR_OK)
- {
- *value = target_buffer_get_u32(target, value_buf);
- DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, *value);
- }
- else
- {
- *value = 0x0;
- DEBUG("address: 0x%8.8x failed", address);
- }
-
- return retval;
-}
-
-int target_read_u16(struct target_s *target, u32 address, u16 *value)
-{
- u8 value_buf[2];
-
- int retval = target->type->read_memory(target, address, 2, 1, value_buf);
-
- if (retval == ERROR_OK)
- {
- *value = target_buffer_get_u16(target, value_buf);
- DEBUG("address: 0x%8.8x, value: 0x%4.4x", address, *value);
- }
- else
- {
- *value = 0x0;
- DEBUG("address: 0x%8.8x failed", address);
- }
-
- return retval;
-}
-
-int target_read_u8(struct target_s *target, u32 address, u8 *value)
-{
- int retval = target->type->read_memory(target, address, 1, 1, value);
-
- if (retval == ERROR_OK)
- {
- DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, *value);
- }
- else
- {
- *value = 0x0;
- DEBUG("address: 0x%8.8x failed", address);
- }
-
- return retval;
-}
-
-int target_write_u32(struct target_s *target, u32 address, u32 value)
-{
- int retval;
- u8 value_buf[4];
-
- DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, value);
-
- target_buffer_set_u32(target, value_buf, value);
- if ((retval = target->type->write_memory(target, address, 4, 1, value_buf)) != ERROR_OK)
- {
- DEBUG("failed: %i", retval);
- }
-
- return retval;
-}
-
-int target_write_u16(struct target_s *target, u32 address, u16 value)
-{
- int retval;
- u8 value_buf[2];
-
- DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, value);
-
- target_buffer_set_u16(target, value_buf, value);
- if ((retval = target->type->write_memory(target, address, 2, 1, value_buf)) != ERROR_OK)
- {
- DEBUG("failed: %i", retval);
- }
-
- return retval;
-}
-
-int target_write_u8(struct target_s *target, u32 address, u8 value)
-{
- int retval;
-
- DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, value);
-
- if ((retval = target->type->read_memory(target, address, 1, 1, &value)) != ERROR_OK)
- {
- DEBUG("failed: %i", retval);
- }
-
- return retval;
-}
-
-int target_register_user_commands(struct command_context_s *cmd_ctx)
-{
- register_command(cmd_ctx, NULL, "reg", handle_reg_command, COMMAND_EXEC, NULL);
- register_command(cmd_ctx, NULL, "poll", handle_poll_command, COMMAND_EXEC, "poll target state");
- register_command(cmd_ctx, NULL, "wait_halt", handle_wait_halt_command, COMMAND_EXEC, "wait for target halt [time (s)]");
- register_command(cmd_ctx, NULL, "halt", handle_halt_command, COMMAND_EXEC, "halt target");
- register_command(cmd_ctx, NULL, "resume", handle_resume_command, COMMAND_EXEC, "resume target [addr]");
- register_command(cmd_ctx, NULL, "step", handle_step_command, COMMAND_EXEC, "step one instruction from current PC or [addr]");
- register_command(cmd_ctx, NULL, "reset", handle_reset_command, COMMAND_EXEC, "reset target [run|halt|init|run_and_halt|run_and_init]");
- register_command(cmd_ctx, NULL, "soft_reset_halt", handle_soft_reset_halt_command, COMMAND_EXEC, "halt the target and do a soft reset");
-
- register_command(cmd_ctx, NULL, "mdw", handle_md_command, COMMAND_EXEC, "display memory words <addr> [count]");
- register_command(cmd_ctx, NULL, "mdh", handle_md_command, COMMAND_EXEC, "display memory half-words <addr> [count]");
- register_command(cmd_ctx, NULL, "mdb", handle_md_command, COMMAND_EXEC, "display memory bytes <addr> [count]");
-
- register_command(cmd_ctx, NULL, "mww", handle_mw_command, COMMAND_EXEC, "write memory word <addr> <value>");
- register_command(cmd_ctx, NULL, "mwh", handle_mw_command, COMMAND_EXEC, "write memory half-word <addr> <value>");
- register_command(cmd_ctx, NULL, "mwb", handle_mw_command, COMMAND_EXEC, "write memory byte <addr> <value>");
-
- register_command(cmd_ctx, NULL, "bp", handle_bp_command, COMMAND_EXEC, "set breakpoint <address> <length> [hw]");
- register_command(cmd_ctx, NULL, "rbp", handle_rbp_command, COMMAND_EXEC, "remove breakpoint <adress>");
- register_command(cmd_ctx, NULL, "wp", handle_wp_command, COMMAND_EXEC, "set watchpoint <address> <length> <r/w/a> [value] [mask]");
- register_command(cmd_ctx, NULL, "rwp", handle_rwp_command, COMMAND_EXEC, "remove watchpoint <adress>");
-
- register_command(cmd_ctx, NULL, "load_image", handle_load_image_command, COMMAND_EXEC, "load_image <file> <address> ['bin'|'ihex'|'elf'|'s19']");
- register_command(cmd_ctx, NULL, "dump_image", handle_dump_image_command, COMMAND_EXEC, "dump_image <file> <address> <size>");
- register_command(cmd_ctx, NULL, "verify_image", handle_verify_image_command, COMMAND_EXEC, "verify_image <file> [offset] [type]");
- register_command(cmd_ctx, NULL, "load_binary", handle_load_image_command, COMMAND_EXEC, "[DEPRECATED] load_binary <file> <address>");
- register_command(cmd_ctx, NULL, "dump_binary", handle_dump_image_command, COMMAND_EXEC, "[DEPRECATED] dump_binary <file> <address> <size>");
-
- target_request_register_commands(cmd_ctx);
- trace_register_commands(cmd_ctx);
-
- return ERROR_OK;
-}
-
-int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = targets;
- int count = 0;
-
- if (argc == 1)
- {
- int num = strtoul(args[0], NULL, 0);
-
- while (target)
- {
- count++;
- target = target->next;
- }
-
- if (num < count)
- cmd_ctx->current_target = num;
- else
- command_print(cmd_ctx, "%i is out of bounds, only %i targets are configured", num, count);
-
- return ERROR_OK;
- }
-
- while (target)
- {
- command_print(cmd_ctx, "%i: %s (%s), state: %s", count++, target->type->name, target_endianess_strings[target->endianness], target_state_strings[target->state]);
- target = target->next;
- }
-
- return ERROR_OK;
-}
-
-int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- int i;
- int found = 0;
-
- if (argc < 3)
- {
- ERROR("target command requires at least three arguments: <type> <endianess> <reset_mode>");
- exit(-1);
- }
-
- /* search for the specified target */
- if (args[0] && (args[0][0] != 0))
- {
- for (i = 0; target_types[i]; i++)
- {
- if (strcmp(args[0], target_types[i]->name) == 0)
- {
- target_t **last_target_p = &targets;
-
- /* register target specific commands */
- if (target_types[i]->register_commands(cmd_ctx) != ERROR_OK)
- {
- ERROR("couldn't register '%s' commands", args[0]);
- exit(-1);
- }
-
- if (*last_target_p)
- {
- while ((*last_target_p)->next)
- last_target_p = &((*last_target_p)->next);
- last_target_p = &((*last_target_p)->next);
- }
-
- *last_target_p = malloc(sizeof(target_t));
-
- (*last_target_p)->type = target_types[i];
-
- if (strcmp(args[1], "big") == 0)
- (*last_target_p)->endianness = TARGET_BIG_ENDIAN;
- else if (strcmp(args[1], "little") == 0)
- (*last_target_p)->endianness = TARGET_LITTLE_ENDIAN;
- else
- {
- ERROR("endianness must be either 'little' or 'big', not '%s'", args[1]);
- exit(-1);
- }
-
- /* what to do on a target reset */
- if (strcmp(args[2], "reset_halt") == 0)
- (*last_target_p)->reset_mode = RESET_HALT;
- else if (strcmp(args[2], "reset_run") == 0)
- (*last_target_p)->reset_mode = RESET_RUN;
- else if (strcmp(args[2], "reset_init") == 0)
- (*last_target_p)->reset_mode = RESET_INIT;
- else if (strcmp(args[2], "run_and_halt") == 0)
- (*last_target_p)->reset_mode = RESET_RUN_AND_HALT;
- else if (strcmp(args[2], "run_and_init") == 0)
- (*last_target_p)->reset_mode = RESET_RUN_AND_INIT;
- else
- {
- ERROR("unknown target startup mode %s", args[2]);
- exit(-1);
- }
- (*last_target_p)->run_and_halt_time = 1000; /* default 1s */
-
- (*last_target_p)->reset_script = NULL;
- (*last_target_p)->post_halt_script = NULL;
- (*last_target_p)->pre_resume_script = NULL;
- (*last_target_p)->gdb_program_script = NULL;
-
- (*last_target_p)->working_area = 0x0;
- (*last_target_p)->working_area_size = 0x0;
- (*last_target_p)->working_areas = NULL;
- (*last_target_p)->backup_working_area = 0;
-
- (*last_target_p)->state = TARGET_UNKNOWN;
- (*last_target_p)->reg_cache = NULL;
- (*last_target_p)->breakpoints = NULL;
- (*last_target_p)->watchpoints = NULL;
- (*last_target_p)->next = NULL;
- (*last_target_p)->arch_info = NULL;
-
- /* initialize trace information */
- (*last_target_p)->trace_info = malloc(sizeof(trace_t));
- (*last_target_p)->trace_info->num_trace_points = 0;
- (*last_target_p)->trace_info->trace_points_size = 0;
- (*last_target_p)->trace_info->trace_points = NULL;
- (*last_target_p)->trace_info->trace_history_size = 0;
- (*last_target_p)->trace_info->trace_history = NULL;
- (*last_target_p)->trace_info->trace_history_pos = 0;
- (*last_target_p)->trace_info->trace_history_overflowed = 0;
-
- (*last_target_p)->dbgmsg = NULL;
- (*last_target_p)->dbg_msg_enabled = 0;
-
- (*last_target_p)->type->target_command(cmd_ctx, cmd, args, argc, *last_target_p);
-
- found = 1;
- break;
- }
- }
- }
-
- /* no matching target found */
- if (!found)
- {
- ERROR("target '%s' not found", args[0]);
- exit(-1);
- }
-
- return ERROR_OK;
-}
-
-/* usage: target_script <target#> <event> <script_file> */
-int handle_target_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = NULL;
-
- if (argc < 3)
- {
- ERROR("incomplete target_script command");
- exit(-1);
- }
-
- target = get_target_by_num(strtoul(args[0], NULL, 0));
-
- if (!target)
- {
- ERROR("target number '%s' not defined", args[0]);
- exit(-1);
- }
-
- if (strcmp(args[1], "reset") == 0)
- {
- if (target->reset_script)
- free(target->reset_script);
- target->reset_script = strdup(args[2]);
- }
- else if (strcmp(args[1], "post_halt") == 0)
- {
- if (target->post_halt_script)
- free(target->post_halt_script);
- target->post_halt_script = strdup(args[2]);
- }
- else if (strcmp(args[1], "pre_resume") == 0)
- {
- if (target->pre_resume_script)
- free(target->pre_resume_script);
- target->pre_resume_script = strdup(args[2]);
- }
- else if (strcmp(args[1], "gdb_program_config") == 0)
- {
- if (target->gdb_program_script)
- free(target->gdb_program_script);
- target->gdb_program_script = strdup(args[2]);
- }
- else
- {
- ERROR("unknown event type: '%s", args[1]);
- exit(-1);
- }
-
- return ERROR_OK;
-}
-
-int handle_run_and_halt_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = NULL;
-
- if (argc < 2)
- {
- ERROR("incomplete run_and_halt_time command");
- exit(-1);
- }
-
- target = get_target_by_num(strtoul(args[0], NULL, 0));
-
- if (!target)
- {
- ERROR("target number '%s' not defined", args[0]);
- exit(-1);
- }
-
- target->run_and_halt_time = strtoul(args[1], NULL, 0);
-
- return ERROR_OK;
-}
-
-int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = NULL;
-
- if ((argc < 4) || (argc > 5))
- {
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- target = get_target_by_num(strtoul(args[0], NULL, 0));
-
- if (!target)
- {
- ERROR("target number '%s' not defined", args[0]);
- exit(-1);
- }
- target_free_all_working_areas(target);
-
- target->working_area_phys = target->working_area_virt = strtoul(args[1], NULL, 0);
- if (argc == 5)
- {
- target->working_area_virt = strtoul(args[4], NULL, 0);
- }
- target->working_area_size = strtoul(args[2], NULL, 0);
-
- if (strcmp(args[3], "backup") == 0)
- {
- target->backup_working_area = 1;
- }
- else if (strcmp(args[3], "nobackup") == 0)
- {
- target->backup_working_area = 0;
- }
- else
- {
- ERROR("unrecognized <backup|nobackup> argument (%s)", args[3]);
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- return ERROR_OK;
-}
-
-
-/* process target state changes */
-int handle_target(void *priv)
-{
- int retval;
- target_t *target = targets;
-
- while (target)
- {
- /* only poll if target isn't already halted */
- if (target->state != TARGET_HALTED)
- {
- if (target_continous_poll)
- if ((retval = target->type->poll(target)) != ERROR_OK)
- {
- ERROR("couldn't poll target(%d). It's due for a reset.", retval);
- }
- }
-
- target = target->next;
- }
-
- return ERROR_OK;
-}
-
-int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target;
- reg_t *reg = NULL;
- int count = 0;
- char *value;
-
- DEBUG("-");
-
- target = get_current_target(cmd_ctx);
-
- /* list all available registers for the current target */
- if (argc == 0)
- {
- reg_cache_t *cache = target->reg_cache;
-
- count = 0;
- while(cache)
- {
- int i;
- for (i = 0; i < cache->num_regs; i++)
- {
- 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);
- }
- cache = cache->next;
- }
-
- return ERROR_OK;
- }
-
- /* access a single register by its ordinal number */
- if ((args[0][0] >= '0') && (args[0][0] <= '9'))
- {
- int num = strtoul(args[0], NULL, 0);
- reg_cache_t *cache = target->reg_cache;
-
- count = 0;
- while(cache)
- {
- int i;
- for (i = 0; i < cache->num_regs; i++)
- {
- if (count++ == num)
- {
- reg = &cache->reg_list[i];
- break;
- }
- }
- if (reg)
- break;
- cache = cache->next;
- }
-
- if (!reg)
- {
- command_print(cmd_ctx, "%i is out of bounds, the current target has only %i registers (0 - %i)", num, count, count - 1);
- return ERROR_OK;
- }
- } else /* access a single register by its name */
- {
- reg = register_get_by_name(target->reg_cache, args[0], 1);
-
- if (!reg)
- {
- command_print(cmd_ctx, "register %s not found in current target", args[0]);
- return ERROR_OK;
- }
- }
-
- /* display a register */
- if ((argc == 1) || ((argc == 2) && !((args[1][0] >= '0') && (args[1][0] <= '9'))))
- {
- if ((argc == 2) && (strcmp(args[1], "force") == 0))
- reg->valid = 0;
-
- if (reg->valid == 0)
- {
- reg_arch_type_t *arch_type = register_get_arch_type(reg->arch_type);
- if (arch_type == NULL)
- {
- ERROR("BUG: encountered unregistered arch type");
- return ERROR_OK;
- }
- arch_type->get(reg);
- }
- 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;
- }
-
- /* set register value */
- if (argc == 2)
- {
- 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)
- {
- ERROR("BUG: encountered unregistered arch type");
- return ERROR_OK;
- }
-
- 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;
- }
-
- command_print(cmd_ctx, "usage: reg <#|name> [value]");
-
- return ERROR_OK;
-}
-
-static int wait_state(struct command_context_s *cmd_ctx, char *cmd, enum target_state state, int ms);
-
-int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
-
- if (argc == 0)
- {
- target->type->poll(target);
- target_arch_state(target);
- }
- else
- {
- if (strcmp(args[0], "on") == 0)
- {
- target_continous_poll = 1;
- }
- else if (strcmp(args[0], "off") == 0)
- {
- target_continous_poll = 0;
- }
- else
- {
- command_print(cmd_ctx, "arg is \"on\" or \"off\"");
- }
- }
-
-
- return ERROR_OK;
-}
-
-int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- int ms = 5000;
-
- if (argc > 0)
- {
- char *end;
-
- ms = strtoul(args[0], &end, 0) * 1000;
- if (*end)
- {
- command_print(cmd_ctx, "usage: %s [seconds]", cmd);
- return ERROR_OK;
- }
- }
-
- return wait_state(cmd_ctx, cmd, TARGET_HALTED, ms);
-}
-
-static void target_process_events(struct command_context_s *cmd_ctx)
-{
- target_t *target = get_current_target(cmd_ctx);
- target->type->poll(target);
- target_call_timer_callbacks();
-}
-
-static int wait_state(struct command_context_s *cmd_ctx, char *cmd, enum target_state state, int ms)
-{
- int retval;
- struct timeval timeout, now;
-
- gettimeofday(&timeout, NULL);
- timeval_add_time(&timeout, 0, ms * 1000);
-
- target_t *target = get_current_target(cmd_ctx);
- for (;;)
- {
- if ((retval=target->type->poll(target))!=ERROR_OK)
- return retval;
- target_call_timer_callbacks();
- if (target->state == state)
- {
- break;
- }
- command_print(cmd_ctx, "waiting for target %s...", target_state_strings[state]);
-
- gettimeofday(&now, NULL);
- if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec)))
- {
- command_print(cmd_ctx, "timed out while waiting for target %s", target_state_strings[state]);
- ERROR("timed out while waiting for target %s", target_state_strings[state]);
- break;
- }
- }
-
- return ERROR_OK;
-}
-
-int handle_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- int retval;
- target_t *target = get_current_target(cmd_ctx);
-
- DEBUG("-");
-
- command_print(cmd_ctx, "requesting target halt...");
-
- if ((retval = target->type->halt(target)) != ERROR_OK)
- {
- switch (retval)
- {
- case ERROR_TARGET_ALREADY_HALTED:
- command_print(cmd_ctx, "target already halted");
- break;
- case ERROR_TARGET_TIMEOUT:
- command_print(cmd_ctx, "target timed out... shutting down");
- return retval;
- default:
- command_print(cmd_ctx, "unknown error... shutting down");
- return retval;
- }
- }
-
- return handle_wait_halt_command(cmd_ctx, cmd, args, argc);
-}
-
-/* what to do on daemon startup */
-int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- if (argc == 1)
- {
- if (strcmp(args[0], "attach") == 0)
- {
- startup_mode = DAEMON_ATTACH;
- return ERROR_OK;
- }
- else if (strcmp(args[0], "reset") == 0)
- {
- startup_mode = DAEMON_RESET;
- return ERROR_OK;
- }
- }
-
- WARNING("invalid daemon_startup configuration directive: %s", args[0]);
- return ERROR_OK;
-
-}
-
-int handle_soft_reset_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- int retval;
-
- command_print(cmd_ctx, "requesting target halt and executing a soft reset");
-
- if ((retval = target->type->soft_reset_halt(target)) != ERROR_OK)
- {
- switch (retval)
- {
- case ERROR_TARGET_TIMEOUT:
- command_print(cmd_ctx, "target timed out... shutting down");
- exit(-1);
- default:
- command_print(cmd_ctx, "unknown error... shutting down");
- exit(-1);
- }
- }
-
- return ERROR_OK;
-}
-
-int handle_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- enum target_reset_mode reset_mode = target->reset_mode;
- enum target_reset_mode save = target->reset_mode;
-
- DEBUG("-");
-
- if (argc >= 1)
- {
- if (strcmp("run", args[0]) == 0)
- reset_mode = RESET_RUN;
- else if (strcmp("halt", args[0]) == 0)
- reset_mode = RESET_HALT;
- else if (strcmp("init", args[0]) == 0)
- reset_mode = RESET_INIT;
- else if (strcmp("run_and_halt", args[0]) == 0)
- {
- reset_mode = RESET_RUN_AND_HALT;
- if (argc >= 2)
- {
- target->run_and_halt_time = strtoul(args[1], NULL, 0);
- }
- }
- else if (strcmp("run_and_init", args[0]) == 0)
- {
- reset_mode = RESET_RUN_AND_INIT;
- if (argc >= 2)
- {
- target->run_and_halt_time = strtoul(args[1], NULL, 0);
- }
- }
- else
- {
- command_print(cmd_ctx, "usage: reset ['run', 'halt', 'init', 'run_and_halt', 'run_and_init]");
- return ERROR_OK;
- }
- }
-
- /* temporarily modify mode of current reset target */
- target->reset_mode = reset_mode;
-
- /* reset *all* targets */
- target_process_reset(cmd_ctx);
-
- /* Restore default reset mode for this target */
- target->reset_mode = save;
-
- return ERROR_OK;
-}
-
-int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- int retval;
- target_t *target = get_current_target(cmd_ctx);
-
- if (argc == 0)
- retval = target->type->resume(target, 1, 0, 1, 0); /* current pc, addr = 0, handle breakpoints, not debugging */
- else if (argc == 1)
- retval = target->type->resume(target, 0, strtoul(args[0], NULL, 0), 1, 0); /* addr = args[0], handle breakpoints, not debugging */
- else
- {
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- target_process_events(cmd_ctx);
-
- target_arch_state(target);
-
- return retval;
-}
-
-int handle_step_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
-
- DEBUG("-");
-
- if (argc == 0)
- target->type->step(target, 1, 0, 1); /* current pc, addr = 0, handle breakpoints */
-
- if (argc == 1)
- target->type->step(target, 0, strtoul(args[0], NULL, 0), 1); /* addr = args[0], handle breakpoints */
-
- return ERROR_OK;
-}
-
-int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- const int line_bytecnt = 32;
- int count = 1;
- int size = 4;
- u32 address = 0;
- int line_modulo;
- int i;
-
- char output[128];
- int output_len;
-
- int retval;
-
- u8 *buffer;
- target_t *target = get_current_target(cmd_ctx);
-
- if (argc < 1)
- return ERROR_OK;
-
- if (argc == 2)
- count = strtoul(args[1], NULL, 0);
-
- address = strtoul(args[0], NULL, 0);
-
-
- switch (cmd[2])
- {
- case 'w':
- size = 4; line_modulo = line_bytecnt / 4;
- break;
- case 'h':
- size = 2; line_modulo = line_bytecnt / 2;
- break;
- case 'b':
- size = 1; line_modulo = line_bytecnt / 1;
- break;
- default:
- return ERROR_OK;
- }
-
- buffer = calloc(count, size);
- retval = target->type->read_memory(target, address, size, count, buffer);
- if (retval != ERROR_OK)
- {
- switch (retval)
- {
- case ERROR_TARGET_UNALIGNED_ACCESS:
- command_print(cmd_ctx, "error: address not aligned");
- break;
- case ERROR_TARGET_NOT_HALTED:
- command_print(cmd_ctx, "error: target must be halted for memory accesses");
- break;
- case ERROR_TARGET_DATA_ABORT:
- command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted");
- break;
- default:
- command_print(cmd_ctx, "error: unknown error");
- break;
- }
- return ERROR_OK;
- }
-
- output_len = 0;
-
- for (i = 0; i < count; i++)
- {
- if (i%line_modulo == 0)
- output_len += snprintf(output + output_len, 128 - output_len, "0x%8.8x: ", address + (i*size));
-
- switch (size)
- {
- case 4:
- output_len += snprintf(output + output_len, 128 - output_len, "%8.8x ", target_buffer_get_u32(target, &buffer[i*4]));
- break;
- case 2:
- output_len += snprintf(output + output_len, 128 - output_len, "%4.4x ", target_buffer_get_u16(target, &buffer[i*2]));
- break;
- case 1:
- output_len += snprintf(output + output_len, 128 - output_len, "%2.2x ", buffer[i*1]);
- break;
- }
-
- if ((i%line_modulo == line_modulo-1) || (i == count - 1))
- {
- command_print(cmd_ctx, output);
- output_len = 0;
- }
- }
-
- free(buffer);
-
- return ERROR_OK;
-}
-
-int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- u32 address = 0;
- u32 value = 0;
- int retval;
- target_t *target = get_current_target(cmd_ctx);
- u8 value_buf[4];
-
- if (argc < 2)
- return ERROR_OK;
-
- address = strtoul(args[0], NULL, 0);
- value = strtoul(args[1], NULL, 0);
-
- switch (cmd[2])
- {
- case 'w':
- target_buffer_set_u32(target, value_buf, value);
- retval = target->type->write_memory(target, address, 4, 1, value_buf);
- break;
- case 'h':
- target_buffer_set_u16(target, value_buf, value);
- retval = target->type->write_memory(target, address, 2, 1, value_buf);
- break;
- case 'b':
- value_buf[0] = value;
- retval = target->type->write_memory(target, address, 1, 1, value_buf);
- break;
- default:
- return ERROR_OK;
- }
-
- switch (retval)
- {
- case ERROR_TARGET_UNALIGNED_ACCESS:
- command_print(cmd_ctx, "error: address not aligned");
- break;
- case ERROR_TARGET_DATA_ABORT:
- command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted");
- break;
- case ERROR_TARGET_NOT_HALTED:
- command_print(cmd_ctx, "error: target must be halted for memory accesses");
- break;
- case ERROR_OK:
- break;
- default:
- command_print(cmd_ctx, "error: unknown error");
- break;
- }
-
- return ERROR_OK;
-
-}
-
-int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- u8 *buffer;
- u32 buf_cnt;
- u32 image_size;
- int i;
- int retval;
-
- image_t image;
-
- duration_t duration;
- char *duration_text;
-
- target_t *target = get_current_target(cmd_ctx);
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "usage: load_image <filename> [address] [type]");
- return ERROR_OK;
- }
-
- /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */
- if (argc >= 2)
- {
- image.base_address_set = 1;
- image.base_address = strtoul(args[1], NULL, 0);
- }
- else
- {
- image.base_address_set = 0;
- }
-
- image.start_address_set = 0;
-
- duration_start_measure(&duration);
-
- if (image_open(&image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK)
- {
- command_print(cmd_ctx, "load_image error: %s", image.error_str);
- return ERROR_OK;
- }
-
- image_size = 0x0;
- for (i = 0; i < image.num_sections; i++)
- {
- buffer = malloc(image.sections[i].size);
- if (buffer == NULL)
- {
- command_print(cmd_ctx, "error allocating buffer for section (%d bytes)", image.sections[i].size);
- break;
- }
-
- if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK)
- {
- ERROR("image_read_section failed with error code: %i", retval);
- command_print(cmd_ctx, "image reading failed, download aborted");
- free(buffer);
- image_close(&image);
- return ERROR_OK;
- }
- target_write_buffer(target, image.sections[i].base_address, buf_cnt, buffer);
- image_size += buf_cnt;
- command_print(cmd_ctx, "%u byte written at address 0x%8.8x", buf_cnt, image.sections[i].base_address);
-
- free(buffer);
- }
-
- duration_stop_measure(&duration, &duration_text);
- command_print(cmd_ctx, "downloaded %u byte in %s", image_size, duration_text);
- free(duration_text);
-
- image_close(&image);
-
- return ERROR_OK;
-
-}
-
-int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- fileio_t fileio;
-
- u32 address;
- u32 size;
- u8 buffer[560];
- int retval;
-
- duration_t duration;
- char *duration_text;
-
- target_t *target = get_current_target(cmd_ctx);
-
- if (argc != 3)
- {
- command_print(cmd_ctx, "usage: dump_image <filename> <address> <size>");
- return ERROR_OK;
- }
-
- address = strtoul(args[1], NULL, 0);
- size = strtoul(args[2], NULL, 0);
-
- if ((address & 3) || (size & 3))
- {
- command_print(cmd_ctx, "only 32-bit aligned address and size are supported");
- return ERROR_OK;
- }
-
- if (fileio_open(&fileio, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK)
- {
- command_print(cmd_ctx, "dump_image error: %s", fileio.error_str);
- return ERROR_OK;
- }
-
- duration_start_measure(&duration);
-
- while (size > 0)
- {
- u32 size_written;
- u32 this_run_size = (size > 560) ? 560 : size;
-
- retval = target->type->read_memory(target, address, 4, this_run_size / 4, buffer);
- if (retval != ERROR_OK)
- {
- command_print(cmd_ctx, "Reading memory failed %d", retval);
- break;
- }
-
- fileio_write(&fileio, this_run_size, buffer, &size_written);
-
- size -= this_run_size;
- address += this_run_size;
- }
-
- fileio_close(&fileio);
-
- duration_stop_measure(&duration, &duration_text);
- command_print(cmd_ctx, "dumped %"PRIi64" byte in %s", fileio.size, duration_text);
- free(duration_text);
-
- return ERROR_OK;
-}
-
-int handle_verify_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- u8 *buffer;
- u32 buf_cnt;
- u32 image_size;
- int i;
- int retval;
- u32 checksum = 0;
- u32 mem_checksum = 0;
-
- image_t image;
-
- duration_t duration;
- char *duration_text;
-
- target_t *target = get_current_target(cmd_ctx);
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "usage: verify_image <file> [offset] [type]");
- return ERROR_OK;
- }
-
- if (!target)
- {
- ERROR("no target selected");
- return ERROR_OK;
- }
-
- duration_start_measure(&duration);
-
- if (argc >= 2)
- {
- image.base_address_set = 1;
- image.base_address = strtoul(args[1], NULL, 0);
- }
- else
- {
- image.base_address_set = 0;
- image.base_address = 0x0;
- }
-
- image.start_address_set = 0;
-
- if (image_open(&image, args[0], (argc == 3) ? args[2] : NULL) != ERROR_OK)
- {
- command_print(cmd_ctx, "verify_image error: %s", image.error_str);
- return ERROR_OK;
- }
-
- image_size = 0x0;
- for (i = 0; i < image.num_sections; i++)
- {
- buffer = malloc(image.sections[i].size);
- if (buffer == NULL)
- {
- command_print(cmd_ctx, "error allocating buffer for section (%d bytes)", image.sections[i].size);
- break;
- }
- if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK)
- {
- ERROR("image_read_section failed with error code: %i", retval);
- command_print(cmd_ctx, "image reading failed, verify aborted");
- free(buffer);
- image_close(&image);
- return ERROR_OK;
- }
-
- /* calculate checksum of image */
- image_calculate_checksum( buffer, buf_cnt, &checksum );
-
- retval = target_checksum_memory(target, image.sections[i].base_address, buf_cnt, &mem_checksum);
-
- if( retval != ERROR_OK )
- {
- command_print(cmd_ctx, "could not calculate checksum, verify aborted");
- free(buffer);
- image_close(&image);
- return ERROR_OK;
- }
-
- if( checksum != mem_checksum )
- {
- /* failed crc checksum, fall back to a binary compare */
- u8 *data;
-
- command_print(cmd_ctx, "checksum mismatch - attempting binary compare");
-
- data = (u8*)malloc(buf_cnt);
-
- /* Can we use 32bit word accesses? */
- int size = 1;
- int count = buf_cnt;
- if ((count % 4) == 0)
- {
- size *= 4;
- count /= 4;
- }
- retval = target->type->read_memory(target, image.sections[i].base_address, size, count, data);
-
- if (retval == ERROR_OK)
- {
- int t;
- for (t = 0; t < buf_cnt; t++)
- {
- if (data[t] != buffer[t])
- {
- command_print(cmd_ctx, "Verify operation failed address 0x%08x. Was 0x%02x instead of 0x%02x\n", t + image.sections[i].base_address, data[t], buffer[t]);
- free(data);
- free(buffer);
- image_close(&image);
- return ERROR_OK;
- }
- }
- }
-
- free(data);
- }
-
- free(buffer);
- image_size += buf_cnt;
- }
-
- duration_stop_measure(&duration, &duration_text);
- command_print(cmd_ctx, "verified %u bytes in %s", image_size, duration_text);
- free(duration_text);
-
- image_close(&image);
-
- return ERROR_OK;
-}
-
-int handle_bp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- int retval;
- target_t *target = get_current_target(cmd_ctx);
-
- if (argc == 0)
- {
- breakpoint_t *breakpoint = target->breakpoints;
-
- while (breakpoint)
- {
- if (breakpoint->type == BKPT_SOFT)
- {
- 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);
- }
- else
- {
- command_print(cmd_ctx, "0x%8.8x, 0x%x, %i", breakpoint->address, breakpoint->length, breakpoint->set);
- }
- breakpoint = breakpoint->next;
- }
- }
- else if (argc >= 2)
- {
- int hw = BKPT_SOFT;
- u32 length = 0;
-
- length = strtoul(args[1], NULL, 0);
-
- if (argc >= 3)
- if (strcmp(args[2], "hw") == 0)
- hw = BKPT_HARD;
-
- if ((retval = breakpoint_add(target, strtoul(args[0], NULL, 0), length, hw)) != ERROR_OK)
- {
- switch (retval)
- {
- case ERROR_TARGET_NOT_HALTED:
- command_print(cmd_ctx, "target must be halted to set breakpoints");
- break;
- case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
- command_print(cmd_ctx, "no more breakpoints available");
- break;
- default:
- command_print(cmd_ctx, "unknown error, breakpoint not set");
- break;
- }
- }
- else
- {
- command_print(cmd_ctx, "breakpoint added at address 0x%8.8x", strtoul(args[0], NULL, 0));
- }
- }
- else
- {
- command_print(cmd_ctx, "usage: bp <address> <length> ['hw']");
- }
-
- return ERROR_OK;
-}
-
-int handle_rbp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
-
- if (argc > 0)
- breakpoint_remove(target, strtoul(args[0], NULL, 0));
-
- return ERROR_OK;
-}
-
-int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- int retval;
-
- if (argc == 0)
- {
- watchpoint_t *watchpoint = target->watchpoints;
-
- while (watchpoint)
- {
- command_print(cmd_ctx, "address: 0x%8.8x, mask: 0x%8.8x, r/w/a: %i, value: 0x%8.8x, mask: 0x%8.8x", watchpoint->address, watchpoint->length, watchpoint->rw, watchpoint->value, watchpoint->mask);
- watchpoint = watchpoint->next;
- }
- }
- else if (argc >= 2)
- {
- enum watchpoint_rw type = WPT_ACCESS;
- u32 data_value = 0x0;
- u32 data_mask = 0xffffffff;
-
- if (argc >= 3)
- {
- switch(args[2][0])
- {
- case 'r':
- type = WPT_READ;
- break;
- case 'w':
- type = WPT_WRITE;
- break;
- case 'a':
- type = WPT_ACCESS;
- break;
- default:
- command_print(cmd_ctx, "usage: wp <address> <length> [r/w/a] [value] [mask]");
- return ERROR_OK;
- }
- }
- if (argc >= 4)
- {
- data_value = strtoul(args[3], NULL, 0);
- }
- if (argc >= 5)
- {
- data_mask = strtoul(args[4], NULL, 0);
- }
-
- if ((retval = watchpoint_add(target, strtoul(args[0], NULL, 0),
- strtoul(args[1], NULL, 0), type, data_value, data_mask)) != ERROR_OK)
- {
- switch (retval)
- {
- case ERROR_TARGET_NOT_HALTED:
- command_print(cmd_ctx, "target must be halted to set watchpoints");
- break;
- case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
- command_print(cmd_ctx, "no more watchpoints available");
- break;
- default:
- command_print(cmd_ctx, "unknown error, watchpoint not set");
- break;
- }
- }
- }
- else
- {
- command_print(cmd_ctx, "usage: wp <address> <length> [r/w/a] [value] [mask]");
- }
-
- return ERROR_OK;
-}
-
-int handle_rwp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
-
- if (argc > 0)
- watchpoint_remove(target, strtoul(args[0], NULL, 0));
-
- return ERROR_OK;
-}
-
-int handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
-{
- int retval;
- target_t *target = get_current_target(cmd_ctx);
- u32 va;
- u32 pa;
-
- if (argc != 1)
- {
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
- va = strtoul(args[0], NULL, 0);
-
- retval = target->type->virt2phys(target, va, &pa);
- if (retval == ERROR_OK)
- {
- command_print(cmd_ctx, "Physical address 0x%08x", pa);
- }
- else
- {
- /* lower levels will have logged a detailed error which is
- * forwarded to telnet/GDB session.
- */
- }
- return retval;
-}
+/*************************************************************************** + * 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 "target.h" +#include "target_request.h" + +#include "log.h" +#include "configuration.h" +#include "binarybuffer.h" +#include "jtag.h" + +#include <string.h> +#include <stdlib.h> +#include <inttypes.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> + +#include <sys/time.h> +#include <time.h> + +#include <time_support.h> + +#include <fileio.h> +#include <image.h> + +int cli_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv); + + +int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int handle_target_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_run_and_halt_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_soft_reset_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_step_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_verify_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_bp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_rbp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_rwp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc); + +/* targets + */ +extern target_type_t arm7tdmi_target; +extern target_type_t arm720t_target; +extern target_type_t arm9tdmi_target; +extern target_type_t arm920t_target; +extern target_type_t arm966e_target; +extern target_type_t arm926ejs_target; +extern target_type_t feroceon_target; +extern target_type_t xscale_target; +extern target_type_t cortexm3_target; + +target_type_t *target_types[] = +{ + &arm7tdmi_target, + &arm9tdmi_target, + &arm920t_target, + &arm720t_target, + &arm966e_target, + &arm926ejs_target, + &feroceon_target, + &xscale_target, + &cortexm3_target, + NULL, +}; + +target_t *targets = NULL; +target_event_callback_t *target_event_callbacks = NULL; +target_timer_callback_t *target_timer_callbacks = NULL; + +char *target_state_strings[] = +{ + "unknown", + "running", + "halted", + "reset", + "debug_running", +}; + +char *target_debug_reason_strings[] = +{ + "debug request", "breakpoint", "watchpoint", + "watchpoint and breakpoint", "single step", + "target not halted" +}; + +char *target_endianess_strings[] = +{ + "big endian", + "little endian", +}; + +enum daemon_startup_mode startup_mode = DAEMON_ATTACH; + +static int target_continous_poll = 1; + +/* read a u32 from a buffer in target memory endianness */ +u32 target_buffer_get_u32(target_t *target, u8 *buffer) +{ + if (target->endianness == TARGET_LITTLE_ENDIAN) + return le_to_h_u32(buffer); + else + return be_to_h_u32(buffer); +} + +/* read a u16 from a buffer in target memory endianness */ +u16 target_buffer_get_u16(target_t *target, u8 *buffer) +{ + if (target->endianness == TARGET_LITTLE_ENDIAN) + return le_to_h_u16(buffer); + else + return be_to_h_u16(buffer); +} + +/* write a u32 to a buffer in target memory endianness */ +void target_buffer_set_u32(target_t *target, u8 *buffer, u32 value) +{ + if (target->endianness == TARGET_LITTLE_ENDIAN) + h_u32_to_le(buffer, value); + else + h_u32_to_be(buffer, value); +} + +/* write a u16 to a buffer in target memory endianness */ +void target_buffer_set_u16(target_t *target, u8 *buffer, u16 value) +{ + if (target->endianness == TARGET_LITTLE_ENDIAN) + h_u16_to_le(buffer, value); + else + h_u16_to_be(buffer, value); +} + +/* returns a pointer to the n-th configured target */ +target_t* get_target_by_num(int num) +{ + target_t *target = targets; + int i = 0; + + while (target) + { + if (num == i) + return target; + target = target->next; + i++; + } + + return NULL; +} + +int get_num_by_target(target_t *query_target) +{ + target_t *target = targets; + int i = 0; + + while (target) + { + if (target == query_target) + return i; + target = target->next; + i++; + } + + return -1; +} + +target_t* get_current_target(command_context_t *cmd_ctx) +{ + target_t *target = get_target_by_num(cmd_ctx->current_target); + + if (target == NULL) + { + ERROR("BUG: current_target out of bounds"); + exit(-1); + } + + return target; +} + +/* Process target initialization, when target entered debug out of reset + * the handler is unregistered at the end of this function, so it's only called once + */ +int target_init_handler(struct target_s *target, enum target_event event, void *priv) +{ + FILE *script; + struct command_context_s *cmd_ctx = priv; + + if ((event == TARGET_EVENT_HALTED) && (target->reset_script)) + { + target_unregister_event_callback(target_init_handler, priv); + + script = open_file_from_path(cmd_ctx, target->reset_script, "r"); + if (!script) + { + ERROR("couldn't open script file %s", target->reset_script); + return ERROR_OK; + } + + INFO("executing reset script '%s'", target->reset_script); + command_run_file(cmd_ctx, script, COMMAND_EXEC); + fclose(script); + + jtag_execute_queue(); + } + + return ERROR_OK; +} + +int target_run_and_halt_handler(void *priv) +{ + target_t *target = priv; + + target->type->halt(target); + + return ERROR_OK; +} + +int target_process_reset(struct command_context_s *cmd_ctx) +{ + int retval = ERROR_OK; + target_t *target; + struct timeval timeout, now; + + /* prepare reset_halt where necessary */ + target = targets; + while (target) + { + if (jtag_reset_config & RESET_SRST_PULLS_TRST) + { + switch (target->reset_mode) + { + case RESET_HALT: + command_print(cmd_ctx, "nSRST pulls nTRST, falling back to RESET_RUN_AND_HALT"); + target->reset_mode = RESET_RUN_AND_HALT; + break; + case RESET_INIT: + command_print(cmd_ctx, "nSRST pulls nTRST, falling back to RESET_RUN_AND_INIT"); + target->reset_mode = RESET_RUN_AND_INIT; + break; + default: + break; + } + } + switch (target->reset_mode) + { + case RESET_HALT: + case RESET_INIT: + target->type->prepare_reset_halt(target); + break; + default: + break; + } + target = target->next; + } + + target = targets; + while (target) + { + target->type->assert_reset(target); + target = target->next; + } + jtag_execute_queue(); + + /* request target halt if necessary, and schedule further action */ + target = targets; + while (target) + { + switch (target->reset_mode) + { + case RESET_RUN: + /* nothing to do if target just wants to be run */ + break; + case RESET_RUN_AND_HALT: + /* schedule halt */ + target_register_timer_callback(target_run_and_halt_handler, target->run_and_halt_time, 0, target); + break; + case RESET_RUN_AND_INIT: + /* schedule halt */ + target_register_timer_callback(target_run_and_halt_handler, target->run_and_halt_time, 0, target); + target_register_event_callback(target_init_handler, cmd_ctx); + break; + case RESET_HALT: + target->type->halt(target); + break; + case RESET_INIT: + target->type->halt(target); + target_register_event_callback(target_init_handler, cmd_ctx); + break; + default: + ERROR("BUG: unknown target->reset_mode"); + } + target = target->next; + } + + target = targets; + while (target) + { + target->type->deassert_reset(target); + target = target->next; + } + jtag_execute_queue(); + + /* Wait for reset to complete, maximum 5 seconds. */ + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, 5, 0); + for(;;) + { + gettimeofday(&now, NULL); + + target_call_timer_callbacks(); + + target = targets; + while (target) + { + target->type->poll(target); + if ((target->reset_mode == RESET_RUN_AND_INIT) || (target->reset_mode == RESET_RUN_AND_HALT)) + { + if (target->state != TARGET_HALTED) + { + if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) + { + command_print(cmd_ctx, "Timed out waiting for reset"); + goto done; + } + usleep(100*1000); /* Do not eat all cpu */ + goto again; + } + } + target = target->next; + } + /* All targets we're waiting for are halted */ + break; + + again:; + } + done: + + + /* We want any events to be processed before the prompt */ + target_call_timer_callbacks(); + + return retval; +} + +static int default_virt2phys(struct target_s *target, u32 virtual, u32 *physical) +{ + *physical = virtual; + return ERROR_OK; +} + +static int default_mmu(struct target_s *target, int *enabled) +{ + *enabled = 0; + return ERROR_OK; +} + +int target_init(struct command_context_s *cmd_ctx) +{ + target_t *target = targets; + + while (target) + { + if (target->type->init_target(cmd_ctx, target) != ERROR_OK) + { + ERROR("target '%s' init failed", target->type->name); + exit(-1); + } + + /* Set up default functions if none are provided by target */ + if (target->type->virt2phys == NULL) + { + target->type->virt2phys = default_virt2phys; + } + if (target->type->mmu == NULL) + { + target->type->mmu = default_mmu; + } + target = target->next; + } + + if (targets) + { + target_register_user_commands(cmd_ctx); + target_register_timer_callback(handle_target, 100, 1, NULL); + } + + return ERROR_OK; +} + +int target_init_reset(struct command_context_s *cmd_ctx) +{ + if (startup_mode == DAEMON_RESET) + target_process_reset(cmd_ctx); + + return ERROR_OK; +} + +int target_register_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv) +{ + target_event_callback_t **callbacks_p = &target_event_callbacks; + + if (callback == NULL) + { + return ERROR_INVALID_ARGUMENTS; + } + + if (*callbacks_p) + { + while ((*callbacks_p)->next) + callbacks_p = &((*callbacks_p)->next); + callbacks_p = &((*callbacks_p)->next); + } + + (*callbacks_p) = malloc(sizeof(target_event_callback_t)); + (*callbacks_p)->callback = callback; + (*callbacks_p)->priv = priv; + (*callbacks_p)->next = NULL; + + return ERROR_OK; +} + +int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv) +{ + target_timer_callback_t **callbacks_p = &target_timer_callbacks; + struct timeval now; + + if (callback == NULL) + { + return ERROR_INVALID_ARGUMENTS; + } + + if (*callbacks_p) + { + while ((*callbacks_p)->next) + callbacks_p = &((*callbacks_p)->next); + callbacks_p = &((*callbacks_p)->next); + } + + (*callbacks_p) = malloc(sizeof(target_timer_callback_t)); + (*callbacks_p)->callback = callback; + (*callbacks_p)->periodic = periodic; + (*callbacks_p)->time_ms = time_ms; + + gettimeofday(&now, NULL); + (*callbacks_p)->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000; + time_ms -= (time_ms % 1000); + (*callbacks_p)->when.tv_sec = now.tv_sec + (time_ms / 1000); + if ((*callbacks_p)->when.tv_usec > 1000000) + { + (*callbacks_p)->when.tv_usec = (*callbacks_p)->when.tv_usec - 1000000; + (*callbacks_p)->when.tv_sec += 1; + } + + (*callbacks_p)->priv = priv; + (*callbacks_p)->next = NULL; + + return ERROR_OK; +} + +int target_unregister_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv) +{ + target_event_callback_t **p = &target_event_callbacks; + target_event_callback_t *c = target_event_callbacks; + + if (callback == NULL) + { + return ERROR_INVALID_ARGUMENTS; + } + + while (c) + { + target_event_callback_t *next = c->next; + if ((c->callback == callback) && (c->priv == priv)) + { + *p = next; + free(c); + return ERROR_OK; + } + else + p = &(c->next); + c = next; + } + + return ERROR_OK; +} + +int target_unregister_timer_callback(int (*callback)(void *priv), void *priv) +{ + target_timer_callback_t **p = &target_timer_callbacks; + target_timer_callback_t *c = target_timer_callbacks; + + if (callback == NULL) + { + return ERROR_INVALID_ARGUMENTS; + } + + while (c) + { + target_timer_callback_t *next = c->next; + if ((c->callback == callback) && (c->priv == priv)) + { + *p = next; + free(c); + return ERROR_OK; + } + else + p = &(c->next); + c = next; + } + + return ERROR_OK; +} + +int target_call_event_callbacks(target_t *target, enum target_event event) +{ + target_event_callback_t *callback = target_event_callbacks; + target_event_callback_t *next_callback; + + DEBUG("target event %i", event); + + while (callback) + { + next_callback = callback->next; + callback->callback(target, event, callback->priv); + callback = next_callback; + } + + return ERROR_OK; +} + +int target_call_timer_callbacks() +{ + target_timer_callback_t *callback = target_timer_callbacks; + target_timer_callback_t *next_callback; + struct timeval now; + + gettimeofday(&now, NULL); + + while (callback) + { + next_callback = callback->next; + + if (((now.tv_sec >= callback->when.tv_sec) && (now.tv_usec >= callback->when.tv_usec)) + || (now.tv_sec > callback->when.tv_sec)) + { + callback->callback(callback->priv); + if (callback->periodic) + { + int time_ms = callback->time_ms; + callback->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000; + time_ms -= (time_ms % 1000); + callback->when.tv_sec = now.tv_sec + time_ms / 1000; + if (callback->when.tv_usec > 1000000) + { + callback->when.tv_usec = callback->when.tv_usec - 1000000; + callback->when.tv_sec += 1; + } + } + else + target_unregister_timer_callback(callback->callback, callback->priv); + } + + callback = next_callback; + } + + return ERROR_OK; +} + +int target_alloc_working_area(struct target_s *target, u32 size, working_area_t **area) +{ + working_area_t *c = target->working_areas; + working_area_t *new_wa = NULL; + + /* Reevaluate working area address based on MMU state*/ + if (target->working_areas == NULL) + { + int retval; + int enabled; + retval = target->type->mmu(target, &enabled); + if (retval != ERROR_OK) + { + return retval; + } + if (enabled) + { + target->working_area = target->working_area_virt; + } + else + { + target->working_area = target->working_area_phys; + } + } + + /* only allocate multiples of 4 byte */ + if (size % 4) + { + ERROR("BUG: code tried to allocate unaligned number of bytes, padding"); + size = CEIL(size, 4); + } + + /* see if there's already a matching working area */ + while (c) + { + if ((c->free) && (c->size == size)) + { + new_wa = c; + break; + } + c = c->next; + } + + /* if not, allocate a new one */ + if (!new_wa) + { + working_area_t **p = &target->working_areas; + u32 first_free = target->working_area; + u32 free_size = target->working_area_size; + + DEBUG("allocating new working area"); + + c = target->working_areas; + while (c) + { + first_free += c->size; + free_size -= c->size; + p = &c->next; + c = c->next; + } + + if (free_size < size) + { + WARNING("not enough working area available(requested %d, free %d)", size, free_size); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + new_wa = malloc(sizeof(working_area_t)); + new_wa->next = NULL; + new_wa->size = size; + new_wa->address = first_free; + + if (target->backup_working_area) + { + new_wa->backup = malloc(new_wa->size); + target->type->read_memory(target, new_wa->address, 4, new_wa->size / 4, new_wa->backup); + } + else + { + new_wa->backup = NULL; + } + + /* put new entry in list */ + *p = new_wa; + } + + /* mark as used, and return the new (reused) area */ + new_wa->free = 0; + *area = new_wa; + + /* user pointer */ + new_wa->user = area; + + return ERROR_OK; +} + +int target_free_working_area(struct target_s *target, working_area_t *area) +{ + if (area->free) + return ERROR_OK; + + if (target->backup_working_area) + target->type->write_memory(target, area->address, 4, area->size / 4, area->backup); + + area->free = 1; + + /* mark user pointer invalid */ + *area->user = NULL; + area->user = NULL; + + return ERROR_OK; +} + +int target_free_all_working_areas(struct target_s *target) +{ + working_area_t *c = target->working_areas; + + while (c) + { + working_area_t *next = c->next; + target_free_working_area(target, c); + + if (c->backup) + free(c->backup); + + free(c); + + c = next; + } + + target->working_areas = NULL; + + return ERROR_OK; +} + +int target_register_commands(struct command_context_s *cmd_ctx) +{ + register_command(cmd_ctx, NULL, "target", handle_target_command, COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "targets", handle_targets_command, COMMAND_EXEC, NULL); + register_command(cmd_ctx, NULL, "daemon_startup", handle_daemon_startup_command, COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "target_script", handle_target_script_command, COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "run_and_halt_time", handle_run_and_halt_time_command, COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "working_area", handle_working_area_command, COMMAND_ANY, "working_area <target#> <address> <size> <'backup'|'nobackup'> [virtual address]"); + register_command(cmd_ctx, NULL, "virt2phys", handle_virt2phys_command, COMMAND_ANY, "virt2phys <virtual address>"); + + return ERROR_OK; +} + +int target_arch_state(struct target_s *target) +{ + int retval; + if (target==NULL) + { + USER("No target has been configured"); + return ERROR_OK; + } + + USER("target state: %s", target_state_strings[target->state]); + + if (target->state!=TARGET_HALTED) + return ERROR_OK; + + retval=target->type->arch_state(target); + return retval; +} + +/* Single aligned words are guaranteed to use 16 or 32 bit access + * mode respectively, otherwise data is handled as quickly as + * possible + */ +int target_write_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer) +{ + int retval; + + DEBUG("writing buffer of %i byte at 0x%8.8x", size, address); + + if (((address % 2) == 0) && (size == 2)) + { + return target->type->write_memory(target, address, 2, 1, buffer); + } + + /* handle unaligned head bytes */ + if (address % 4) + { + int unaligned = 4 - (address % 4); + + if (unaligned > size) + unaligned = size; + + if ((retval = target->type->write_memory(target, address, 1, unaligned, buffer)) != ERROR_OK) + return retval; + + buffer += unaligned; + address += unaligned; + size -= unaligned; + } + + /* handle aligned words */ + if (size >= 4) + { + int aligned = size - (size % 4); + + /* use bulk writes above a certain limit. This may have to be changed */ + if (aligned > 128) + { + if ((retval = target->type->bulk_write_memory(target, address, aligned / 4, buffer)) != ERROR_OK) + return retval; + } + else + { + if ((retval = target->type->write_memory(target, address, 4, aligned / 4, buffer)) != ERROR_OK) + return retval; + } + + buffer += aligned; + address += aligned; + size -= aligned; + } + + /* handle tail writes of less than 4 bytes */ + if (size > 0) + { + if ((retval = target->type->write_memory(target, address, 1, size, buffer)) != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + + +/* Single aligned words are guaranteed to use 16 or 32 bit access + * mode respectively, otherwise data is handled as quickly as + * possible + */ +int target_read_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer) +{ + int retval; + + DEBUG("reading buffer of %i byte at 0x%8.8x", size, address); + + if (((address % 2) == 0) && (size == 2)) + { + return target->type->read_memory(target, address, 2, 1, buffer); + } + + /* handle unaligned head bytes */ + if (address % 4) + { + int unaligned = 4 - (address % 4); + + if (unaligned > size) + unaligned = size; + + if ((retval = target->type->read_memory(target, address, 1, unaligned, buffer)) != ERROR_OK) + return retval; + + buffer += unaligned; + address += unaligned; + size -= unaligned; + } + + /* handle aligned words */ + if (size >= 4) + { + int aligned = size - (size % 4); + + if ((retval = target->type->read_memory(target, address, 4, aligned / 4, buffer)) != ERROR_OK) + return retval; + + buffer += aligned; + address += aligned; + size -= aligned; + } + + /* handle tail writes of less than 4 bytes */ + if (size > 0) + { + if ((retval = target->type->read_memory(target, address, 1, size, buffer)) != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + +int target_checksum_memory(struct target_s *target, u32 address, u32 size, u32* crc) +{ + u8 *buffer; + int retval; + int i; + u32 checksum = 0; + + if ((retval = target->type->checksum_memory(target, address, + size, &checksum)) == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + { + buffer = malloc(size); + if (buffer == NULL) + { + ERROR("error allocating buffer for section (%d bytes)", size); + return ERROR_INVALID_ARGUMENTS; + } + retval = target_read_buffer(target, address, size, buffer); + if (retval != ERROR_OK) + { + free(buffer); + return retval; + } + + /* convert to target endianess */ + for (i = 0; i < (size/sizeof(u32)); i++) + { + u32 target_data; + target_data = target_buffer_get_u32(target, &buffer[i*sizeof(u32)]); + target_buffer_set_u32(target, &buffer[i*sizeof(u32)], target_data); + } + + retval = image_calculate_checksum( buffer, size, &checksum ); + free(buffer); + } + + *crc = checksum; + + return retval; +} + +int target_read_u32(struct target_s *target, u32 address, u32 *value) +{ + u8 value_buf[4]; + + int retval = target->type->read_memory(target, address, 4, 1, value_buf); + + if (retval == ERROR_OK) + { + *value = target_buffer_get_u32(target, value_buf); + DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, *value); + } + else + { + *value = 0x0; + DEBUG("address: 0x%8.8x failed", address); + } + + return retval; +} + +int target_read_u16(struct target_s *target, u32 address, u16 *value) +{ + u8 value_buf[2]; + + int retval = target->type->read_memory(target, address, 2, 1, value_buf); + + if (retval == ERROR_OK) + { + *value = target_buffer_get_u16(target, value_buf); + DEBUG("address: 0x%8.8x, value: 0x%4.4x", address, *value); + } + else + { + *value = 0x0; + DEBUG("address: 0x%8.8x failed", address); + } + + return retval; +} + +int target_read_u8(struct target_s *target, u32 address, u8 *value) +{ + int retval = target->type->read_memory(target, address, 1, 1, value); + + if (retval == ERROR_OK) + { + DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, *value); + } + else + { + *value = 0x0; + DEBUG("address: 0x%8.8x failed", address); + } + + return retval; +} + +int target_write_u32(struct target_s *target, u32 address, u32 value) +{ + int retval; + u8 value_buf[4]; + + DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, value); + + target_buffer_set_u32(target, value_buf, value); + if ((retval = target->type->write_memory(target, address, 4, 1, value_buf)) != ERROR_OK) + { + DEBUG("failed: %i", retval); + } + + return retval; +} + +int target_write_u16(struct target_s *target, u32 address, u16 value) +{ + int retval; + u8 value_buf[2]; + + DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, value); + + target_buffer_set_u16(target, value_buf, value); + if ((retval = target->type->write_memory(target, address, 2, 1, value_buf)) != ERROR_OK) + { + DEBUG("failed: %i", retval); + } + + return retval; +} + +int target_write_u8(struct target_s *target, u32 address, u8 value) +{ + int retval; + + DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, value); + + if ((retval = target->type->read_memory(target, address, 1, 1, &value)) != ERROR_OK) + { + DEBUG("failed: %i", retval); + } + + return retval; +} + +int target_register_user_commands(struct command_context_s *cmd_ctx) +{ + register_command(cmd_ctx, NULL, "reg", handle_reg_command, COMMAND_EXEC, NULL); + register_command(cmd_ctx, NULL, "poll", handle_poll_command, COMMAND_EXEC, "poll target state"); + register_command(cmd_ctx, NULL, "wait_halt", handle_wait_halt_command, COMMAND_EXEC, "wait for target halt [time (s)]"); + register_command(cmd_ctx, NULL, "halt", handle_halt_command, COMMAND_EXEC, "halt target"); + register_command(cmd_ctx, NULL, "resume", handle_resume_command, COMMAND_EXEC, "resume target [addr]"); + register_command(cmd_ctx, NULL, "step", handle_step_command, COMMAND_EXEC, "step one instruction from current PC or [addr]"); + register_command(cmd_ctx, NULL, "reset", handle_reset_command, COMMAND_EXEC, "reset target [run|halt|init|run_and_halt|run_and_init]"); + register_command(cmd_ctx, NULL, "soft_reset_halt", handle_soft_reset_halt_command, COMMAND_EXEC, "halt the target and do a soft reset"); + + register_command(cmd_ctx, NULL, "mdw", handle_md_command, COMMAND_EXEC, "display memory words <addr> [count]"); + register_command(cmd_ctx, NULL, "mdh", handle_md_command, COMMAND_EXEC, "display memory half-words <addr> [count]"); + register_command(cmd_ctx, NULL, "mdb", handle_md_command, COMMAND_EXEC, "display memory bytes <addr> [count]"); + + register_command(cmd_ctx, NULL, "mww", handle_mw_command, COMMAND_EXEC, "write memory word <addr> <value>"); + register_command(cmd_ctx, NULL, "mwh", handle_mw_command, COMMAND_EXEC, "write memory half-word <addr> <value>"); + register_command(cmd_ctx, NULL, "mwb", handle_mw_command, COMMAND_EXEC, "write memory byte <addr> <value>"); + + register_command(cmd_ctx, NULL, "bp", handle_bp_command, COMMAND_EXEC, "set breakpoint <address> <length> [hw]"); + register_command(cmd_ctx, NULL, "rbp", handle_rbp_command, COMMAND_EXEC, "remove breakpoint <adress>"); + register_command(cmd_ctx, NULL, "wp", handle_wp_command, COMMAND_EXEC, "set watchpoint <address> <length> <r/w/a> [value] [mask]"); + register_command(cmd_ctx, NULL, "rwp", handle_rwp_command, COMMAND_EXEC, "remove watchpoint <adress>"); + + register_command(cmd_ctx, NULL, "load_image", handle_load_image_command, COMMAND_EXEC, "load_image <file> <address> ['bin'|'ihex'|'elf'|'s19']"); + register_command(cmd_ctx, NULL, "dump_image", handle_dump_image_command, COMMAND_EXEC, "dump_image <file> <address> <size>"); + register_command(cmd_ctx, NULL, "verify_image", handle_verify_image_command, COMMAND_EXEC, "verify_image <file> [offset] [type]"); + register_command(cmd_ctx, NULL, "load_binary", handle_load_image_command, COMMAND_EXEC, "[DEPRECATED] load_binary <file> <address>"); + register_command(cmd_ctx, NULL, "dump_binary", handle_dump_image_command, COMMAND_EXEC, "[DEPRECATED] dump_binary <file> <address> <size>"); + + target_request_register_commands(cmd_ctx); + trace_register_commands(cmd_ctx); + + return ERROR_OK; +} + +int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = targets; + int count = 0; + + if (argc == 1) + { + int num = strtoul(args[0], NULL, 0); + + while (target) + { + count++; + target = target->next; + } + + if (num < count) + cmd_ctx->current_target = num; + else + command_print(cmd_ctx, "%i is out of bounds, only %i targets are configured", num, count); + + return ERROR_OK; + } + + while (target) + { + command_print(cmd_ctx, "%i: %s (%s), state: %s", count++, target->type->name, target_endianess_strings[target->endianness], target_state_strings[target->state]); + target = target->next; + } + + return ERROR_OK; +} + +int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int i; + int found = 0; + + if (argc < 3) + { + ERROR("target command requires at least three arguments: <type> <endianess> <reset_mode>"); + exit(-1); + } + + /* search for the specified target */ + if (args[0] && (args[0][0] != 0)) + { + for (i = 0; target_types[i]; i++) + { + if (strcmp(args[0], target_types[i]->name) == 0) + { + target_t **last_target_p = &targets; + + /* register target specific commands */ + if (target_types[i]->register_commands(cmd_ctx) != ERROR_OK) + { + ERROR("couldn't register '%s' commands", args[0]); + exit(-1); + } + + if (*last_target_p) + { + while ((*last_target_p)->next) + last_target_p = &((*last_target_p)->next); + last_target_p = &((*last_target_p)->next); + } + + *last_target_p = malloc(sizeof(target_t)); + + (*last_target_p)->type = target_types[i]; + + if (strcmp(args[1], "big") == 0) + (*last_target_p)->endianness = TARGET_BIG_ENDIAN; + else if (strcmp(args[1], "little") == 0) + (*last_target_p)->endianness = TARGET_LITTLE_ENDIAN; + else + { + ERROR("endianness must be either 'little' or 'big', not '%s'", args[1]); + exit(-1); + } + + /* what to do on a target reset */ + if (strcmp(args[2], "reset_halt") == 0) + (*last_target_p)->reset_mode = RESET_HALT; + else if (strcmp(args[2], "reset_run") == 0) + (*last_target_p)->reset_mode = RESET_RUN; + else if (strcmp(args[2], "reset_init") == 0) + (*last_target_p)->reset_mode = RESET_INIT; + else if (strcmp(args[2], "run_and_halt") == 0) + (*last_target_p)->reset_mode = RESET_RUN_AND_HALT; + else if (strcmp(args[2], "run_and_init") == 0) + (*last_target_p)->reset_mode = RESET_RUN_AND_INIT; + else + { + ERROR("unknown target startup mode %s", args[2]); + exit(-1); + } + (*last_target_p)->run_and_halt_time = 1000; /* default 1s */ + + (*last_target_p)->reset_script = NULL; + (*last_target_p)->post_halt_script = NULL; + (*last_target_p)->pre_resume_script = NULL; + (*last_target_p)->gdb_program_script = NULL; + + (*last_target_p)->working_area = 0x0; + (*last_target_p)->working_area_size = 0x0; + (*last_target_p)->working_areas = NULL; + (*last_target_p)->backup_working_area = 0; + + (*last_target_p)->state = TARGET_UNKNOWN; + (*last_target_p)->reg_cache = NULL; + (*last_target_p)->breakpoints = NULL; + (*last_target_p)->watchpoints = NULL; + (*last_target_p)->next = NULL; + (*last_target_p)->arch_info = NULL; + + /* initialize trace information */ + (*last_target_p)->trace_info = malloc(sizeof(trace_t)); + (*last_target_p)->trace_info->num_trace_points = 0; + (*last_target_p)->trace_info->trace_points_size = 0; + (*last_target_p)->trace_info->trace_points = NULL; + (*last_target_p)->trace_info->trace_history_size = 0; + (*last_target_p)->trace_info->trace_history = NULL; + (*last_target_p)->trace_info->trace_history_pos = 0; + (*last_target_p)->trace_info->trace_history_overflowed = 0; + + (*last_target_p)->dbgmsg = NULL; + (*last_target_p)->dbg_msg_enabled = 0; + + (*last_target_p)->type->target_command(cmd_ctx, cmd, args, argc, *last_target_p); + + found = 1; + break; + } + } + } + + /* no matching target found */ + if (!found) + { + ERROR("target '%s' not found", args[0]); + exit(-1); + } + + return ERROR_OK; +} + +/* usage: target_script <target#> <event> <script_file> */ +int handle_target_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = NULL; + + if (argc < 3) + { + ERROR("incomplete target_script command"); + exit(-1); + } + + target = get_target_by_num(strtoul(args[0], NULL, 0)); + + if (!target) + { + ERROR("target number '%s' not defined", args[0]); + exit(-1); + } + + if (strcmp(args[1], "reset") == 0) + { + if (target->reset_script) + free(target->reset_script); + target->reset_script = strdup(args[2]); + } + else if (strcmp(args[1], "post_halt") == 0) + { + if (target->post_halt_script) + free(target->post_halt_script); + target->post_halt_script = strdup(args[2]); + } + else if (strcmp(args[1], "pre_resume") == 0) + { + if (target->pre_resume_script) + free(target->pre_resume_script); + target->pre_resume_script = strdup(args[2]); + } + else if (strcmp(args[1], "gdb_program_config") == 0) + { + if (target->gdb_program_script) + free(target->gdb_program_script); + target->gdb_program_script = strdup(args[2]); + } + else + { + ERROR("unknown event type: '%s", args[1]); + exit(-1); + } + + return ERROR_OK; +} + +int handle_run_and_halt_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = NULL; + + if (argc < 2) + { + ERROR("incomplete run_and_halt_time command"); + exit(-1); + } + + target = get_target_by_num(strtoul(args[0], NULL, 0)); + + if (!target) + { + ERROR("target number '%s' not defined", args[0]); + exit(-1); + } + + target->run_and_halt_time = strtoul(args[1], NULL, 0); + + return ERROR_OK; +} + +int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = NULL; + + if ((argc < 4) || (argc > 5)) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + target = get_target_by_num(strtoul(args[0], NULL, 0)); + + if (!target) + { + ERROR("target number '%s' not defined", args[0]); + exit(-1); + } + target_free_all_working_areas(target); + + target->working_area_phys = target->working_area_virt = strtoul(args[1], NULL, 0); + if (argc == 5) + { + target->working_area_virt = strtoul(args[4], NULL, 0); + } + target->working_area_size = strtoul(args[2], NULL, 0); + + if (strcmp(args[3], "backup") == 0) + { + target->backup_working_area = 1; + } + else if (strcmp(args[3], "nobackup") == 0) + { + target->backup_working_area = 0; + } + else + { + ERROR("unrecognized <backup|nobackup> argument (%s)", args[3]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + return ERROR_OK; +} + + +/* process target state changes */ +int handle_target(void *priv) +{ + int retval; + target_t *target = targets; + + while (target) + { + /* only poll if target isn't already halted */ + if (target->state != TARGET_HALTED) + { + if (target_continous_poll) + if ((retval = target->type->poll(target)) != ERROR_OK) + { + ERROR("couldn't poll target(%d). It's due for a reset.", retval); + } + } + + target = target->next; + } + + return ERROR_OK; +} + +int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + reg_t *reg = NULL; + int count = 0; + char *value; + + DEBUG("-"); + + target = get_current_target(cmd_ctx); + + /* list all available registers for the current target */ + if (argc == 0) + { + reg_cache_t *cache = target->reg_cache; + + count = 0; + while(cache) + { + int i; + for (i = 0; i < cache->num_regs; i++) + { + 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); + } + cache = cache->next; + } + + return ERROR_OK; + } + + /* access a single register by its ordinal number */ + if ((args[0][0] >= '0') && (args[0][0] <= '9')) + { + int num = strtoul(args[0], NULL, 0); + reg_cache_t *cache = target->reg_cache; + + count = 0; + while(cache) + { + int i; + for (i = 0; i < cache->num_regs; i++) + { + if (count++ == num) + { + reg = &cache->reg_list[i]; + break; + } + } + if (reg) + break; + cache = cache->next; + } + + if (!reg) + { + command_print(cmd_ctx, "%i is out of bounds, the current target has only %i registers (0 - %i)", num, count, count - 1); + return ERROR_OK; + } + } else /* access a single register by its name */ + { + reg = register_get_by_name(target->reg_cache, args[0], 1); + + if (!reg) + { + command_print(cmd_ctx, "register %s not found in current target", args[0]); + return ERROR_OK; + } + } + + /* display a register */ + if ((argc == 1) || ((argc == 2) && !((args[1][0] >= '0') && (args[1][0] <= '9')))) + { + if ((argc == 2) && (strcmp(args[1], "force") == 0)) + reg->valid = 0; + + if (reg->valid == 0) + { + reg_arch_type_t *arch_type = register_get_arch_type(reg->arch_type); + if (arch_type == NULL) + { + ERROR("BUG: encountered unregistered arch type"); + return ERROR_OK; + } + arch_type->get(reg); + } + 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; + } + + /* set register value */ + if (argc == 2) + { + 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) + { + ERROR("BUG: encountered unregistered arch type"); + return ERROR_OK; + } + + 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; + } + + command_print(cmd_ctx, "usage: reg <#|name> [value]"); + + return ERROR_OK; +} + +static int wait_state(struct command_context_s *cmd_ctx, char *cmd, enum target_state state, int ms); + +int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + + if (argc == 0) + { + target->type->poll(target); + target_arch_state(target); + } + else + { + if (strcmp(args[0], "on") == 0) + { + target_continous_poll = 1; + } + else if (strcmp(args[0], "off") == 0) + { + target_continous_poll = 0; + } + else + { + command_print(cmd_ctx, "arg is \"on\" or \"off\""); + } + } + + + return ERROR_OK; +} + +int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int ms = 5000; + + if (argc > 0) + { + char *end; + + ms = strtoul(args[0], &end, 0) * 1000; + if (*end) + { + command_print(cmd_ctx, "usage: %s [seconds]", cmd); + return ERROR_OK; + } + } + + return wait_state(cmd_ctx, cmd, TARGET_HALTED, ms); +} + +static void target_process_events(struct command_context_s *cmd_ctx) +{ + target_t *target = get_current_target(cmd_ctx); + target->type->poll(target); + target_call_timer_callbacks(); +} + +static int wait_state(struct command_context_s *cmd_ctx, char *cmd, enum target_state state, int ms) +{ + int retval; + struct timeval timeout, now; + + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, 0, ms * 1000); + + target_t *target = get_current_target(cmd_ctx); + for (;;) + { + if ((retval=target->type->poll(target))!=ERROR_OK) + return retval; + target_call_timer_callbacks(); + if (target->state == state) + { + break; + } + command_print(cmd_ctx, "waiting for target %s...", target_state_strings[state]); + + gettimeofday(&now, NULL); + if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) + { + command_print(cmd_ctx, "timed out while waiting for target %s", target_state_strings[state]); + ERROR("timed out while waiting for target %s", target_state_strings[state]); + break; + } + } + + return ERROR_OK; +} + +int handle_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + + DEBUG("-"); + + command_print(cmd_ctx, "requesting target halt..."); + + if ((retval = target->type->halt(target)) != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_ALREADY_HALTED: + command_print(cmd_ctx, "target already halted"); + break; + case ERROR_TARGET_TIMEOUT: + command_print(cmd_ctx, "target timed out... shutting down"); + return retval; + default: + command_print(cmd_ctx, "unknown error... shutting down"); + return retval; + } + } + + return handle_wait_halt_command(cmd_ctx, cmd, args, argc); +} + +/* what to do on daemon startup */ +int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 1) + { + if (strcmp(args[0], "attach") == 0) + { + startup_mode = DAEMON_ATTACH; + return ERROR_OK; + } + else if (strcmp(args[0], "reset") == 0) + { + startup_mode = DAEMON_RESET; + return ERROR_OK; + } + } + + WARNING("invalid daemon_startup configuration directive: %s", args[0]); + return ERROR_OK; + +} + +int handle_soft_reset_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + int retval; + + command_print(cmd_ctx, "requesting target halt and executing a soft reset"); + + if ((retval = target->type->soft_reset_halt(target)) != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_TIMEOUT: + command_print(cmd_ctx, "target timed out... shutting down"); + exit(-1); + default: + command_print(cmd_ctx, "unknown error... shutting down"); + exit(-1); + } + } + + return ERROR_OK; +} + +int handle_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + enum target_reset_mode reset_mode = target->reset_mode; + enum target_reset_mode save = target->reset_mode; + + DEBUG("-"); + + if (argc >= 1) + { + if (strcmp("run", args[0]) == 0) + reset_mode = RESET_RUN; + else if (strcmp("halt", args[0]) == 0) + reset_mode = RESET_HALT; + else if (strcmp("init", args[0]) == 0) + reset_mode = RESET_INIT; + else if (strcmp("run_and_halt", args[0]) == 0) + { + reset_mode = RESET_RUN_AND_HALT; + if (argc >= 2) + { + target->run_and_halt_time = strtoul(args[1], NULL, 0); + } + } + else if (strcmp("run_and_init", args[0]) == 0) + { + reset_mode = RESET_RUN_AND_INIT; + if (argc >= 2) + { + target->run_and_halt_time = strtoul(args[1], NULL, 0); + } + } + else + { + command_print(cmd_ctx, "usage: reset ['run', 'halt', 'init', 'run_and_halt', 'run_and_init]"); + return ERROR_OK; + } + } + + /* temporarily modify mode of current reset target */ + target->reset_mode = reset_mode; + + /* reset *all* targets */ + target_process_reset(cmd_ctx); + + /* Restore default reset mode for this target */ + target->reset_mode = save; + + return ERROR_OK; +} + +int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + + if (argc == 0) + retval = target->type->resume(target, 1, 0, 1, 0); /* current pc, addr = 0, handle breakpoints, not debugging */ + else if (argc == 1) + retval = target->type->resume(target, 0, strtoul(args[0], NULL, 0), 1, 0); /* addr = args[0], handle breakpoints, not debugging */ + else + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + target_process_events(cmd_ctx); + + target_arch_state(target); + + return retval; +} + +int handle_step_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + + DEBUG("-"); + + if (argc == 0) + target->type->step(target, 1, 0, 1); /* current pc, addr = 0, handle breakpoints */ + + if (argc == 1) + target->type->step(target, 0, strtoul(args[0], NULL, 0), 1); /* addr = args[0], handle breakpoints */ + + return ERROR_OK; +} + +int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + const int line_bytecnt = 32; + int count = 1; + int size = 4; + u32 address = 0; + int line_modulo; + int i; + + char output[128]; + int output_len; + + int retval; + + u8 *buffer; + target_t *target = get_current_target(cmd_ctx); + + if (argc < 1) + return ERROR_OK; + + if (argc == 2) + count = strtoul(args[1], NULL, 0); + + address = strtoul(args[0], NULL, 0); + + + switch (cmd[2]) + { + case 'w': + size = 4; line_modulo = line_bytecnt / 4; + break; + case 'h': + size = 2; line_modulo = line_bytecnt / 2; + break; + case 'b': + size = 1; line_modulo = line_bytecnt / 1; + break; + default: + return ERROR_OK; + } + + buffer = calloc(count, size); + retval = target->type->read_memory(target, address, size, count, buffer); + if (retval != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_UNALIGNED_ACCESS: + command_print(cmd_ctx, "error: address not aligned"); + break; + case ERROR_TARGET_NOT_HALTED: + command_print(cmd_ctx, "error: target must be halted for memory accesses"); + break; + case ERROR_TARGET_DATA_ABORT: + command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted"); + break; + default: + command_print(cmd_ctx, "error: unknown error"); + break; + } + return ERROR_OK; + } + + output_len = 0; + + for (i = 0; i < count; i++) + { + if (i%line_modulo == 0) + output_len += snprintf(output + output_len, 128 - output_len, "0x%8.8x: ", address + (i*size)); + + switch (size) + { + case 4: + output_len += snprintf(output + output_len, 128 - output_len, "%8.8x ", target_buffer_get_u32(target, &buffer[i*4])); + break; + case 2: + output_len += snprintf(output + output_len, 128 - output_len, "%4.4x ", target_buffer_get_u16(target, &buffer[i*2])); + break; + case 1: + output_len += snprintf(output + output_len, 128 - output_len, "%2.2x ", buffer[i*1]); + break; + } + + if ((i%line_modulo == line_modulo-1) || (i == count - 1)) + { + command_print(cmd_ctx, output); + output_len = 0; + } + } + + free(buffer); + + return ERROR_OK; +} + +int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + u32 address = 0; + u32 value = 0; + int retval; + target_t *target = get_current_target(cmd_ctx); + u8 value_buf[4]; + + if (argc < 2) + return ERROR_OK; + + address = strtoul(args[0], NULL, 0); + value = strtoul(args[1], NULL, 0); + + switch (cmd[2]) + { + case 'w': + target_buffer_set_u32(target, value_buf, value); + retval = target->type->write_memory(target, address, 4, 1, value_buf); + break; + case 'h': + target_buffer_set_u16(target, value_buf, value); + retval = target->type->write_memory(target, address, 2, 1, value_buf); + break; + case 'b': + value_buf[0] = value; + retval = target->type->write_memory(target, address, 1, 1, value_buf); + break; + default: + return ERROR_OK; + } + + switch (retval) + { + case ERROR_TARGET_UNALIGNED_ACCESS: + command_print(cmd_ctx, "error: address not aligned"); + break; + case ERROR_TARGET_DATA_ABORT: + command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted"); + break; + case ERROR_TARGET_NOT_HALTED: + command_print(cmd_ctx, "error: target must be halted for memory accesses"); + break; + case ERROR_OK: + break; + default: + command_print(cmd_ctx, "error: unknown error"); + break; + } + + return ERROR_OK; + +} + +int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + u8 *buffer; + u32 buf_cnt; + u32 image_size; + int i; + int retval; + + image_t image; + + duration_t duration; + char *duration_text; + + target_t *target = get_current_target(cmd_ctx); + + if (argc < 1) + { + command_print(cmd_ctx, "usage: load_image <filename> [address] [type]"); + return ERROR_OK; + } + + /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ + if (argc >= 2) + { + image.base_address_set = 1; + image.base_address = strtoul(args[1], NULL, 0); + } + else + { + image.base_address_set = 0; + } + + image.start_address_set = 0; + + duration_start_measure(&duration); + + if (image_open(&image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK) + { + command_print(cmd_ctx, "load_image error: %s", image.error_str); + return ERROR_OK; + } + + image_size = 0x0; + for (i = 0; i < image.num_sections; i++) + { + buffer = malloc(image.sections[i].size); + if (buffer == NULL) + { + command_print(cmd_ctx, "error allocating buffer for section (%d bytes)", image.sections[i].size); + break; + } + + if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK) + { + ERROR("image_read_section failed with error code: %i", retval); + command_print(cmd_ctx, "image reading failed, download aborted"); + free(buffer); + image_close(&image); + return ERROR_OK; + } + target_write_buffer(target, image.sections[i].base_address, buf_cnt, buffer); + image_size += buf_cnt; + command_print(cmd_ctx, "%u byte written at address 0x%8.8x", buf_cnt, image.sections[i].base_address); + + free(buffer); + } + + duration_stop_measure(&duration, &duration_text); + command_print(cmd_ctx, "downloaded %u byte in %s", image_size, duration_text); + free(duration_text); + + image_close(&image); + + return ERROR_OK; + +} + +int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + fileio_t fileio; + + u32 address; + u32 size; + u8 buffer[560]; + int retval; + + duration_t duration; + char *duration_text; + + target_t *target = get_current_target(cmd_ctx); + + if (argc != 3) + { + command_print(cmd_ctx, "usage: dump_image <filename> <address> <size>"); + return ERROR_OK; + } + + address = strtoul(args[1], NULL, 0); + size = strtoul(args[2], NULL, 0); + + if ((address & 3) || (size & 3)) + { + command_print(cmd_ctx, "only 32-bit aligned address and size are supported"); + return ERROR_OK; + } + + if (fileio_open(&fileio, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) + { + command_print(cmd_ctx, "dump_image error: %s", fileio.error_str); + return ERROR_OK; + } + + duration_start_measure(&duration); + + while (size > 0) + { + u32 size_written; + u32 this_run_size = (size > 560) ? 560 : size; + + retval = target->type->read_memory(target, address, 4, this_run_size / 4, buffer); + if (retval != ERROR_OK) + { + command_print(cmd_ctx, "Reading memory failed %d", retval); + break; + } + + fileio_write(&fileio, this_run_size, buffer, &size_written); + + size -= this_run_size; + address += this_run_size; + } + + fileio_close(&fileio); + + duration_stop_measure(&duration, &duration_text); + command_print(cmd_ctx, "dumped %"PRIi64" byte in %s", fileio.size, duration_text); + free(duration_text); + + return ERROR_OK; +} + +int handle_verify_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + u8 *buffer; + u32 buf_cnt; + u32 image_size; + int i; + int retval; + u32 checksum = 0; + u32 mem_checksum = 0; + + image_t image; + + duration_t duration; + char *duration_text; + + target_t *target = get_current_target(cmd_ctx); + + if (argc < 1) + { + command_print(cmd_ctx, "usage: verify_image <file> [offset] [type]"); + return ERROR_OK; + } + + if (!target) + { + ERROR("no target selected"); + return ERROR_OK; + } + + duration_start_measure(&duration); + + if (argc >= 2) + { + image.base_address_set = 1; + image.base_address = strtoul(args[1], NULL, 0); + } + else + { + image.base_address_set = 0; + image.base_address = 0x0; + } + + image.start_address_set = 0; + + if (image_open(&image, args[0], (argc == 3) ? args[2] : NULL) != ERROR_OK) + { + command_print(cmd_ctx, "verify_image error: %s", image.error_str); + return ERROR_OK; + } + + image_size = 0x0; + for (i = 0; i < image.num_sections; i++) + { + buffer = malloc(image.sections[i].size); + if (buffer == NULL) + { + command_print(cmd_ctx, "error allocating buffer for section (%d bytes)", image.sections[i].size); + break; + } + if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK) + { + ERROR("image_read_section failed with error code: %i", retval); + command_print(cmd_ctx, "image reading failed, verify aborted"); + free(buffer); + image_close(&image); + return ERROR_OK; + } + + /* calculate checksum of image */ + image_calculate_checksum( buffer, buf_cnt, &checksum ); + + retval = target_checksum_memory(target, image.sections[i].base_address, buf_cnt, &mem_checksum); + + if( retval != ERROR_OK ) + { + command_print(cmd_ctx, "could not calculate checksum, verify aborted"); + free(buffer); + image_close(&image); + return ERROR_OK; + } + + if( checksum != mem_checksum ) + { + /* failed crc checksum, fall back to a binary compare */ + u8 *data; + + command_print(cmd_ctx, "checksum mismatch - attempting binary compare"); + + data = (u8*)malloc(buf_cnt); + + /* Can we use 32bit word accesses? */ + int size = 1; + int count = buf_cnt; + if ((count % 4) == 0) + { + size *= 4; + count /= 4; + } + retval = target->type->read_memory(target, image.sections[i].base_address, size, count, data); + + if (retval == ERROR_OK) + { + int t; + for (t = 0; t < buf_cnt; t++) + { + if (data[t] != buffer[t]) + { + command_print(cmd_ctx, "Verify operation failed address 0x%08x. Was 0x%02x instead of 0x%02x\n", t + image.sections[i].base_address, data[t], buffer[t]); + free(data); + free(buffer); + image_close(&image); + return ERROR_OK; + } + } + } + + free(data); + } + + free(buffer); + image_size += buf_cnt; + } + + duration_stop_measure(&duration, &duration_text); + command_print(cmd_ctx, "verified %u bytes in %s", image_size, duration_text); + free(duration_text); + + image_close(&image); + + return ERROR_OK; +} + +int handle_bp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + + if (argc == 0) + { + breakpoint_t *breakpoint = target->breakpoints; + + while (breakpoint) + { + if (breakpoint->type == BKPT_SOFT) + { + 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); + } + else + { + command_print(cmd_ctx, "0x%8.8x, 0x%x, %i", breakpoint->address, breakpoint->length, breakpoint->set); + } + breakpoint = breakpoint->next; + } + } + else if (argc >= 2) + { + int hw = BKPT_SOFT; + u32 length = 0; + + length = strtoul(args[1], NULL, 0); + + if (argc >= 3) + if (strcmp(args[2], "hw") == 0) + hw = BKPT_HARD; + + if ((retval = breakpoint_add(target, strtoul(args[0], NULL, 0), length, hw)) != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_NOT_HALTED: + command_print(cmd_ctx, "target must be halted to set breakpoints"); + break; + case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: + command_print(cmd_ctx, "no more breakpoints available"); + break; + default: + command_print(cmd_ctx, "unknown error, breakpoint not set"); + break; + } + } + else + { + command_print(cmd_ctx, "breakpoint added at address 0x%8.8x", strtoul(args[0], NULL, 0)); + } + } + else + { + command_print(cmd_ctx, "usage: bp <address> <length> ['hw']"); + } + + return ERROR_OK; +} + +int handle_rbp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + + if (argc > 0) + breakpoint_remove(target, strtoul(args[0], NULL, 0)); + + return ERROR_OK; +} + +int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + int retval; + + if (argc == 0) + { + watchpoint_t *watchpoint = target->watchpoints; + + while (watchpoint) + { + command_print(cmd_ctx, "address: 0x%8.8x, mask: 0x%8.8x, r/w/a: %i, value: 0x%8.8x, mask: 0x%8.8x", watchpoint->address, watchpoint->length, watchpoint->rw, watchpoint->value, watchpoint->mask); + watchpoint = watchpoint->next; + } + } + else if (argc >= 2) + { + enum watchpoint_rw type = WPT_ACCESS; + u32 data_value = 0x0; + u32 data_mask = 0xffffffff; + + if (argc >= 3) + { + switch(args[2][0]) + { + case 'r': + type = WPT_READ; + break; + case 'w': + type = WPT_WRITE; + break; + case 'a': + type = WPT_ACCESS; + break; + default: + command_print(cmd_ctx, "usage: wp <address> <length> [r/w/a] [value] [mask]"); + return ERROR_OK; + } + } + if (argc >= 4) + { + data_value = strtoul(args[3], NULL, 0); + } + if (argc >= 5) + { + data_mask = strtoul(args[4], NULL, 0); + } + + if ((retval = watchpoint_add(target, strtoul(args[0], NULL, 0), + strtoul(args[1], NULL, 0), type, data_value, data_mask)) != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_NOT_HALTED: + command_print(cmd_ctx, "target must be halted to set watchpoints"); + break; + case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: + command_print(cmd_ctx, "no more watchpoints available"); + break; + default: + command_print(cmd_ctx, "unknown error, watchpoint not set"); + break; + } + } + } + else + { + command_print(cmd_ctx, "usage: wp <address> <length> [r/w/a] [value] [mask]"); + } + + return ERROR_OK; +} + +int handle_rwp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + + if (argc > 0) + watchpoint_remove(target, strtoul(args[0], NULL, 0)); + + return ERROR_OK; +} + +int handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + u32 va; + u32 pa; + + if (argc != 1) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + va = strtoul(args[0], NULL, 0); + + retval = target->type->virt2phys(target, va, &pa); + if (retval == ERROR_OK) + { + command_print(cmd_ctx, "Physical address 0x%08x", pa); + } + else + { + /* lower levels will have logged a detailed error which is + * forwarded to telnet/GDB session. + */ + } + return retval; +} diff --git a/src/target/xscale.c b/src/target/xscale.c index 11ae5ee..b156e22 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -1,3799 +1,3799 @@ -/***************************************************************************
- * Copyright (C) 2006, 2007 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 "xscale.h"
-
-#include "register.h"
-#include "target.h"
-#include "armv4_5.h"
-#include "arm_simulator.h"
-#include "arm_disassembler.h"
-#include "log.h"
-#include "jtag.h"
-#include "binarybuffer.h"
-#include "time_support.h"
-#include "breakpoints.h"
-#include "fileio.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <errno.h>
-
-
-/* cli handling */
-int xscale_register_commands(struct command_context_s *cmd_ctx);
-
-/* forward declarations */
-int xscale_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target);
-int xscale_init_target(struct command_context_s *cmd_ctx, struct target_s *target);
-int xscale_quit();
-
-int xscale_arch_state(struct target_s *target);
-int xscale_poll(target_t *target);
-int xscale_halt(target_t *target);
-int xscale_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution);
-int xscale_step(struct target_s *target, int current, u32 address, int handle_breakpoints);
-int xscale_debug_entry(target_t *target);
-int xscale_restore_context(target_t *target);
-
-int xscale_assert_reset(target_t *target);
-int xscale_deassert_reset(target_t *target);
-int xscale_soft_reset_halt(struct target_s *target);
-int xscale_prepare_reset_halt(struct target_s *target);
-
-int xscale_set_reg_u32(reg_t *reg, u32 value);
-
-int xscale_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode);
-int xscale_write_core_reg(struct target_s *target, int num, enum armv4_5_mode mode, u32 value);
-
-int xscale_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
-int xscale_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer);
-int xscale_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer);
-int xscale_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum);
-
-int xscale_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint);
-int xscale_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint);
-int xscale_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint);
-int xscale_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint);
-int xscale_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint);
-int xscale_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint);
-void xscale_enable_watchpoints(struct target_s *target);
-void xscale_enable_breakpoints(struct target_s *target);
-static int xscale_virt2phys(struct target_s *target, u32 virtual, u32 *physical);
-static int xscale_mmu(struct target_s *target, int *enabled);
-
-int xscale_read_trace(target_t *target);
-
-target_type_t xscale_target =
-{
- .name = "xscale",
-
- .poll = xscale_poll,
- .arch_state = xscale_arch_state,
-
- .target_request_data = NULL,
-
- .halt = xscale_halt,
- .resume = xscale_resume,
- .step = xscale_step,
-
- .assert_reset = xscale_assert_reset,
- .deassert_reset = xscale_deassert_reset,
- .soft_reset_halt = xscale_soft_reset_halt,
- .prepare_reset_halt = xscale_prepare_reset_halt,
-
- .get_gdb_reg_list = armv4_5_get_gdb_reg_list,
-
- .read_memory = xscale_read_memory,
- .write_memory = xscale_write_memory,
- .bulk_write_memory = xscale_bulk_write_memory,
- .checksum_memory = xscale_checksum_memory,
-
- .run_algorithm = armv4_5_run_algorithm,
-
- .add_breakpoint = xscale_add_breakpoint,
- .remove_breakpoint = xscale_remove_breakpoint,
- .add_watchpoint = xscale_add_watchpoint,
- .remove_watchpoint = xscale_remove_watchpoint,
-
- .register_commands = xscale_register_commands,
- .target_command = xscale_target_command,
- .init_target = xscale_init_target,
- .quit = xscale_quit,
-
- .virt2phys = xscale_virt2phys,
- .mmu = xscale_mmu
-};
-
-char* xscale_reg_list[] =
-{
- "XSCALE_MAINID", /* 0 */
- "XSCALE_CACHETYPE",
- "XSCALE_CTRL",
- "XSCALE_AUXCTRL",
- "XSCALE_TTB",
- "XSCALE_DAC",
- "XSCALE_FSR",
- "XSCALE_FAR",
- "XSCALE_PID",
- "XSCALE_CPACCESS",
- "XSCALE_IBCR0", /* 10 */
- "XSCALE_IBCR1",
- "XSCALE_DBR0",
- "XSCALE_DBR1",
- "XSCALE_DBCON",
- "XSCALE_TBREG",
- "XSCALE_CHKPT0",
- "XSCALE_CHKPT1",
- "XSCALE_DCSR",
- "XSCALE_TX",
- "XSCALE_RX", /* 20 */
- "XSCALE_TXRXCTRL",
-};
-
-xscale_reg_t xscale_reg_arch_info[] =
-{
- {XSCALE_MAINID, NULL},
- {XSCALE_CACHETYPE, NULL},
- {XSCALE_CTRL, NULL},
- {XSCALE_AUXCTRL, NULL},
- {XSCALE_TTB, NULL},
- {XSCALE_DAC, NULL},
- {XSCALE_FSR, NULL},
- {XSCALE_FAR, NULL},
- {XSCALE_PID, NULL},
- {XSCALE_CPACCESS, NULL},
- {XSCALE_IBCR0, NULL},
- {XSCALE_IBCR1, NULL},
- {XSCALE_DBR0, NULL},
- {XSCALE_DBR1, NULL},
- {XSCALE_DBCON, NULL},
- {XSCALE_TBREG, NULL},
- {XSCALE_CHKPT0, NULL},
- {XSCALE_CHKPT1, NULL},
- {XSCALE_DCSR, NULL}, /* DCSR accessed via JTAG or SW */
- {-1, NULL}, /* TX accessed via JTAG */
- {-1, NULL}, /* RX accessed via JTAG */
- {-1, NULL}, /* TXRXCTRL implicit access via JTAG */
-};
-
-int xscale_reg_arch_type = -1;
-
-int xscale_get_reg(reg_t *reg);
-int xscale_set_reg(reg_t *reg, u8 *buf);
-
-int xscale_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, xscale_common_t **xscale_p)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
- {
- ERROR("target isn't an XScale target");
- return -1;
- }
-
- if (xscale->common_magic != XSCALE_COMMON_MAGIC)
- {
- ERROR("target isn't an XScale target");
- return -1;
- }
-
- *armv4_5_p = armv4_5;
- *xscale_p = xscale;
-
- return ERROR_OK;
-}
-
-int xscale_jtag_set_instr(int chain_pos, u32 new_instr)
-{
- jtag_device_t *device = jtag_get_device(chain_pos);
-
- if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr)
- {
- scan_field_t field;
-
- field.device = chain_pos;
- field.num_bits = device->ir_length;
- field.out_value = calloc(CEIL(field.num_bits, 8), 1);
- buf_set_u32(field.out_value, 0, field.num_bits, new_instr);
- field.out_mask = NULL;
- field.in_value = NULL;
- jtag_set_check_value(&field, device->expected, device->expected_mask, NULL);
-
- jtag_add_ir_scan(1, &field, -1);
-
- free(field.out_value);
- }
-
- return ERROR_OK;
-}
-
-int xscale_jtag_callback(enum jtag_event event, void *priv)
-{
- switch (event)
- {
- case JTAG_TRST_ASSERTED:
- break;
- case JTAG_TRST_RELEASED:
- break;
- case JTAG_SRST_ASSERTED:
- break;
- case JTAG_SRST_RELEASED:
- break;
- default:
- WARNING("unhandled JTAG event");
- }
-
- return ERROR_OK;
-}
-
-int xscale_read_dcsr(target_t *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- int retval;
-
- scan_field_t fields[3];
- u8 field0 = 0x0;
- u8 field0_check_value = 0x2;
- u8 field0_check_mask = 0x7;
- u8 field2 = 0x0;
- u8 field2_check_value = 0x0;
- u8 field2_check_mask = 0x1;
-
- jtag_add_end_state(TAP_PD);
- xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr);
-
- buf_set_u32(&field0, 1, 1, xscale->hold_rst);
- buf_set_u32(&field0, 2, 1, xscale->external_debug_break);
-
- fields[0].device = xscale->jtag_info.chain_pos;
- fields[0].num_bits = 3;
- fields[0].out_value = &field0;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL);
-
- fields[1].device = xscale->jtag_info.chain_pos;
- fields[1].num_bits = 32;
- fields[1].out_value = NULL;
- fields[1].out_mask = NULL;
- fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
-
-
-
- fields[2].device = xscale->jtag_info.chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = &field2;
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL);
-
- jtag_add_dr_scan(3, fields, -1);
-
- if ((retval = jtag_execute_queue()) != ERROR_OK)
- {
- ERROR("JTAG error while reading DCSR");
- return retval;
- }
-
- xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = 0;
- xscale->reg_cache->reg_list[XSCALE_DCSR].valid = 1;
-
- /* write the register with the value we just read
- * on this second pass, only the first bit of field0 is guaranteed to be 0)
- */
- field0_check_mask = 0x1;
- fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value;
- fields[1].in_value = NULL;
-
- jtag_add_end_state(TAP_RTI);
-
- jtag_add_dr_scan(3, fields, -1);
-
- return ERROR_OK;
-}
-
-int xscale_receive(target_t *target, u32 *buffer, int num_words)
-{
- int retval = ERROR_OK;
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- enum tap_state path[3];
- scan_field_t fields[3];
-
- u8 *field0 = malloc(num_words * 1);
- u8 field0_check_value = 0x2;
- u8 field0_check_mask = 0x6;
- u32 *field1 = malloc(num_words * 4);
- u8 field2_check_value = 0x0;
- u8 field2_check_mask = 0x1;
- int words_done = 0;
- int words_scheduled = 0;
-
- int i;
-
- path[0] = TAP_SDS;
- path[1] = TAP_CD;
- path[2] = TAP_SD;
-
- fields[0].device = xscale->jtag_info.chain_pos;
- fields[0].num_bits = 3;
- fields[0].out_value = NULL;
- fields[0].out_mask = NULL;
- /* fields[0].in_value = field0; */
- jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL);
-
- fields[1].device = xscale->jtag_info.chain_pos;
- fields[1].num_bits = 32;
- fields[1].out_value = NULL;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
-
-
-
- fields[2].device = xscale->jtag_info.chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = NULL;
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL);
-
- jtag_add_end_state(TAP_RTI);
- xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgtx);
- jtag_add_runtest(1, -1);
-
- /* repeat until all words have been collected */
- int attempts = 0;
- while (words_done < num_words)
- {
- /* schedule reads */
- words_scheduled = 0;
- for (i = words_done; i < num_words; i++)
- {
- fields[0].in_value = &field0[i];
- fields[1].in_handler = buf_to_u32_handler;
- fields[1].in_handler_priv = (u8*)&field1[i];
-
- jtag_add_pathmove(3, path);
- jtag_add_dr_scan(3, fields, TAP_RTI);
- words_scheduled++;
- }
-
- if ((retval = jtag_execute_queue()) != ERROR_OK)
- {
- ERROR("JTAG error while receiving data from debug handler");
- break;
- }
-
- /* examine results */
- for (i = words_done; i < num_words; i++)
- {
- if (!(field0[0] & 1))
- {
- /* move backwards if necessary */
- int j;
- for (j = i; j < num_words - 1; j++)
- {
- field0[j] = field0[j+1];
- field1[j] = field1[j+1];
- }
- words_scheduled--;
- }
- }
- if (words_scheduled == 0)
- {
- if (attempts++ == 1000)
- {
- ERROR("Failed to receiving data from debug handler after 1000 attempts");
- retval = ERROR_JTAG_QUEUE_FAILED;
- break;
- }
- }
-
- words_done += words_scheduled;
- }
-
- for (i = 0; i < num_words; i++)
- *(buffer++) = buf_get_u32((u8*)&field1[i], 0, 32);
-
- free(field1);
-
- return retval;
-}
-
-int xscale_read_tx(target_t *target, int consume)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
- enum tap_state path[3];
- enum tap_state noconsume_path[9];
-
- int retval;
- struct timeval timeout, now;
-
- scan_field_t fields[3];
- u8 field0_in = 0x0;
- u8 field0_check_value = 0x2;
- u8 field0_check_mask = 0x6;
- u8 field2_check_value = 0x0;
- u8 field2_check_mask = 0x1;
-
- jtag_add_end_state(TAP_RTI);
-
- xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgtx);
-
- path[0] = TAP_SDS;
- path[1] = TAP_CD;
- path[2] = TAP_SD;
-
- noconsume_path[0] = TAP_SDS;
- noconsume_path[1] = TAP_CD;
- noconsume_path[2] = TAP_E1D;
- noconsume_path[3] = TAP_PD;
- noconsume_path[4] = TAP_E2D;
- noconsume_path[5] = TAP_UD;
- noconsume_path[6] = TAP_SDS;
- noconsume_path[7] = TAP_CD;
- noconsume_path[8] = TAP_SD;
-
- fields[0].device = xscale->jtag_info.chain_pos;
- fields[0].num_bits = 3;
- fields[0].out_value = NULL;
- fields[0].out_mask = NULL;
- fields[0].in_value = &field0_in;
- jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL);
-
- fields[1].device = xscale->jtag_info.chain_pos;
- fields[1].num_bits = 32;
- fields[1].out_value = NULL;
- fields[1].out_mask = NULL;
- fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_TX].value;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
-
-
-
- fields[2].device = xscale->jtag_info.chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = NULL;
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL);
-
- gettimeofday(&timeout, NULL);
- timeval_add_time(&timeout, 5, 0);
-
- do
- {
- /* if we want to consume the register content (i.e. clear TX_READY),
- * we have to go straight from Capture-DR to Shift-DR
- * otherwise, we go from Capture-DR to Exit1-DR to Pause-DR
- */
- if (consume)
- jtag_add_pathmove(3, path);
- else
- jtag_add_pathmove(sizeof(noconsume_path)/sizeof(*noconsume_path), noconsume_path);
-
- jtag_add_dr_scan(3, fields, TAP_RTI);
-
- if ((retval = jtag_execute_queue()) != ERROR_OK)
- {
- ERROR("JTAG error while reading TX");
- return ERROR_TARGET_TIMEOUT;
- }
-
- gettimeofday(&now, NULL);
- if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec)&& (now.tv_usec > timeout.tv_usec)))
- {
- ERROR("time out reading TX register");
- return ERROR_TARGET_TIMEOUT;
- }
- } while ((!(field0_in & 1)) && consume);
-
- if (!(field0_in & 1))
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-
- return ERROR_OK;
-}
-
-int xscale_write_rx(target_t *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- int retval;
- struct timeval timeout, now;
-
- scan_field_t fields[3];
- u8 field0_out = 0x0;
- u8 field0_in = 0x0;
- u8 field0_check_value = 0x2;
- u8 field0_check_mask = 0x6;
- u8 field2 = 0x0;
- u8 field2_check_value = 0x0;
- u8 field2_check_mask = 0x1;
-
- jtag_add_end_state(TAP_RTI);
-
- xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgrx);
-
- fields[0].device = xscale->jtag_info.chain_pos;
- fields[0].num_bits = 3;
- fields[0].out_value = &field0_out;
- fields[0].out_mask = NULL;
- fields[0].in_value = &field0_in;
- jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL);
-
- fields[1].device = xscale->jtag_info.chain_pos;
- fields[1].num_bits = 32;
- fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_RX].value;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
-
-
-
- fields[2].device = xscale->jtag_info.chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = &field2;
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL);
-
- gettimeofday(&timeout, NULL);
- timeval_add_time(&timeout, 5, 0);
-
- /* poll until rx_read is low */
- DEBUG("polling RX");
- do
- {
- jtag_add_dr_scan(3, fields, TAP_RTI);
-
- if ((retval = jtag_execute_queue()) != ERROR_OK)
- {
- ERROR("JTAG error while writing RX");
- return retval;
- }
-
- gettimeofday(&now, NULL);
- if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec)&& (now.tv_usec > timeout.tv_usec)))
- {
- ERROR("time out writing RX register");
- return ERROR_TARGET_TIMEOUT;
- }
- } while (field0_in & 1);
-
- /* set rx_valid */
- field2 = 0x1;
- jtag_add_dr_scan(3, fields, TAP_RTI);
-
- if ((retval = jtag_execute_queue()) != ERROR_OK)
- {
- ERROR("JTAG error while writing RX");
- return retval;
- }
-
- return ERROR_OK;
-}
-
-/* send count elements of size byte to the debug handler */
-int xscale_send(target_t *target, u8 *buffer, int count, int size)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- int retval;
-
- int done_count = 0;
- u8 output[4] = {0, 0, 0, 0};
-
- scan_field_t fields[3];
- u8 field0_out = 0x0;
- u8 field0_check_value = 0x2;
- u8 field0_check_mask = 0x6;
- u8 field2 = 0x1;
- u8 field2_check_value = 0x0;
- u8 field2_check_mask = 0x1;
-
- jtag_add_end_state(TAP_RTI);
-
- xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgrx);
-
- fields[0].device = xscale->jtag_info.chain_pos;
- fields[0].num_bits = 3;
- fields[0].out_value = &field0_out;
- fields[0].out_mask = NULL;
- fields[0].in_handler = NULL;
- if (!xscale->fast_memory_access)
- {
- jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL);
- }
-
- fields[1].device = xscale->jtag_info.chain_pos;
- fields[1].num_bits = 32;
- fields[1].out_value = output;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
-
-
-
- fields[2].device = xscale->jtag_info.chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = &field2;
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- fields[2].in_handler = NULL;
- if (!xscale->fast_memory_access)
- {
- jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL);
- }
-
- if (size==4)
- {
- int endianness = target->endianness;
- while (done_count++ < count)
- {
- if (endianness == TARGET_LITTLE_ENDIAN)
- {
- output[0]=buffer[0];
- output[1]=buffer[1];
- output[2]=buffer[2];
- output[3]=buffer[3];
- } else
- {
- output[0]=buffer[3];
- output[1]=buffer[2];
- output[2]=buffer[1];
- output[3]=buffer[0];
- }
- jtag_add_dr_scan(3, fields, TAP_RTI);
- buffer += size;
- }
-
- } else
- {
- while (done_count++ < count)
- {
- /* extract sized element from target-endian buffer, and put it
- * into little-endian output buffer
- */
- switch (size)
- {
- case 2:
- buf_set_u32(output, 0, 32, target_buffer_get_u16(target, buffer));
- break;
- case 1:
- output[0] = *buffer;
- break;
- default:
- ERROR("BUG: size neither 4, 2 nor 1");
- exit(-1);
- }
-
- jtag_add_dr_scan(3, fields, TAP_RTI);
- buffer += size;
- }
-
- }
-
- if ((retval = jtag_execute_queue()) != ERROR_OK)
- {
- ERROR("JTAG error while sending data to debug handler");
- return retval;
- }
-
- return ERROR_OK;
-}
-
-int xscale_send_u32(target_t *target, u32 value)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value);
- return xscale_write_rx(target);
-}
-
-int xscale_write_dcsr(target_t *target, int hold_rst, int ext_dbg_brk)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- int retval;
-
- scan_field_t fields[3];
- u8 field0 = 0x0;
- u8 field0_check_value = 0x2;
- u8 field0_check_mask = 0x7;
- u8 field2 = 0x0;
- u8 field2_check_value = 0x0;
- u8 field2_check_mask = 0x1;
-
- if (hold_rst != -1)
- xscale->hold_rst = hold_rst;
-
- if (ext_dbg_brk != -1)
- xscale->external_debug_break = ext_dbg_brk;
-
- jtag_add_end_state(TAP_RTI);
- xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr);
-
- buf_set_u32(&field0, 1, 1, xscale->hold_rst);
- buf_set_u32(&field0, 2, 1, xscale->external_debug_break);
-
- fields[0].device = xscale->jtag_info.chain_pos;
- fields[0].num_bits = 3;
- fields[0].out_value = &field0;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL);
-
- fields[1].device = xscale->jtag_info.chain_pos;
- fields[1].num_bits = 32;
- fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
-
-
-
- fields[2].device = xscale->jtag_info.chain_pos;
- fields[2].num_bits = 1;
- fields[2].out_value = &field2;
- fields[2].out_mask = NULL;
- fields[2].in_value = NULL;
- jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL);
-
- jtag_add_dr_scan(3, fields, -1);
-
- if ((retval = jtag_execute_queue()) != ERROR_OK)
- {
- ERROR("JTAG error while writing DCSR");
- return retval;
- }
-
- xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = 0;
- xscale->reg_cache->reg_list[XSCALE_DCSR].valid = 1;
-
- return ERROR_OK;
-}
-
-/* parity of the number of bits 0 if even; 1 if odd. for 32 bit words */
-unsigned int parity (unsigned int v)
-{
- unsigned int ov = v;
- v ^= v >> 16;
- v ^= v >> 8;
- v ^= v >> 4;
- v &= 0xf;
- DEBUG("parity of 0x%x is %i", ov, (0x6996 >> v) & 1);
- return (0x6996 >> v) & 1;
-}
-
-int xscale_load_ic(target_t *target, int mini, u32 va, u32 buffer[8])
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
- u8 packet[4];
- u8 cmd;
- int word;
-
- scan_field_t fields[2];
-
- DEBUG("loading miniIC at 0x%8.8x", va);
-
- jtag_add_end_state(TAP_RTI);
- xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.ldic); /* LDIC */
-
- /* CMD is b010 for Main IC and b011 for Mini IC */
- if (mini)
- buf_set_u32(&cmd, 0, 3, 0x3);
- else
- buf_set_u32(&cmd, 0, 3, 0x2);
-
- buf_set_u32(&cmd, 3, 3, 0x0);
-
- /* virtual address of desired cache line */
- buf_set_u32(packet, 0, 27, va >> 5);
-
- fields[0].device = xscale->jtag_info.chain_pos;
- fields[0].num_bits = 6;
- fields[0].out_value = &cmd;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = xscale->jtag_info.chain_pos;
- fields[1].num_bits = 27;
- fields[1].out_value = packet;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- jtag_add_dr_scan(2, fields, -1);
-
- fields[0].num_bits = 32;
- fields[0].out_value = packet;
-
- fields[1].num_bits = 1;
- fields[1].out_value = &cmd;
-
- for (word = 0; word < 8; word++)
- {
- buf_set_u32(packet, 0, 32, buffer[word]);
- cmd = parity(*((u32*)packet));
- jtag_add_dr_scan(2, fields, -1);
- }
-
- jtag_execute_queue();
-
- return ERROR_OK;
-}
-
-int xscale_invalidate_ic_line(target_t *target, u32 va)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
- u8 packet[4];
- u8 cmd;
-
- scan_field_t fields[2];
-
- jtag_add_end_state(TAP_RTI);
- xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.ldic); /* LDIC */
-
- /* CMD for invalidate IC line b000, bits [6:4] b000 */
- buf_set_u32(&cmd, 0, 6, 0x0);
-
- /* virtual address of desired cache line */
- buf_set_u32(packet, 0, 27, va >> 5);
-
- fields[0].device = xscale->jtag_info.chain_pos;
- fields[0].num_bits = 6;
- fields[0].out_value = &cmd;
- fields[0].out_mask = NULL;
- fields[0].in_value = NULL;
- fields[0].in_check_value = NULL;
- fields[0].in_check_mask = NULL;
- fields[0].in_handler = NULL;
- fields[0].in_handler_priv = NULL;
-
- fields[1].device = xscale->jtag_info.chain_pos;
- fields[1].num_bits = 27;
- fields[1].out_value = packet;
- fields[1].out_mask = NULL;
- fields[1].in_value = NULL;
- fields[1].in_check_value = NULL;
- fields[1].in_check_mask = NULL;
- fields[1].in_handler = NULL;
- fields[1].in_handler_priv = NULL;
-
- jtag_add_dr_scan(2, fields, -1);
-
- return ERROR_OK;
-}
-
-int xscale_update_vectors(target_t *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
- int i;
-
- u32 low_reset_branch, high_reset_branch;
-
- for (i = 1; i < 8; i++)
- {
- /* if there's a static vector specified for this exception, override */
- if (xscale->static_high_vectors_set & (1 << i))
- {
- xscale->high_vectors[i] = xscale->static_high_vectors[i];
- }
- else
- {
- if (target_read_u32(target, 0xffff0000 + 4*i, &xscale->high_vectors[i]) != ERROR_OK)
- {
- xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0);
- }
- }
- }
-
- for (i = 1; i < 8; i++)
- {
- if (xscale->static_low_vectors_set & (1 << i))
- {
- xscale->low_vectors[i] = xscale->static_low_vectors[i];
- }
- else
- {
- if (target_read_u32(target, 0x0 + 4*i, &xscale->low_vectors[i]) != ERROR_OK)
- {
- xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0);
- }
- }
- }
-
- /* calculate branches to debug handler */
- low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2;
- high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2;
-
- xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0);
- xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0);
-
- /* invalidate and load exception vectors in mini i-cache */
- xscale_invalidate_ic_line(target, 0x0);
- xscale_invalidate_ic_line(target, 0xffff0000);
-
- xscale_load_ic(target, 1, 0x0, xscale->low_vectors);
- xscale_load_ic(target, 1, 0xffff0000, xscale->high_vectors);
-
- return ERROR_OK;
-}
-
-int xscale_arch_state(struct target_s *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- char *state[] =
- {
- "disabled", "enabled"
- };
-
- char *arch_dbg_reason[] =
- {
- "", "\n(processor reset)", "\n(trace buffer full)"
- };
-
- if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC)
- {
- ERROR("BUG: called for a non-ARMv4/5 target");
- exit(-1);
- }
-
- USER("target halted in %s state due to %s, current mode: %s\n"
- "cpsr: 0x%8.8x pc: 0x%8.8x\n"
- "MMU: %s, D-Cache: %s, I-Cache: %s"
- "%s",
- armv4_5_state_strings[armv4_5->core_state],
- target_debug_reason_strings[target->debug_reason],
- armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)],
- buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32),
- buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32),
- state[xscale->armv4_5_mmu.mmu_enabled],
- state[xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled],
- state[xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled],
- arch_dbg_reason[xscale->arch_debug_reason]);
-
- return ERROR_OK;
-}
-
-int xscale_poll(target_t *target)
-{
- int retval=ERROR_OK;
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- if ((target->state == TARGET_RUNNING) || (target->state == TARGET_DEBUG_RUNNING))
- {
- enum target_state previous_state = target->state;
- if ((retval = xscale_read_tx(target, 0)) == ERROR_OK)
- {
-
- /* there's data to read from the tx register, we entered debug state */
- xscale->handler_running = 1;
-
- target->state = TARGET_HALTED;
-
- /* process debug entry, fetching current mode regs */
- retval = xscale_debug_entry(target);
- }
- else if (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
- {
- USER("error while polling TX register, reset CPU");
- /* here we "lie" so GDB won't get stuck and a reset can be perfomed */
- target->state = TARGET_HALTED;
- }
-
- /* debug_entry could have overwritten target state (i.e. immediate resume)
- * don't signal event handlers in that case
- */
- if (target->state != TARGET_HALTED)
- return ERROR_OK;
-
- /* if target was running, signal that we halted
- * otherwise we reentered from debug execution */
- if (previous_state == TARGET_RUNNING)
- target_call_event_callbacks(target, TARGET_EVENT_HALTED);
- else
- target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
- }
- return retval;
-}
-
-int xscale_debug_entry(target_t *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
- u32 pc;
- u32 buffer[10];
- int i;
-
- u32 moe;
-
- /* clear external dbg break (will be written on next DCSR read) */
- xscale->external_debug_break = 0;
- xscale_read_dcsr(target);
-
- /* get r0, pc, r1 to r7 and cpsr */
- xscale_receive(target, buffer, 10);
-
- /* move r0 from buffer to register cache */
- buf_set_u32(armv4_5->core_cache->reg_list[0].value, 0, 32, buffer[0]);
- armv4_5->core_cache->reg_list[15].dirty = 1;
- armv4_5->core_cache->reg_list[15].valid = 1;
- DEBUG("r0: 0x%8.8x", buffer[0]);
-
- /* move pc from buffer to register cache */
- buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, buffer[1]);
- armv4_5->core_cache->reg_list[15].dirty = 1;
- armv4_5->core_cache->reg_list[15].valid = 1;
- DEBUG("pc: 0x%8.8x", buffer[1]);
-
- /* move data from buffer to register cache */
- for (i = 1; i <= 7; i++)
- {
- buf_set_u32(armv4_5->core_cache->reg_list[i].value, 0, 32, buffer[1 + i]);
- armv4_5->core_cache->reg_list[i].dirty = 1;
- armv4_5->core_cache->reg_list[i].valid = 1;
- DEBUG("r%i: 0x%8.8x", i, buffer[i + 1]);
- }
-
- buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32, buffer[9]);
- armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
- armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
- DEBUG("cpsr: 0x%8.8x", buffer[9]);
-
- armv4_5->core_mode = buffer[9] & 0x1f;
- if (armv4_5_mode_to_number(armv4_5->core_mode) == -1)
- {
- target->state = TARGET_UNKNOWN;
- ERROR("cpsr contains invalid mode value - communication failure");
- return ERROR_TARGET_FAILURE;
- }
- DEBUG("target entered debug state in %s mode", armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)]);
-
- if (buffer[9] & 0x20)
- armv4_5->core_state = ARMV4_5_STATE_THUMB;
- else
- armv4_5->core_state = ARMV4_5_STATE_ARM;
-
- /* get banked registers, r8 to r14, and spsr if not in USR/SYS mode */
- if ((armv4_5->core_mode != ARMV4_5_MODE_USR) && (armv4_5->core_mode != ARMV4_5_MODE_SYS))
- {
- xscale_receive(target, buffer, 8);
- buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32, buffer[7]);
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).dirty = 0;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).valid = 1;
- }
- else
- {
- /* r8 to r14, but no spsr */
- xscale_receive(target, buffer, 7);
- }
-
- /* move data from buffer to register cache */
- for (i = 8; i <= 14; i++)
- {
- buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).value, 0, 32, buffer[i - 8]);
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).dirty = 0;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).valid = 1;
- }
-
- /* examine debug reason */
- xscale_read_dcsr(target);
- moe = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 2, 3);
-
- /* stored PC (for calculating fixup) */
- pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
-
- switch (moe)
- {
- case 0x0: /* Processor reset */
- target->debug_reason = DBG_REASON_DBGRQ;
- xscale->arch_debug_reason = XSCALE_DBG_REASON_RESET;
- pc -= 4;
- break;
- case 0x1: /* Instruction breakpoint hit */
- target->debug_reason = DBG_REASON_BREAKPOINT;
- xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC;
- pc -= 4;
- break;
- case 0x2: /* Data breakpoint hit */
- target->debug_reason = DBG_REASON_WATCHPOINT;
- xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC;
- pc -= 4;
- break;
- case 0x3: /* BKPT instruction executed */
- target->debug_reason = DBG_REASON_BREAKPOINT;
- xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC;
- pc -= 4;
- break;
- case 0x4: /* Ext. debug event */
- target->debug_reason = DBG_REASON_DBGRQ;
- xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC;
- pc -= 4;
- break;
- case 0x5: /* Vector trap occured */
- target->debug_reason = DBG_REASON_BREAKPOINT;
- xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC;
- pc -= 4;
- break;
- case 0x6: /* Trace buffer full break */
- target->debug_reason = DBG_REASON_DBGRQ;
- xscale->arch_debug_reason = XSCALE_DBG_REASON_TB_FULL;
- pc -= 4;
- break;
- case 0x7: /* Reserved */
- default:
- ERROR("Method of Entry is 'Reserved'");
- exit(-1);
- break;
- }
-
- /* apply PC fixup */
- buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, pc);
-
- /* on the first debug entry, identify cache type */
- if (xscale->armv4_5_mmu.armv4_5_cache.ctype == -1)
- {
- u32 cache_type_reg;
-
- /* read cp15 cache type register */
- xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CACHETYPE]);
- cache_type_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CACHETYPE].value, 0, 32);
-
- armv4_5_identify_cache(cache_type_reg, &xscale->armv4_5_mmu.armv4_5_cache);
- }
-
- /* examine MMU and Cache settings */
- /* read cp15 control register */
- xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]);
- xscale->cp15_control_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32);
- xscale->armv4_5_mmu.mmu_enabled = (xscale->cp15_control_reg & 0x1U) ? 1 : 0;
- xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (xscale->cp15_control_reg & 0x4U) ? 1 : 0;
- xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (xscale->cp15_control_reg & 0x1000U) ? 1 : 0;
-
- /* tracing enabled, read collected trace data */
- if (xscale->trace.buffer_enabled)
- {
- xscale_read_trace(target);
- xscale->trace.buffer_fill--;
-
- /* resume if we're still collecting trace data */
- if ((xscale->arch_debug_reason == XSCALE_DBG_REASON_TB_FULL)
- && (xscale->trace.buffer_fill > 0))
- {
- xscale_resume(target, 1, 0x0, 1, 0);
- }
- else
- {
- xscale->trace.buffer_enabled = 0;
- }
- }
-
- return ERROR_OK;
-}
-
-int xscale_halt(target_t *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- DEBUG("target->state: %s", target_state_strings[target->state]);
-
- if (target->state == TARGET_HALTED)
- {
- WARNING("target was already halted");
- return ERROR_TARGET_ALREADY_HALTED;
- }
- else if (target->state == TARGET_UNKNOWN)
- {
- /* this must not happen for a xscale target */
- ERROR("target was in unknown state when halt was requested");
- return ERROR_TARGET_INVALID;
- }
- else if (target->state == TARGET_RESET)
- {
- DEBUG("target->state == TARGET_RESET");
- }
- else
- {
- /* assert external dbg break */
- xscale->external_debug_break = 1;
- xscale_read_dcsr(target);
-
- target->debug_reason = DBG_REASON_DBGRQ;
- }
-
- return ERROR_OK;
-}
-
-int xscale_enable_single_step(struct target_s *target, u32 next_pc)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale= armv4_5->arch_info;
- reg_t *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0];
-
- if (xscale->ibcr0_used)
- {
- breakpoint_t *ibcr0_bp = breakpoint_find(target, buf_get_u32(ibcr0->value, 0, 32) & 0xfffffffe);
-
- if (ibcr0_bp)
- {
- xscale_unset_breakpoint(target, ibcr0_bp);
- }
- else
- {
- ERROR("BUG: xscale->ibcr0_used is set, but no breakpoint with that address found");
- exit(-1);
- }
- }
-
- xscale_set_reg_u32(ibcr0, next_pc | 0x1);
-
- return ERROR_OK;
-}
-
-int xscale_disable_single_step(struct target_s *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale= armv4_5->arch_info;
- reg_t *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0];
-
- xscale_set_reg_u32(ibcr0, 0x0);
-
- return ERROR_OK;
-}
-
-int xscale_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale= armv4_5->arch_info;
- breakpoint_t *breakpoint = target->breakpoints;
-
- u32 current_pc;
-
- int retval;
- int i;
-
- DEBUG("-");
-
- if (target->state != TARGET_HALTED)
- {
- WARNING("target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (!debug_execution)
- {
- target_free_all_working_areas(target);
- }
-
- /* update vector tables */
- xscale_update_vectors(target);
-
- /* current = 1: continue on current pc, otherwise continue at <address> */
- if (!current)
- buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, address);
-
- current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
-
- /* if we're at the reset vector, we have to simulate the branch */
- if (current_pc == 0x0)
- {
- arm_simulate_step(target, NULL);
- current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
- }
-
- /* the front-end may request us not to handle breakpoints */
- if (handle_breakpoints)
- {
- if ((breakpoint = breakpoint_find(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32))))
- {
- u32 next_pc;
-
- /* there's a breakpoint at the current PC, we have to step over it */
- DEBUG("unset breakpoint at 0x%8.8x", breakpoint->address);
- xscale_unset_breakpoint(target, breakpoint);
-
- /* calculate PC of next instruction */
- if ((retval = arm_simulate_step(target, &next_pc)) != ERROR_OK)
- {
- u32 current_opcode;
- target_read_u32(target, current_pc, ¤t_opcode);
- ERROR("BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8x", current_opcode);
- }
-
- DEBUG("enable single-step");
- xscale_enable_single_step(target, next_pc);
-
- /* restore banked registers */
- xscale_restore_context(target);
-
- /* send resume request (command 0x30 or 0x31)
- * clean the trace buffer if it is to be enabled (0x62) */
- if (xscale->trace.buffer_enabled)
- {
- xscale_send_u32(target, 0x62);
- xscale_send_u32(target, 0x31);
- }
- else
- xscale_send_u32(target, 0x30);
-
- /* send CPSR */
- xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32));
- DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32));
-
- for (i = 7; i >= 0; i--)
- {
- /* send register */
- xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32));
- DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32));
- }
-
- /* send PC */
- xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
- DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
-
- /* wait for and process debug entry */
- xscale_debug_entry(target);
-
- DEBUG("disable single-step");
- xscale_disable_single_step(target);
-
- DEBUG("set breakpoint at 0x%8.8x", breakpoint->address);
- xscale_set_breakpoint(target, breakpoint);
- }
- }
-
- /* enable any pending breakpoints and watchpoints */
- xscale_enable_breakpoints(target);
- xscale_enable_watchpoints(target);
-
- /* restore banked registers */
- xscale_restore_context(target);
-
- /* send resume request (command 0x30 or 0x31)
- * clean the trace buffer if it is to be enabled (0x62) */
- if (xscale->trace.buffer_enabled)
- {
- xscale_send_u32(target, 0x62);
- xscale_send_u32(target, 0x31);
- }
- else
- xscale_send_u32(target, 0x30);
-
- /* send CPSR */
- xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32));
- DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32));
-
- for (i = 7; i >= 0; i--)
- {
- /* send register */
- xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32));
- DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32));
- }
-
- /* send PC */
- xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
- DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
-
- target->debug_reason = DBG_REASON_NOTHALTED;
-
- if (!debug_execution)
- {
- /* registers are now invalid */
- armv4_5_invalidate_core_regs(target);
- target->state = TARGET_RUNNING;
- target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
- }
- else
- {
- target->state = TARGET_DEBUG_RUNNING;
- target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
- }
-
- DEBUG("target resumed");
-
- xscale->handler_running = 1;
-
- return ERROR_OK;
-}
-
-int xscale_step(struct target_s *target, int current, u32 address, int handle_breakpoints)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
- breakpoint_t *breakpoint = target->breakpoints;
-
- u32 current_pc, next_pc;
- int i;
- int retval;
-
- if (target->state != TARGET_HALTED)
- {
- WARNING("target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- /* current = 1: continue on current pc, otherwise continue at <address> */
- if (!current)
- buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, address);
-
- current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
-
- /* if we're at the reset vector, we have to simulate the step */
- if (current_pc == 0x0)
- {
- arm_simulate_step(target, NULL);
- current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
-
- target->debug_reason = DBG_REASON_SINGLESTEP;
- target_call_event_callbacks(target, TARGET_EVENT_HALTED);
-
- return ERROR_OK;
- }
-
- /* the front-end may request us not to handle breakpoints */
- if (handle_breakpoints)
- if ((breakpoint = breakpoint_find(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32))))
- {
- xscale_unset_breakpoint(target, breakpoint);
- }
-
- target->debug_reason = DBG_REASON_SINGLESTEP;
-
- /* calculate PC of next instruction */
- if ((retval = arm_simulate_step(target, &next_pc)) != ERROR_OK)
- {
- u32 current_opcode;
- target_read_u32(target, current_pc, ¤t_opcode);
- ERROR("BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8x", current_opcode);
- }
-
- DEBUG("enable single-step");
- xscale_enable_single_step(target, next_pc);
-
- /* restore banked registers */
- xscale_restore_context(target);
-
- /* send resume request (command 0x30 or 0x31)
- * clean the trace buffer if it is to be enabled (0x62) */
- if (xscale->trace.buffer_enabled)
- {
- xscale_send_u32(target, 0x62);
- xscale_send_u32(target, 0x31);
- }
- else
- xscale_send_u32(target, 0x30);
-
- /* send CPSR */
- xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32));
- DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32));
-
- for (i = 7; i >= 0; i--)
- {
- /* send register */
- xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32));
- DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32));
- }
-
- /* send PC */
- xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
- DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
-
- target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
-
- /* registers are now invalid */
- armv4_5_invalidate_core_regs(target);
-
- /* wait for and process debug entry */
- xscale_debug_entry(target);
-
- DEBUG("disable single-step");
- xscale_disable_single_step(target);
-
- target_call_event_callbacks(target, TARGET_EVENT_HALTED);
-
- if (breakpoint)
- {
- xscale_set_breakpoint(target, breakpoint);
- }
-
- DEBUG("target stepped");
-
- return ERROR_OK;
-
-}
-
-int xscale_assert_reset(target_t *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- DEBUG("target->state: %s", target_state_strings[target->state]);
-
- /* select DCSR instruction (set endstate to R-T-I to ensure we don't
- * end up in T-L-R, which would reset JTAG
- */
- jtag_add_end_state(TAP_RTI);
- xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr);
-
- /* set Hold reset, Halt mode and Trap Reset */
- buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1);
- buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1);
- xscale_write_dcsr(target, 1, 0);
-
- /* select BYPASS, because having DCSR selected caused problems on the PXA27x */
- xscale_jtag_set_instr(xscale->jtag_info.chain_pos, 0x7f);
- jtag_execute_queue();
-
- /* assert reset */
- jtag_add_reset(0, 1);
-
- /* sleep 1ms, to be sure we fulfill any requirements */
- jtag_add_sleep(1000);
- jtag_execute_queue();
-
- target->state = TARGET_RESET;
-
- return ERROR_OK;
-}
-
-int xscale_deassert_reset(target_t *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- fileio_t debug_handler;
- u32 address;
- u32 binary_size;
-
- u32 buf_cnt;
- int i;
- int retval;
-
- breakpoint_t *breakpoint = target->breakpoints;
-
- DEBUG("-");
-
- xscale->ibcr_available = 2;
- xscale->ibcr0_used = 0;
- xscale->ibcr1_used = 0;
-
- xscale->dbr_available = 2;
- xscale->dbr0_used = 0;
- xscale->dbr1_used = 0;
-
- /* mark all hardware breakpoints as unset */
- while (breakpoint)
- {
- if (breakpoint->type == BKPT_HARD)
- {
- breakpoint->set = 0;
- }
- breakpoint = breakpoint->next;
- }
-
- if (!xscale->handler_installed)
- {
- /* release SRST */
- jtag_add_reset(0, 0);
-
- /* wait 300ms; 150 and 100ms were not enough */
- jtag_add_sleep(300*1000);
-
- jtag_add_runtest(2030, TAP_RTI);
- jtag_execute_queue();
-
- /* set Hold reset, Halt mode and Trap Reset */
- buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1);
- buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1);
- xscale_write_dcsr(target, 1, 0);
-
- /* Load debug handler */
- if (fileio_open(&debug_handler, PKGLIBDIR "/xscale/debug_handler.bin", FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
- {
- ERROR("file open error: %s", debug_handler.error_str);
- return ERROR_OK;
- }
-
- if ((binary_size = debug_handler.size) % 4)
- {
- ERROR("debug_handler.bin: size not a multiple of 4");
- exit(-1);
- }
-
- if (binary_size > 0x800)
- {
- ERROR("debug_handler.bin: larger than 2kb");
- exit(-1);
- }
-
- binary_size = CEIL(binary_size, 32) * 32;
-
- address = xscale->handler_address;
- while (binary_size > 0)
- {
- u32 cache_line[8];
- u8 buffer[32];
-
- if ((retval = fileio_read(&debug_handler, 32, buffer, &buf_cnt)) != ERROR_OK)
- {
- ERROR("reading debug handler failed: %s", debug_handler.error_str);
- }
-
- for (i = 0; i < buf_cnt; i += 4)
- {
- /* convert LE buffer to host-endian u32 */
- cache_line[i / 4] = le_to_h_u32(&buffer[i]);
- }
-
- for (; buf_cnt < 32; buf_cnt += 4)
- {
- cache_line[buf_cnt / 4] = 0xe1a08008;
- }
-
- /* only load addresses other than the reset vectors */
- if ((address % 0x400) != 0x0)
- {
- xscale_load_ic(target, 1, address, cache_line);
- }
-
- address += buf_cnt;
- binary_size -= buf_cnt;
- };
-
- xscale_load_ic(target, 1, 0x0, xscale->low_vectors);
- xscale_load_ic(target, 1, 0xffff0000, xscale->high_vectors);
-
- jtag_add_runtest(30, TAP_RTI);
-
- jtag_add_sleep(100000);
-
- /* set Hold reset, Halt mode and Trap Reset */
- buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1);
- buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1);
- xscale_write_dcsr(target, 1, 0);
-
- /* clear Hold reset to let the target run (should enter debug handler) */
- xscale_write_dcsr(target, 0, 1);
- target->state = TARGET_RUNNING;
-
- if ((target->reset_mode != RESET_HALT) && (target->reset_mode != RESET_INIT))
- {
- jtag_add_sleep(10000);
-
- /* we should have entered debug now */
- xscale_debug_entry(target);
- target->state = TARGET_HALTED;
-
- /* resume the target */
- xscale_resume(target, 1, 0x0, 1, 0);
- }
-
- fileio_close(&debug_handler);
- }
- else
- {
- jtag_add_reset(0, 0);
- }
-
-
- return ERROR_OK;
-}
-
-int xscale_soft_reset_halt(struct target_s *target)
-{
-
- return ERROR_OK;
-}
-
-int xscale_prepare_reset_halt(struct target_s *target)
-{
- /* nothing to be done for reset_halt on XScale targets
- * we always halt after a reset to upload the debug handler
- */
- return ERROR_OK;
-}
-
-int xscale_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode)
-{
-
- return ERROR_OK;
-}
-
-int xscale_write_core_reg(struct target_s *target, int num, enum armv4_5_mode mode, u32 value)
-{
-
- return ERROR_OK;
-}
-
-int xscale_full_context(target_t *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
-
- u32 *buffer;
-
- int i, j;
-
- DEBUG("-");
-
- if (target->state != TARGET_HALTED)
- {
- WARNING("target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- buffer = malloc(4 * 8);
-
- /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS)
- * we can't enter User mode on an XScale (unpredictable),
- * but User shares registers with SYS
- */
- for(i = 1; i < 7; i++)
- {
- int valid = 1;
-
- /* check if there are invalid registers in the current mode
- */
- for (j = 0; j <= 16; j++)
- {
- if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid == 0)
- valid = 0;
- }
-
- if (!valid)
- {
- u32 tmp_cpsr;
-
- /* request banked registers */
- xscale_send_u32(target, 0x0);
-
- tmp_cpsr = 0x0;
- tmp_cpsr |= armv4_5_number_to_mode(i);
- tmp_cpsr |= 0xc0; /* I/F bits */
-
- /* send CPSR for desired mode */
- xscale_send_u32(target, tmp_cpsr);
-
- /* get banked registers, r8 to r14, and spsr if not in USR/SYS mode */
- if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS))
- {
- xscale_receive(target, buffer, 8);
- buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32, buffer[7]);
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).valid = 1;
- }
- else
- {
- xscale_receive(target, buffer, 7);
- }
-
- /* move data from buffer to register cache */
- for (j = 8; j <= 14; j++)
- {
- buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).value, 0, 32, buffer[j - 8]);
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty = 0;
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid = 1;
- }
- }
- }
-
- free(buffer);
-
- return ERROR_OK;
-}
-
-int xscale_restore_context(target_t *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
-
- int i, j;
-
- DEBUG("-");
-
- if (target->state != TARGET_HALTED)
- {
- WARNING("target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS)
- * we can't enter User mode on an XScale (unpredictable),
- * but User shares registers with SYS
- */
- for(i = 1; i < 7; i++)
- {
- int dirty = 0;
-
- /* check if there are invalid registers in the current mode
- */
- for (j = 8; j <= 14; j++)
- {
- if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty == 1)
- dirty = 1;
- }
-
- /* if not USR/SYS, check if the SPSR needs to be written */
- if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS))
- {
- if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty == 1)
- dirty = 1;
- }
-
- if (dirty)
- {
- u32 tmp_cpsr;
-
- /* send banked registers */
- xscale_send_u32(target, 0x1);
-
- tmp_cpsr = 0x0;
- tmp_cpsr |= armv4_5_number_to_mode(i);
- tmp_cpsr |= 0xc0; /* I/F bits */
-
- /* send CPSR for desired mode */
- xscale_send_u32(target, tmp_cpsr);
-
- /* send banked registers, r8 to r14, and spsr if not in USR/SYS mode */
- for (j = 8; j <= 14; j++)
- {
- xscale_send_u32(target, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, j).value, 0, 32));
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty = 0;
- }
-
- if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS))
- {
- xscale_send_u32(target, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32));
- ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0;
- }
- }
- }
-
- return ERROR_OK;
-}
-
-int xscale_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
- u32 *buf32;
- int i;
-
- DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count);
-
- if (target->state != TARGET_HALTED)
- {
- WARNING("target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- /* sanitize arguments */
- if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer))
- return ERROR_INVALID_ARGUMENTS;
-
- if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
- return ERROR_TARGET_UNALIGNED_ACCESS;
-
- /* send memory read request (command 0x1n, n: access size) */
- xscale_send_u32(target, 0x10 | size);
-
- /* send base address for read request */
- xscale_send_u32(target, address);
-
- /* send number of requested data words */
- xscale_send_u32(target, count);
-
- /* receive data from target (count times 32-bit words in host endianness) */
- buf32 = malloc(4 * count);
- xscale_receive(target, buf32, count);
-
- /* extract data from host-endian buffer into byte stream */
- for (i = 0; i < count; i++)
- {
- switch (size)
- {
- case 4:
- target_buffer_set_u32(target, buffer, buf32[i]);
- buffer += 4;
- break;
- case 2:
- target_buffer_set_u16(target, buffer, buf32[i] & 0xffff);
- buffer += 2;
- break;
- case 1:
- *buffer++ = buf32[i] & 0xff;
- break;
- default:
- ERROR("should never get here");
- exit(-1);
- }
- }
-
- free(buf32);
-
- /* examine DCSR, to see if Sticky Abort (SA) got set */
- xscale_read_dcsr(target);
- if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1)
- {
- /* clear SA bit */
- xscale_send_u32(target, 0x60);
-
- return ERROR_TARGET_DATA_ABORT;
- }
-
- return ERROR_OK;
-}
-
-int xscale_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count);
-
- if (target->state != TARGET_HALTED)
- {
- WARNING("target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- /* sanitize arguments */
- if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer))
- return ERROR_INVALID_ARGUMENTS;
-
- if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
- return ERROR_TARGET_UNALIGNED_ACCESS;
-
- /* send memory write request (command 0x2n, n: access size) */
- xscale_send_u32(target, 0x20 | size);
-
- /* send base address for read request */
- xscale_send_u32(target, address);
-
- /* send number of requested data words to be written*/
- xscale_send_u32(target, count);
-
- /* extract data from host-endian buffer into byte stream */
-#if 0
- for (i = 0; i < count; i++)
- {
- switch (size)
- {
- case 4:
- value = target_buffer_get_u32(target, buffer);
- xscale_send_u32(target, value);
- buffer += 4;
- break;
- case 2:
- value = target_buffer_get_u16(target, buffer);
- xscale_send_u32(target, value);
- buffer += 2;
- break;
- case 1:
- value = *buffer;
- xscale_send_u32(target, value);
- buffer += 1;
- break;
- default:
- ERROR("should never get here");
- exit(-1);
- }
- }
-#endif
- xscale_send(target, buffer, count, size);
-
- /* examine DCSR, to see if Sticky Abort (SA) got set */
- xscale_read_dcsr(target);
- if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1)
- {
- /* clear SA bit */
- xscale_send_u32(target, 0x60);
-
- return ERROR_TARGET_DATA_ABORT;
- }
-
- return ERROR_OK;
-}
-
-int xscale_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer)
-{
- return xscale_write_memory(target, address, 4, count, buffer);
-}
-
-int xscale_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum)
-{
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-}
-
-u32 xscale_get_ttb(target_t *target)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
- u32 ttb;
-
- xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_TTB]);
- ttb = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_TTB].value, 0, 32);
-
- return ttb;
-}
-
-void xscale_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
- u32 cp15_control;
-
- /* read cp15 control register */
- xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]);
- cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32);
-
- if (mmu)
- cp15_control &= ~0x1U;
-
- if (d_u_cache)
- {
- /* clean DCache */
- xscale_send_u32(target, 0x50);
- xscale_send_u32(target, xscale->cache_clean_address);
-
- /* invalidate DCache */
- xscale_send_u32(target, 0x51);
-
- cp15_control &= ~0x4U;
- }
-
- if (i_cache)
- {
- /* invalidate ICache */
- xscale_send_u32(target, 0x52);
- cp15_control &= ~0x1000U;
- }
-
- /* write new cp15 control register */
- xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control);
-
- /* execute cpwait to ensure outstanding operations complete */
- xscale_send_u32(target, 0x53);
-}
-
-void xscale_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
- u32 cp15_control;
-
- /* read cp15 control register */
- xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]);
- cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32);
-
- if (mmu)
- cp15_control |= 0x1U;
-
- if (d_u_cache)
- cp15_control |= 0x4U;
-
- if (i_cache)
- cp15_control |= 0x1000U;
-
- /* write new cp15 control register */
- xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control);
-
- /* execute cpwait to ensure outstanding operations complete */
- xscale_send_u32(target, 0x53);
-}
-
-int xscale_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- if (target->state != TARGET_HALTED)
- {
- WARNING("target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (xscale->force_hw_bkpts)
- breakpoint->type = BKPT_HARD;
-
- if (breakpoint->set)
- {
- WARNING("breakpoint already set");
- return ERROR_OK;
- }
-
- if (breakpoint->type == BKPT_HARD)
- {
- u32 value = breakpoint->address | 1;
- if (!xscale->ibcr0_used)
- {
- xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], value);
- xscale->ibcr0_used = 1;
- breakpoint->set = 1; /* breakpoint set on first breakpoint register */
- }
- else if (!xscale->ibcr1_used)
- {
- xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], value);
- xscale->ibcr1_used = 1;
- breakpoint->set = 2; /* breakpoint set on second breakpoint register */
- }
- else
- {
- ERROR("BUG: no hardware comparator available");
- return ERROR_OK;
- }
- }
- else if (breakpoint->type == BKPT_SOFT)
- {
- if (breakpoint->length == 4)
- {
- /* keep the original instruction in target endianness */
- target->type->read_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr);
- /* write the original instruction in target endianness (arm7_9->arm_bkpt is host endian) */
- target_write_u32(target, breakpoint->address, xscale->arm_bkpt);
- }
- else
- {
- /* keep the original instruction in target endianness */
- target->type->read_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr);
- /* write the original instruction in target endianness (arm7_9->arm_bkpt is host endian) */
- target_write_u32(target, breakpoint->address, xscale->thumb_bkpt);
- }
- breakpoint->set = 1;
- }
-
- return ERROR_OK;
-
-}
-
-int xscale_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- if (target->state != TARGET_HALTED)
- {
- WARNING("target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (xscale->force_hw_bkpts)
- {
- DEBUG("forcing use of hardware breakpoint at address 0x%8.8x", breakpoint->address);
- breakpoint->type = BKPT_HARD;
- }
-
- if ((breakpoint->type == BKPT_HARD) && (xscale->ibcr_available < 1))
- {
- INFO("no breakpoint unit available for hardware breakpoint");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
- else
- {
- xscale->ibcr_available--;
- }
-
- if ((breakpoint->length != 2) && (breakpoint->length != 4))
- {
- INFO("only breakpoints of two (Thumb) or four (ARM) bytes length supported");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
-
- return ERROR_OK;
-}
-
-int xscale_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- if (target->state != TARGET_HALTED)
- {
- WARNING("target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (!breakpoint->set)
- {
- WARNING("breakpoint not set");
- return ERROR_OK;
- }
-
- if (breakpoint->type == BKPT_HARD)
- {
- if (breakpoint->set == 1)
- {
- xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], 0x0);
- xscale->ibcr0_used = 0;
- }
- else if (breakpoint->set == 2)
- {
- xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], 0x0);
- xscale->ibcr1_used = 0;
- }
- breakpoint->set = 0;
- }
- else
- {
- /* restore original instruction (kept in target endianness) */
- if (breakpoint->length == 4)
- {
- target->type->write_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr);
- }
- else
- {
- target->type->write_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr);
- }
- breakpoint->set = 0;
- }
-
- return ERROR_OK;
-}
-
-int xscale_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- if (target->state != TARGET_HALTED)
- {
- WARNING("target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (breakpoint->set)
- {
- xscale_unset_breakpoint(target, breakpoint);
- }
-
- if (breakpoint->type == BKPT_HARD)
- xscale->ibcr_available++;
-
- return ERROR_OK;
-}
-
-int xscale_set_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
- u8 enable = 0;
- reg_t *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON];
- u32 dbcon_value = buf_get_u32(dbcon->value, 0, 32);
-
- if (target->state != TARGET_HALTED)
- {
- WARNING("target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- xscale_get_reg(dbcon);
-
- switch (watchpoint->rw)
- {
- case WPT_READ:
- enable = 0x3;
- break;
- case WPT_ACCESS:
- enable = 0x2;
- break;
- case WPT_WRITE:
- enable = 0x1;
- break;
- default:
- ERROR("BUG: watchpoint->rw neither read, write nor access");
- }
-
- if (!xscale->dbr0_used)
- {
- xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR0], watchpoint->address);
- dbcon_value |= enable;
- xscale_set_reg_u32(dbcon, dbcon_value);
- watchpoint->set = 1;
- xscale->dbr0_used = 1;
- }
- else if (!xscale->dbr1_used)
- {
- xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR1], watchpoint->address);
- dbcon_value |= enable << 2;
- xscale_set_reg_u32(dbcon, dbcon_value);
- watchpoint->set = 2;
- xscale->dbr1_used = 1;
- }
- else
- {
- ERROR("BUG: no hardware comparator available");
- return ERROR_OK;
- }
-
- return ERROR_OK;
-}
-
-int xscale_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- if (target->state != TARGET_HALTED)
- {
- WARNING("target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (xscale->dbr_available < 1)
- {
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
-
- if ((watchpoint->length != 1) && (watchpoint->length != 2) && (watchpoint->length != 4))
- {
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
-
- xscale->dbr_available--;
-
- return ERROR_OK;
-}
-
-int xscale_unset_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
- reg_t *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON];
- u32 dbcon_value = buf_get_u32(dbcon->value, 0, 32);
-
- if (target->state != TARGET_HALTED)
- {
- WARNING("target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (!watchpoint->set)
- {
- WARNING("breakpoint not set");
- return ERROR_OK;
- }
-
- if (watchpoint->set == 1)
- {
- dbcon_value &= ~0x3;
- xscale_set_reg_u32(dbcon, dbcon_value);
- xscale->dbr0_used = 0;
- }
- else if (watchpoint->set == 2)
- {
- dbcon_value &= ~0xc;
- xscale_set_reg_u32(dbcon, dbcon_value);
- xscale->dbr1_used = 0;
- }
- watchpoint->set = 0;
-
- return ERROR_OK;
-}
-
-int xscale_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- if (target->state != TARGET_HALTED)
- {
- WARNING("target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (watchpoint->set)
- {
- xscale_unset_watchpoint(target, watchpoint);
- }
-
- xscale->dbr_available++;
-
- return ERROR_OK;
-}
-
-void xscale_enable_watchpoints(struct target_s *target)
-{
- watchpoint_t *watchpoint = target->watchpoints;
-
- while (watchpoint)
- {
- if (watchpoint->set == 0)
- xscale_set_watchpoint(target, watchpoint);
- watchpoint = watchpoint->next;
- }
-}
-
-void xscale_enable_breakpoints(struct target_s *target)
-{
- breakpoint_t *breakpoint = target->breakpoints;
-
- /* set any pending breakpoints */
- while (breakpoint)
- {
- if (breakpoint->set == 0)
- xscale_set_breakpoint(target, breakpoint);
- breakpoint = breakpoint->next;
- }
-}
-
-int xscale_get_reg(reg_t *reg)
-{
- xscale_reg_t *arch_info = reg->arch_info;
- target_t *target = arch_info->target;
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- /* DCSR, TX and RX are accessible via JTAG */
- if (strcmp(reg->name, "XSCALE_DCSR") == 0)
- {
- return xscale_read_dcsr(arch_info->target);
- }
- else if (strcmp(reg->name, "XSCALE_TX") == 0)
- {
- /* 1 = consume register content */
- return xscale_read_tx(arch_info->target, 1);
- }
- else if (strcmp(reg->name, "XSCALE_RX") == 0)
- {
- /* can't read from RX register (host -> debug handler) */
- return ERROR_OK;
- }
- else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0)
- {
- /* can't (explicitly) read from TXRXCTRL register */
- return ERROR_OK;
- }
- else /* Other DBG registers have to be transfered by the debug handler */
- {
- /* send CP read request (command 0x40) */
- xscale_send_u32(target, 0x40);
-
- /* send CP register number */
- xscale_send_u32(target, arch_info->dbg_handler_number);
-
- /* read register value */
- xscale_read_tx(target, 1);
- buf_cpy(xscale->reg_cache->reg_list[XSCALE_TX].value, reg->value, 32);
-
- reg->dirty = 0;
- reg->valid = 1;
- }
-
- return ERROR_OK;
-}
-
-int xscale_set_reg(reg_t *reg, u8* buf)
-{
- xscale_reg_t *arch_info = reg->arch_info;
- target_t *target = arch_info->target;
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
- u32 value = buf_get_u32(buf, 0, 32);
-
- /* DCSR, TX and RX are accessible via JTAG */
- if (strcmp(reg->name, "XSCALE_DCSR") == 0)
- {
- buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32, value);
- return xscale_write_dcsr(arch_info->target, -1, -1);
- }
- else if (strcmp(reg->name, "XSCALE_RX") == 0)
- {
- buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value);
- return xscale_write_rx(arch_info->target);
- }
- else if (strcmp(reg->name, "XSCALE_TX") == 0)
- {
- /* can't write to TX register (debug-handler -> host) */
- return ERROR_OK;
- }
- else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0)
- {
- /* can't (explicitly) write to TXRXCTRL register */
- return ERROR_OK;
- }
- else /* Other DBG registers have to be transfered by the debug handler */
- {
- /* send CP write request (command 0x41) */
- xscale_send_u32(target, 0x41);
-
- /* send CP register number */
- xscale_send_u32(target, arch_info->dbg_handler_number);
-
- /* send CP register value */
- xscale_send_u32(target, value);
- buf_set_u32(reg->value, 0, 32, value);
- }
-
- return ERROR_OK;
-}
-
-/* convenience wrapper to access XScale specific registers */
-int xscale_set_reg_u32(reg_t *reg, u32 value)
-{
- u8 buf[4];
-
- buf_set_u32(buf, 0, 32, value);
-
- return xscale_set_reg(reg, buf);
-}
-
-int xscale_write_dcsr_sw(target_t *target, u32 value)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
- reg_t *dcsr = &xscale->reg_cache->reg_list[XSCALE_DCSR];
- xscale_reg_t *dcsr_arch_info = dcsr->arch_info;
-
- /* send CP write request (command 0x41) */
- xscale_send_u32(target, 0x41);
-
- /* send CP register number */
- xscale_send_u32(target, dcsr_arch_info->dbg_handler_number);
-
- /* send CP register value */
- xscale_send_u32(target, value);
- buf_set_u32(dcsr->value, 0, 32, value);
-
- return ERROR_OK;
-}
-
-int xscale_read_trace(target_t *target)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
- xscale_trace_data_t **trace_data_p;
-
- /* 258 words from debug handler
- * 256 trace buffer entries
- * 2 checkpoint addresses
- */
- u32 trace_buffer[258];
- int is_address[256];
- int i, j;
-
- if (target->state != TARGET_HALTED)
- {
- WARNING("target must be stopped to read trace data");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- /* send read trace buffer command (command 0x61) */
- xscale_send_u32(target, 0x61);
-
- /* receive trace buffer content */
- xscale_receive(target, trace_buffer, 258);
-
- /* parse buffer backwards to identify address entries */
- for (i = 255; i >= 0; i--)
- {
- is_address[i] = 0;
- if (((trace_buffer[i] & 0xf0) == 0x90) ||
- ((trace_buffer[i] & 0xf0) == 0xd0))
- {
- if (i >= 3)
- is_address[--i] = 1;
- if (i >= 2)
- is_address[--i] = 1;
- if (i >= 1)
- is_address[--i] = 1;
- if (i >= 0)
- is_address[--i] = 1;
- }
- }
-
-
- /* search first non-zero entry */
- for (j = 0; (j < 256) && (trace_buffer[j] == 0) && (!is_address[j]); j++)
- ;
-
- if (j == 256)
- {
- DEBUG("no trace data collected");
- return ERROR_XSCALE_NO_TRACE_DATA;
- }
-
- for (trace_data_p = &xscale->trace.data; *trace_data_p; trace_data_p = &(*trace_data_p)->next)
- ;
-
- *trace_data_p = malloc(sizeof(xscale_trace_data_t));
- (*trace_data_p)->next = NULL;
- (*trace_data_p)->chkpt0 = trace_buffer[256];
- (*trace_data_p)->chkpt1 = trace_buffer[257];
- (*trace_data_p)->last_instruction = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
- (*trace_data_p)->entries = malloc(sizeof(xscale_trace_entry_t) * (256 - j));
- (*trace_data_p)->depth = 256 - j;
-
- for (i = j; i < 256; i++)
- {
- (*trace_data_p)->entries[i - j].data = trace_buffer[i];
- if (is_address[i])
- (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_ADDRESS;
- else
- (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_MESSAGE;
- }
-
- return ERROR_OK;
-}
-
-int xscale_read_instruction(target_t *target, arm_instruction_t *instruction)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
- int i;
- int section = -1;
- u32 size_read;
- u32 opcode;
- int retval;
-
- if (!xscale->trace.image)
- return ERROR_TRACE_IMAGE_UNAVAILABLE;
-
- /* search for the section the current instruction belongs to */
- for (i = 0; i < xscale->trace.image->num_sections; i++)
- {
- if ((xscale->trace.image->sections[i].base_address <= xscale->trace.current_pc) &&
- (xscale->trace.image->sections[i].base_address + xscale->trace.image->sections[i].size > xscale->trace.current_pc))
- {
- section = i;
- break;
- }
- }
-
- if (section == -1)
- {
- /* current instruction couldn't be found in the image */
- return ERROR_TRACE_INSTRUCTION_UNAVAILABLE;
- }
-
- if (xscale->trace.core_state == ARMV4_5_STATE_ARM)
- {
- u8 buf[4];
- if ((retval = image_read_section(xscale->trace.image, section,
- xscale->trace.current_pc - xscale->trace.image->sections[section].base_address,
- 4, buf, &size_read)) != ERROR_OK)
- {
- ERROR("error while reading instruction: %i", retval);
- return ERROR_TRACE_INSTRUCTION_UNAVAILABLE;
- }
- opcode = target_buffer_get_u32(target, buf);
- arm_evaluate_opcode(opcode, xscale->trace.current_pc, instruction);
- }
- else if (xscale->trace.core_state == ARMV4_5_STATE_THUMB)
- {
- u8 buf[2];
- if ((retval = image_read_section(xscale->trace.image, section,
- xscale->trace.current_pc - xscale->trace.image->sections[section].base_address,
- 2, buf, &size_read)) != ERROR_OK)
- {
- ERROR("error while reading instruction: %i", retval);
- return ERROR_TRACE_INSTRUCTION_UNAVAILABLE;
- }
- opcode = target_buffer_get_u16(target, buf);
- thumb_evaluate_opcode(opcode, xscale->trace.current_pc, instruction);
- }
- else
- {
- ERROR("BUG: unknown core state encountered");
- exit(-1);
- }
-
- return ERROR_OK;
-}
-
-int xscale_branch_address(xscale_trace_data_t *trace_data, int i, u32 *target)
-{
- /* if there are less than four entries prior to the indirect branch message
- * we can't extract the address */
- if (i < 4)
- {
- return -1;
- }
-
- *target = (trace_data->entries[i-1].data) | (trace_data->entries[i-2].data << 8) |
- (trace_data->entries[i-3].data << 16) | (trace_data->entries[i-4].data << 24);
-
- return 0;
-}
-
-int xscale_analyze_trace(target_t *target, command_context_t *cmd_ctx)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
- int next_pc_ok = 0;
- u32 next_pc = 0x0;
- xscale_trace_data_t *trace_data = xscale->trace.data;
- int retval;
-
- while (trace_data)
- {
- int i, chkpt;
- int rollover;
- int branch;
- int exception;
- xscale->trace.core_state = ARMV4_5_STATE_ARM;
-
- chkpt = 0;
- rollover = 0;
-
- for (i = 0; i < trace_data->depth; i++)
- {
- next_pc_ok = 0;
- branch = 0;
- exception = 0;
-
- if (trace_data->entries[i].type == XSCALE_TRACE_ADDRESS)
- continue;
-
- switch ((trace_data->entries[i].data & 0xf0) >> 4)
- {
- case 0: /* Exceptions */
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- exception = (trace_data->entries[i].data & 0x70) >> 4;
- next_pc_ok = 1;
- next_pc = (trace_data->entries[i].data & 0xf0) >> 2;
- command_print(cmd_ctx, "--- exception %i ---", (trace_data->entries[i].data & 0xf0) >> 4);
- break;
- case 8: /* Direct Branch */
- branch = 1;
- break;
- case 9: /* Indirect Branch */
- branch = 1;
- if (xscale_branch_address(trace_data, i, &next_pc) == 0)
- {
- next_pc_ok = 1;
- }
- break;
- case 13: /* Checkpointed Indirect Branch */
- if (xscale_branch_address(trace_data, i, &next_pc) == 0)
- {
- next_pc_ok = 1;
- if (((chkpt == 0) && (next_pc != trace_data->chkpt0))
- || ((chkpt == 1) && (next_pc != trace_data->chkpt1)))
- WARNING("checkpointed indirect branch target address doesn't match checkpoint");
- }
- /* explicit fall-through */
- case 12: /* Checkpointed Direct Branch */
- branch = 1;
- if (chkpt == 0)
- {
- next_pc_ok = 1;
- next_pc = trace_data->chkpt0;
- chkpt++;
- }
- else if (chkpt == 1)
- {
- next_pc_ok = 1;
- next_pc = trace_data->chkpt0;
- chkpt++;
- }
- else
- {
- WARNING("more than two checkpointed branches encountered");
- }
- break;
- case 15: /* Roll-over */
- rollover++;
- continue;
- default: /* Reserved */
- command_print(cmd_ctx, "--- reserved trace message ---");
- ERROR("BUG: trace message %i is reserved", (trace_data->entries[i].data & 0xf0) >> 4);
- return ERROR_OK;
- }
-
- if (xscale->trace.pc_ok)
- {
- int executed = (trace_data->entries[i].data & 0xf) + rollover * 16;
- arm_instruction_t instruction;
-
- if ((exception == 6) || (exception == 7))
- {
- /* IRQ or FIQ exception, no instruction executed */
- executed -= 1;
- }
-
- while (executed-- >= 0)
- {
- if ((retval = xscale_read_instruction(target, &instruction)) != ERROR_OK)
- {
- /* can't continue tracing with no image available */
- if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE)
- {
- return retval;
- }
- else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE)
- {
- /* TODO: handle incomplete images */
- }
- }
-
- /* a precise abort on a load to the PC is included in the incremental
- * word count, other instructions causing data aborts are not included
- */
- if ((executed == 0) && (exception == 4)
- && ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDM)))
- {
- if ((instruction.type == ARM_LDM)
- && ((instruction.info.load_store_multiple.register_list & 0x8000) == 0))
- {
- executed--;
- }
- else if (((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDRSH))
- && (instruction.info.load_store.Rd != 15))
- {
- executed--;
- }
- }
-
- /* only the last instruction executed
- * (the one that caused the control flow change)
- * could be a taken branch
- */
- if (((executed == -1) && (branch == 1)) &&
- (((instruction.type == ARM_B) ||
- (instruction.type == ARM_BL) ||
- (instruction.type == ARM_BLX)) &&
- (instruction.info.b_bl_bx_blx.target_address != -1)))
- {
- xscale->trace.current_pc = instruction.info.b_bl_bx_blx.target_address;
- }
- else
- {
- xscale->trace.current_pc += (xscale->trace.core_state == ARMV4_5_STATE_ARM) ? 4 : 2;
- }
- command_print(cmd_ctx, "%s", instruction.text);
- }
-
- rollover = 0;
- }
-
- if (next_pc_ok)
- {
- xscale->trace.current_pc = next_pc;
- xscale->trace.pc_ok = 1;
- }
- }
-
- for (; xscale->trace.current_pc < trace_data->last_instruction; xscale->trace.current_pc += (xscale->trace.core_state == ARMV4_5_STATE_ARM) ? 4 : 2)
- {
- arm_instruction_t instruction;
- if ((retval = xscale_read_instruction(target, &instruction)) != ERROR_OK)
- {
- /* can't continue tracing with no image available */
- if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE)
- {
- return retval;
- }
- else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE)
- {
- /* TODO: handle incomplete images */
- }
- }
- command_print(cmd_ctx, "%s", instruction.text);
- }
-
- trace_data = trace_data->next;
- }
-
- return ERROR_OK;
-}
-
-void xscale_build_reg_cache(target_t *target)
-{
- /* get pointers to arch-specific information */
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache);
- xscale_reg_t *arch_info = malloc(sizeof(xscale_reg_arch_info));
- int i;
- int num_regs = sizeof(xscale_reg_arch_info) / sizeof(xscale_reg_t);
-
- (*cache_p) = armv4_5_build_reg_cache(target, armv4_5);
- armv4_5->core_cache = (*cache_p);
-
- /* register a register arch-type for XScale dbg registers only once */
- if (xscale_reg_arch_type == -1)
- xscale_reg_arch_type = register_reg_arch_type(xscale_get_reg, xscale_set_reg);
-
- (*cache_p)->next = malloc(sizeof(reg_cache_t));
- cache_p = &(*cache_p)->next;
-
- /* fill in values for the xscale reg cache */
- (*cache_p)->name = "XScale registers";
- (*cache_p)->next = NULL;
- (*cache_p)->reg_list = malloc(num_regs * sizeof(reg_t));
- (*cache_p)->num_regs = num_regs;
-
- for (i = 0; i < num_regs; i++)
- {
- (*cache_p)->reg_list[i].name = xscale_reg_list[i];
- (*cache_p)->reg_list[i].value = calloc(4, 1);
- (*cache_p)->reg_list[i].dirty = 0;
- (*cache_p)->reg_list[i].valid = 0;
- (*cache_p)->reg_list[i].size = 32;
- (*cache_p)->reg_list[i].bitfield_desc = NULL;
- (*cache_p)->reg_list[i].num_bitfields = 0;
- (*cache_p)->reg_list[i].arch_info = &arch_info[i];
- (*cache_p)->reg_list[i].arch_type = xscale_reg_arch_type;
- arch_info[i] = xscale_reg_arch_info[i];
- arch_info[i].target = target;
- }
-
- xscale->reg_cache = (*cache_p);
-}
-
-int xscale_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
-{
- if (startup_mode != DAEMON_RESET)
- {
- ERROR("XScale target requires a reset");
- ERROR("Reset target to enable debug");
- }
-
- /* assert TRST once during startup */
- jtag_add_reset(1, 0);
- jtag_add_sleep(5000);
- jtag_add_reset(0, 0);
- jtag_execute_queue();
-
- return ERROR_OK;
-}
-
-int xscale_quit()
-{
-
- return ERROR_OK;
-}
-
-int xscale_init_arch_info(target_t *target, xscale_common_t *xscale, int chain_pos, char *variant)
-{
- armv4_5_common_t *armv4_5;
- u32 high_reset_branch, low_reset_branch;
- int i;
-
- armv4_5 = &xscale->armv4_5_common;
-
- /* store architecture specfic data (none so far) */
- xscale->arch_info = NULL;
- xscale->common_magic = XSCALE_COMMON_MAGIC;
-
- /* remember the variant (PXA25x, PXA27x, IXP42x, ...) */
- xscale->variant = strdup(variant);
-
- /* prepare JTAG information for the new target */
- xscale->jtag_info.chain_pos = chain_pos;
- jtag_register_event_callback(xscale_jtag_callback, target);
-
- xscale->jtag_info.dbgrx = 0x02;
- xscale->jtag_info.dbgtx = 0x10;
- xscale->jtag_info.dcsr = 0x09;
- xscale->jtag_info.ldic = 0x07;
-
- if ((strcmp(xscale->variant, "pxa250") == 0) ||
- (strcmp(xscale->variant, "pxa255") == 0) ||
- (strcmp(xscale->variant, "pxa26x") == 0))
- {
- xscale->jtag_info.ir_length = 5;
- }
- else if ((strcmp(xscale->variant, "pxa27x") == 0) ||
- (strcmp(xscale->variant, "ixp42x") == 0) ||
- (strcmp(xscale->variant, "ixp45x") == 0) ||
- (strcmp(xscale->variant, "ixp46x") == 0))
- {
- xscale->jtag_info.ir_length = 7;
- }
-
- /* the debug handler isn't installed (and thus not running) at this time */
- xscale->handler_installed = 0;
- xscale->handler_running = 0;
- xscale->handler_address = 0xfe000800;
-
- /* clear the vectors we keep locally for reference */
- memset(xscale->low_vectors, 0, sizeof(xscale->low_vectors));
- memset(xscale->high_vectors, 0, sizeof(xscale->high_vectors));
-
- /* no user-specified vectors have been configured yet */
- xscale->static_low_vectors_set = 0x0;
- xscale->static_high_vectors_set = 0x0;
-
- /* calculate branches to debug handler */
- low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2;
- high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2;
-
- xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0);
- xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0);
-
- for (i = 1; i <= 7; i++)
- {
- xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0);
- xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0);
- }
-
- /* 64kB aligned region used for DCache cleaning */
- xscale->cache_clean_address = 0xfffe0000;
-
- xscale->hold_rst = 0;
- xscale->external_debug_break = 0;
-
- xscale->force_hw_bkpts = 1;
-
- xscale->ibcr_available = 2;
- xscale->ibcr0_used = 0;
- xscale->ibcr1_used = 0;
-
- xscale->dbr_available = 2;
- xscale->dbr0_used = 0;
- xscale->dbr1_used = 0;
-
- xscale->arm_bkpt = ARMV5_BKPT(0x0);
- xscale->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff;
-
- xscale->vector_catch = 0x1;
-
- xscale->trace.capture_status = TRACE_IDLE;
- xscale->trace.data = NULL;
- xscale->trace.image = NULL;
- xscale->trace.buffer_enabled = 0;
- xscale->trace.buffer_fill = 0;
-
- /* prepare ARMv4/5 specific information */
- armv4_5->arch_info = xscale;
- armv4_5->read_core_reg = xscale_read_core_reg;
- armv4_5->write_core_reg = xscale_write_core_reg;
- armv4_5->full_context = xscale_full_context;
-
- armv4_5_init_arch_info(target, armv4_5);
-
- xscale->armv4_5_mmu.armv4_5_cache.ctype = -1;
- xscale->armv4_5_mmu.get_ttb = xscale_get_ttb;
- xscale->armv4_5_mmu.read_memory = xscale_read_memory;
- xscale->armv4_5_mmu.write_memory = xscale_write_memory;
- xscale->armv4_5_mmu.disable_mmu_caches = xscale_disable_mmu_caches;
- xscale->armv4_5_mmu.enable_mmu_caches = xscale_enable_mmu_caches;
- xscale->armv4_5_mmu.has_tiny_pages = 1;
- xscale->armv4_5_mmu.mmu_enabled = 0;
-
- xscale->fast_memory_access = 0;
-
- return ERROR_OK;
-}
-
-/* target xscale <endianess> <startup_mode> <chain_pos> <variant> */
-int xscale_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
-{
- int chain_pos;
- char *variant = NULL;
- xscale_common_t *xscale = malloc(sizeof(xscale_common_t));
-
- if (argc < 5)
- {
- ERROR("'target xscale' requires four arguments: <endianess> <startup_mode> <chain_pos> <variant>");
- return ERROR_OK;
- }
-
- chain_pos = strtoul(args[3], NULL, 0);
-
- variant = args[4];
-
- xscale_init_arch_info(target, xscale, chain_pos, variant);
- xscale_build_reg_cache(target);
-
- return ERROR_OK;
-}
-
-int xscale_handle_debug_handler_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = NULL;
- armv4_5_common_t *armv4_5;
- xscale_common_t *xscale;
-
- u32 handler_address;
-
- if (argc < 2)
- {
- ERROR("'xscale debug_handler <target#> <address>' command takes two required operands");
- return ERROR_OK;
- }
-
- if ((target = get_target_by_num(strtoul(args[0], NULL, 0))) == NULL)
- {
- ERROR("no target '%s' configured", args[0]);
- return ERROR_OK;
- }
-
- if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
- {
- return ERROR_OK;
- }
-
- handler_address = strtoul(args[1], NULL, 0);
-
- if (((handler_address >= 0x800) && (handler_address <= 0x1fef800)) ||
- ((handler_address >= 0xfe000800) && (handler_address <= 0xfffff800)))
- {
- xscale->handler_address = handler_address;
- }
- else
- {
- ERROR("xscale debug_handler <address> must be between 0x800 and 0x1fef800 or between 0xfe000800 and 0xfffff800");
- }
-
- return ERROR_OK;
-}
-
-int xscale_handle_cache_clean_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = NULL;
- armv4_5_common_t *armv4_5;
- xscale_common_t *xscale;
-
- u32 cache_clean_address;
-
- if (argc < 2)
- {
- ERROR("'xscale cache_clean_address <target#> <address>' command takes two required operands");
- return ERROR_OK;
- }
-
- if ((target = get_target_by_num(strtoul(args[0], NULL, 0))) == NULL)
- {
- ERROR("no target '%s' configured", args[0]);
- return ERROR_OK;
- }
-
- if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
- {
- return ERROR_OK;
- }
-
- cache_clean_address = strtoul(args[1], NULL, 0);
-
- if (cache_clean_address & 0xffff)
- {
- ERROR("xscale cache_clean_address <address> must be 64kb aligned");
- }
- else
- {
- xscale->cache_clean_address = cache_clean_address;
- }
-
- return ERROR_OK;
-}
-
-int xscale_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- xscale_common_t *xscale;
-
- if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
- {
- return ERROR_OK;
- }
-
- return armv4_5_handle_cache_info_command(cmd_ctx, &xscale->armv4_5_mmu.armv4_5_cache);
-}
-
-static int xscale_virt2phys(struct target_s *target, u32 virtual, u32 *physical)
-{
- armv4_5_common_t *armv4_5;
- xscale_common_t *xscale;
- int retval;
- int type;
- u32 cb;
- int domain;
- u32 ap;
-
- if ((retval = xscale_get_arch_pointers(target, &armv4_5, &xscale)) != ERROR_OK)
- {
- return retval;
- }
- u32 ret = armv4_5_mmu_translate_va(target, &xscale->armv4_5_mmu, virtual, &type, &cb, &domain, &ap);
- if (type == -1)
- {
- return ret;
- }
-
- *physical = ret;
- return ERROR_OK;
-}
-
-static int xscale_mmu(struct target_s *target, int *enabled)
-{
- armv4_5_common_t *armv4_5 = target->arch_info;
- xscale_common_t *xscale = armv4_5->arch_info;
-
- if (target->state != TARGET_HALTED)
- {
- ERROR("Target not halted");
- return ERROR_TARGET_INVALID;
- }
-
- *enabled = xscale->armv4_5_mmu.mmu_enabled;
- return ERROR_OK;
-}
-
-int xscale_handle_mmu_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- xscale_common_t *xscale;
-
- if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
- {
- return ERROR_OK;
- }
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- if (argc >= 1)
- {
- if (strcmp("enable", args[0]) == 0)
- {
- xscale_enable_mmu_caches(target, 1, 0, 0);
- xscale->armv4_5_mmu.mmu_enabled = 1;
- }
- else if (strcmp("disable", args[0]) == 0)
- {
- xscale_disable_mmu_caches(target, 1, 0, 0);
- xscale->armv4_5_mmu.mmu_enabled = 0;
- }
- }
-
- command_print(cmd_ctx, "mmu %s", (xscale->armv4_5_mmu.mmu_enabled) ? "enabled" : "disabled");
-
- return ERROR_OK;
-}
-
-int xscale_handle_idcache_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- xscale_common_t *xscale;
- int icache = 0, dcache = 0;
-
- if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
- {
- return ERROR_OK;
- }
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- if (strcmp(cmd, "icache") == 0)
- icache = 1;
- else if (strcmp(cmd, "dcache") == 0)
- dcache = 1;
-
- if (argc >= 1)
- {
- if (strcmp("enable", args[0]) == 0)
- {
- xscale_enable_mmu_caches(target, 0, dcache, icache);
-
- if (icache)
- xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 1;
- else if (dcache)
- xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 1;
- }
- else if (strcmp("disable", args[0]) == 0)
- {
- xscale_disable_mmu_caches(target, 0, dcache, icache);
-
- if (icache)
- xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0;
- else if (dcache)
- xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0;
- }
- }
-
- if (icache)
- command_print(cmd_ctx, "icache %s", (xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled) ? "enabled" : "disabled");
-
- if (dcache)
- command_print(cmd_ctx, "dcache %s", (xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) ? "enabled" : "disabled");
-
- return ERROR_OK;
-}
-
-int xscale_handle_vector_catch_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- xscale_common_t *xscale;
-
- if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
- {
- return ERROR_OK;
- }
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "usage: xscale vector_catch [mask]");
- }
- else
- {
- xscale->vector_catch = strtoul(args[0], NULL, 0);
- buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 8, xscale->vector_catch);
- xscale_write_dcsr(target, -1, -1);
- }
-
- command_print(cmd_ctx, "vector catch mask: 0x%2.2x", xscale->vector_catch);
-
- return ERROR_OK;
-}
-
-int xscale_handle_force_hw_bkpts_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- xscale_common_t *xscale;
-
- if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
- {
- return ERROR_OK;
- }
-
- if ((argc >= 1) && (strcmp("enable", args[0]) == 0))
- {
- xscale->force_hw_bkpts = 1;
- }
- else if ((argc >= 1) && (strcmp("disable", args[0]) == 0))
- {
- xscale->force_hw_bkpts = 0;
- }
- else
- {
- command_print(cmd_ctx, "usage: xscale force_hw_bkpts <enable|disable>");
- }
-
- command_print(cmd_ctx, "force hardware breakpoints %s", (xscale->force_hw_bkpts) ? "enabled" : "disabled");
-
- return ERROR_OK;
-}
-
-int xscale_handle_trace_buffer_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- xscale_common_t *xscale;
- u32 dcsr_value;
-
- if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
- {
- return ERROR_OK;
- }
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- if ((argc >= 1) && (strcmp("enable", args[0]) == 0))
- {
- xscale_trace_data_t *td, *next_td;
- xscale->trace.buffer_enabled = 1;
-
- /* free old trace data */
- td = xscale->trace.data;
- while (td)
- {
- next_td = td->next;
-
- if (td->entries)
- free(td->entries);
- free(td);
- td = next_td;
- }
- xscale->trace.data = NULL;
- }
- else if ((argc >= 1) && (strcmp("disable", args[0]) == 0))
- {
- xscale->trace.buffer_enabled = 0;
- }
-
- if ((argc >= 2) && (strcmp("fill", args[1]) == 0))
- {
- if (argc >= 3)
- xscale->trace.buffer_fill = strtoul(args[2], NULL, 0);
- else
- xscale->trace.buffer_fill = 1;
- }
- else if ((argc >= 2) && (strcmp("wrap", args[1]) == 0))
- {
- xscale->trace.buffer_fill = -1;
- }
-
- if (xscale->trace.buffer_enabled)
- {
- /* if we enable the trace buffer in fill-once
- * mode we know the address of the first instruction */
- xscale->trace.pc_ok = 1;
- xscale->trace.current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32);
- }
- else
- {
- /* otherwise the address is unknown, and we have no known good PC */
- xscale->trace.pc_ok = 0;
- }
-
- command_print(cmd_ctx, "trace buffer %s (%s)",
- (xscale->trace.buffer_enabled) ? "enabled" : "disabled",
- (xscale->trace.buffer_fill > 0) ? "fill" : "wrap");
-
- dcsr_value = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32);
- if (xscale->trace.buffer_fill >= 0)
- xscale_write_dcsr_sw(target, (dcsr_value & 0xfffffffc) | 2);
- else
- xscale_write_dcsr_sw(target, dcsr_value & 0xfffffffc);
-
- return ERROR_OK;
-}
-
-int xscale_handle_trace_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target;
- armv4_5_common_t *armv4_5;
- xscale_common_t *xscale;
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "usage: xscale trace_image <file> [base address] [type]");
- return ERROR_OK;
- }
-
- target = get_current_target(cmd_ctx);
-
- if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
- {
- return ERROR_OK;
- }
-
- if (xscale->trace.image)
- {
- image_close(xscale->trace.image);
- free(xscale->trace.image);
- command_print(cmd_ctx, "previously loaded image found and closed");
- }
-
- xscale->trace.image = malloc(sizeof(image_t));
- xscale->trace.image->base_address_set = 0;
- xscale->trace.image->start_address_set = 0;
-
- /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */
- if (argc >= 2)
- {
- xscale->trace.image->base_address_set = 1;
- xscale->trace.image->base_address = strtoul(args[1], NULL, 0);
- }
- else
- {
- xscale->trace.image->base_address_set = 0;
- }
-
- if (image_open(xscale->trace.image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK)
- {
- command_print(cmd_ctx, "image opening error: %s", xscale->trace.image->error_str);
- free(xscale->trace.image);
- xscale->trace.image = NULL;
- return ERROR_OK;
- }
-
- return ERROR_OK;
-}
-
-int xscale_handle_dump_trace_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- xscale_common_t *xscale;
- xscale_trace_data_t *trace_data;
- fileio_t file;
-
- if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
- {
- return ERROR_OK;
- }
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
-
- if (argc < 1)
- {
- command_print(cmd_ctx, "usage: xscale dump_trace <file>");
- return ERROR_OK;
- }
-
- trace_data = xscale->trace.data;
-
- if (!trace_data)
- {
- command_print(cmd_ctx, "no trace data collected");
- return ERROR_OK;
- }
-
- if (fileio_open(&file, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK)
- {
- command_print(cmd_ctx, "file open error: %s", file.error_str);
- return ERROR_OK;
- }
-
- while (trace_data)
- {
- int i;
-
- fileio_write_u32(&file, trace_data->chkpt0);
- fileio_write_u32(&file, trace_data->chkpt1);
- fileio_write_u32(&file, trace_data->last_instruction);
- fileio_write_u32(&file, trace_data->depth);
-
- for (i = 0; i < trace_data->depth; i++)
- fileio_write_u32(&file, trace_data->entries[i].data | ((trace_data->entries[i].type & 0xffff) << 16));
-
- trace_data = trace_data->next;
- }
-
- fileio_close(&file);
-
- return ERROR_OK;
-}
-
-int xscale_handle_analyze_trace_buffer_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- xscale_common_t *xscale;
-
- if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
- {
- return ERROR_OK;
- }
-
- xscale_analyze_trace(target, cmd_ctx);
-
- return ERROR_OK;
-}
-
-int xscale_handle_cp15(command_context_t *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- xscale_common_t *xscale;
-
- if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
- {
- return ERROR_OK;
- }
-
- if (target->state != TARGET_HALTED)
- {
- command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
- return ERROR_OK;
- }
- u32 reg_no = 0;
- reg_t *reg = NULL;
- if(argc > 0)
- {
- reg_no = strtoul(args[0], NULL, 0);
- /*translate from xscale cp15 register no to openocd register*/
- switch(reg_no)
- {
- case 0:
- reg_no = XSCALE_MAINID;
- break;
- case 1:
- reg_no = XSCALE_CTRL;
- break;
- case 2:
- reg_no = XSCALE_TTB;
- break;
- case 3:
- reg_no = XSCALE_DAC;
- break;
- case 5:
- reg_no = XSCALE_FSR;
- break;
- case 6:
- reg_no = XSCALE_FAR;
- break;
- case 13:
- reg_no = XSCALE_PID;
- break;
- case 15:
- reg_no = XSCALE_CPACCESS;
- break;
- default:
- command_print(cmd_ctx, "invalid register number");
- return ERROR_INVALID_ARGUMENTS;
- }
- reg = &xscale->reg_cache->reg_list[reg_no];
-
- }
- if(argc == 1)
- {
- u32 value;
-
- /* read cp15 control register */
- xscale_get_reg(reg);
- value = buf_get_u32(reg->value, 0, 32);
- command_print(cmd_ctx, "%s (/%i): 0x%x", reg->name, reg->size, value);
- }
- else if(argc == 2)
- {
-
- u32 value = strtoul(args[1], NULL, 0);
-
- /* send CP write request (command 0x41) */
- xscale_send_u32(target, 0x41);
-
- /* send CP register number */
- xscale_send_u32(target, reg_no);
-
- /* send CP register value */
- xscale_send_u32(target, value);
-
- /* execute cpwait to ensure outstanding operations complete */
- xscale_send_u32(target, 0x53);
- }
- else
- {
- command_print(cmd_ctx, "usage: cp15 [register]<, [value]>");
- }
-
- return ERROR_OK;
-}
-
-int handle_xscale_fast_memory_access_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- target_t *target = get_current_target(cmd_ctx);
- armv4_5_common_t *armv4_5;
- xscale_common_t *xscale;
-
- if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK)
- {
- return ERROR_OK;
- }
-
- if (argc == 1)
- {
- if (strcmp("enable", args[0]) == 0)
- {
- xscale->fast_memory_access = 1;
- }
- else if (strcmp("disable", args[0]) == 0)
- {
- xscale->fast_memory_access = 0;
- }
- else
- {
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
- } else if (argc!=0)
- {
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- command_print(cmd_ctx, "fast memory access is %s", (xscale->fast_memory_access) ? "enabled" : "disabled");
-
- return ERROR_OK;
-}
-
-int xscale_register_commands(struct command_context_s *cmd_ctx)
-{
- command_t *xscale_cmd;
-
- xscale_cmd = register_command(cmd_ctx, NULL, "xscale", NULL, COMMAND_ANY, "xscale specific commands");
-
- register_command(cmd_ctx, xscale_cmd, "debug_handler", xscale_handle_debug_handler_command, COMMAND_ANY, "'xscale debug_handler <target#> <address>' command takes two required operands");
- register_command(cmd_ctx, xscale_cmd, "cache_clean_address", xscale_handle_cache_clean_address_command, COMMAND_ANY, NULL);
-
- register_command(cmd_ctx, xscale_cmd, "cache_info", xscale_handle_cache_info_command, COMMAND_EXEC, NULL);
- register_command(cmd_ctx, xscale_cmd, "mmu", xscale_handle_mmu_command, COMMAND_EXEC, "['enable'|'disable'] the MMU");
- register_command(cmd_ctx, xscale_cmd, "icache", xscale_handle_idcache_command, COMMAND_EXEC, "['enable'|'disable'] the ICache");
- register_command(cmd_ctx, xscale_cmd, "dcache", xscale_handle_idcache_command, COMMAND_EXEC, "['enable'|'disable'] the DCache");
-
- register_command(cmd_ctx, xscale_cmd, "vector_catch", xscale_handle_idcache_command, COMMAND_EXEC, "<mask> of vectors that should be catched");
-
- register_command(cmd_ctx, xscale_cmd, "trace_buffer", xscale_handle_trace_buffer_command, COMMAND_EXEC, "<enable|disable> ['fill' [n]|'wrap']");
-
- register_command(cmd_ctx, xscale_cmd, "dump_trace", xscale_handle_dump_trace_command, COMMAND_EXEC, "dump content of trace buffer to <file>");
- register_command(cmd_ctx, xscale_cmd, "analyze_trace", xscale_handle_analyze_trace_buffer_command, COMMAND_EXEC, "analyze content of trace buffer");
- register_command(cmd_ctx, xscale_cmd, "trace_image", xscale_handle_trace_image_command,
- COMMAND_EXEC, "load image from <file> [base address]");
-
- register_command(cmd_ctx, xscale_cmd, "cp15", xscale_handle_cp15, COMMAND_EXEC, "access coproc 15 <register> [value]");
- register_command(cmd_ctx, xscale_cmd, "fast_memory_access", handle_xscale_fast_memory_access_command,
- COMMAND_ANY, "use fast memory accesses instead of slower but potentially unsafe slow accesses <enable|disable>");
-
- armv4_5_register_commands(cmd_ctx);
-
- return ERROR_OK;
-}
+/*************************************************************************** + * Copyright (C) 2006, 2007 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 "xscale.h" + +#include "register.h" +#include "target.h" +#include "armv4_5.h" +#include "arm_simulator.h" +#include "arm_disassembler.h" +#include "log.h" +#include "jtag.h" +#include "binarybuffer.h" +#include "time_support.h" +#include "breakpoints.h" +#include "fileio.h" + +#include <stdlib.h> +#include <string.h> + +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> + + +/* cli handling */ +int xscale_register_commands(struct command_context_s *cmd_ctx); + +/* forward declarations */ +int xscale_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int xscale_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int xscale_quit(); + +int xscale_arch_state(struct target_s *target); +int xscale_poll(target_t *target); +int xscale_halt(target_t *target); +int xscale_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution); +int xscale_step(struct target_s *target, int current, u32 address, int handle_breakpoints); +int xscale_debug_entry(target_t *target); +int xscale_restore_context(target_t *target); + +int xscale_assert_reset(target_t *target); +int xscale_deassert_reset(target_t *target); +int xscale_soft_reset_halt(struct target_s *target); +int xscale_prepare_reset_halt(struct target_s *target); + +int xscale_set_reg_u32(reg_t *reg, u32 value); + +int xscale_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode); +int xscale_write_core_reg(struct target_s *target, int num, enum armv4_5_mode mode, u32 value); + +int xscale_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int xscale_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int xscale_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer); +int xscale_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum); + +int xscale_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int xscale_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int xscale_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int xscale_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int xscale_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint); +int xscale_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint); +void xscale_enable_watchpoints(struct target_s *target); +void xscale_enable_breakpoints(struct target_s *target); +static int xscale_virt2phys(struct target_s *target, u32 virtual, u32 *physical); +static int xscale_mmu(struct target_s *target, int *enabled); + +int xscale_read_trace(target_t *target); + +target_type_t xscale_target = +{ + .name = "xscale", + + .poll = xscale_poll, + .arch_state = xscale_arch_state, + + .target_request_data = NULL, + + .halt = xscale_halt, + .resume = xscale_resume, + .step = xscale_step, + + .assert_reset = xscale_assert_reset, + .deassert_reset = xscale_deassert_reset, + .soft_reset_halt = xscale_soft_reset_halt, + .prepare_reset_halt = xscale_prepare_reset_halt, + + .get_gdb_reg_list = armv4_5_get_gdb_reg_list, + + .read_memory = xscale_read_memory, + .write_memory = xscale_write_memory, + .bulk_write_memory = xscale_bulk_write_memory, + .checksum_memory = xscale_checksum_memory, + + .run_algorithm = armv4_5_run_algorithm, + + .add_breakpoint = xscale_add_breakpoint, + .remove_breakpoint = xscale_remove_breakpoint, + .add_watchpoint = xscale_add_watchpoint, + .remove_watchpoint = xscale_remove_watchpoint, + + .register_commands = xscale_register_commands, + .target_command = xscale_target_command, + .init_target = xscale_init_target, + .quit = xscale_quit, + + .virt2phys = xscale_virt2phys, + .mmu = xscale_mmu +}; + +char* xscale_reg_list[] = +{ + "XSCALE_MAINID", /* 0 */ + "XSCALE_CACHETYPE", + "XSCALE_CTRL", + "XSCALE_AUXCTRL", + "XSCALE_TTB", + "XSCALE_DAC", + "XSCALE_FSR", + "XSCALE_FAR", + "XSCALE_PID", + "XSCALE_CPACCESS", + "XSCALE_IBCR0", /* 10 */ + "XSCALE_IBCR1", + "XSCALE_DBR0", + "XSCALE_DBR1", + "XSCALE_DBCON", + "XSCALE_TBREG", + "XSCALE_CHKPT0", + "XSCALE_CHKPT1", + "XSCALE_DCSR", + "XSCALE_TX", + "XSCALE_RX", /* 20 */ + "XSCALE_TXRXCTRL", +}; + +xscale_reg_t xscale_reg_arch_info[] = +{ + {XSCALE_MAINID, NULL}, + {XSCALE_CACHETYPE, NULL}, + {XSCALE_CTRL, NULL}, + {XSCALE_AUXCTRL, NULL}, + {XSCALE_TTB, NULL}, + {XSCALE_DAC, NULL}, + {XSCALE_FSR, NULL}, + {XSCALE_FAR, NULL}, + {XSCALE_PID, NULL}, + {XSCALE_CPACCESS, NULL}, + {XSCALE_IBCR0, NULL}, + {XSCALE_IBCR1, NULL}, + {XSCALE_DBR0, NULL}, + {XSCALE_DBR1, NULL}, + {XSCALE_DBCON, NULL}, + {XSCALE_TBREG, NULL}, + {XSCALE_CHKPT0, NULL}, + {XSCALE_CHKPT1, NULL}, + {XSCALE_DCSR, NULL}, /* DCSR accessed via JTAG or SW */ + {-1, NULL}, /* TX accessed via JTAG */ + {-1, NULL}, /* RX accessed via JTAG */ + {-1, NULL}, /* TXRXCTRL implicit access via JTAG */ +}; + +int xscale_reg_arch_type = -1; + +int xscale_get_reg(reg_t *reg); +int xscale_set_reg(reg_t *reg, u8 *buf); + +int xscale_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, xscale_common_t **xscale_p) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + ERROR("target isn't an XScale target"); + return -1; + } + + if (xscale->common_magic != XSCALE_COMMON_MAGIC) + { + ERROR("target isn't an XScale target"); + return -1; + } + + *armv4_5_p = armv4_5; + *xscale_p = xscale; + + return ERROR_OK; +} + +int xscale_jtag_set_instr(int chain_pos, u32 new_instr) +{ + jtag_device_t *device = jtag_get_device(chain_pos); + + if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) + { + scan_field_t field; + + field.device = chain_pos; + field.num_bits = device->ir_length; + field.out_value = calloc(CEIL(field.num_bits, 8), 1); + buf_set_u32(field.out_value, 0, field.num_bits, new_instr); + field.out_mask = NULL; + field.in_value = NULL; + jtag_set_check_value(&field, device->expected, device->expected_mask, NULL); + + jtag_add_ir_scan(1, &field, -1); + + free(field.out_value); + } + + return ERROR_OK; +} + +int xscale_jtag_callback(enum jtag_event event, void *priv) +{ + switch (event) + { + case JTAG_TRST_ASSERTED: + break; + case JTAG_TRST_RELEASED: + break; + case JTAG_SRST_ASSERTED: + break; + case JTAG_SRST_RELEASED: + break; + default: + WARNING("unhandled JTAG event"); + } + + return ERROR_OK; +} + +int xscale_read_dcsr(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + int retval; + + scan_field_t fields[3]; + u8 field0 = 0x0; + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x7; + u8 field2 = 0x0; + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + + jtag_add_end_state(TAP_PD); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr); + + buf_set_u32(&field0, 1, 1, xscale->hold_rst); + buf_set_u32(&field0, 2, 1, xscale->external_debug_break); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = &field0; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + + + fields[2].device = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = &field2; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + + jtag_add_dr_scan(3, fields, -1); + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while reading DCSR"); + return retval; + } + + xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = 0; + xscale->reg_cache->reg_list[XSCALE_DCSR].valid = 1; + + /* write the register with the value we just read + * on this second pass, only the first bit of field0 is guaranteed to be 0) + */ + field0_check_mask = 0x1; + fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; + fields[1].in_value = NULL; + + jtag_add_end_state(TAP_RTI); + + jtag_add_dr_scan(3, fields, -1); + + return ERROR_OK; +} + +int xscale_receive(target_t *target, u32 *buffer, int num_words) +{ + int retval = ERROR_OK; + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + enum tap_state path[3]; + scan_field_t fields[3]; + + u8 *field0 = malloc(num_words * 1); + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x6; + u32 *field1 = malloc(num_words * 4); + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + int words_done = 0; + int words_scheduled = 0; + + int i; + + path[0] = TAP_SDS; + path[1] = TAP_CD; + path[2] = TAP_SD; + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + /* fields[0].in_value = field0; */ + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + + + fields[2].device = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = NULL; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + + jtag_add_end_state(TAP_RTI); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgtx); + jtag_add_runtest(1, -1); + + /* repeat until all words have been collected */ + int attempts = 0; + while (words_done < num_words) + { + /* schedule reads */ + words_scheduled = 0; + for (i = words_done; i < num_words; i++) + { + fields[0].in_value = &field0[i]; + fields[1].in_handler = buf_to_u32_handler; + fields[1].in_handler_priv = (u8*)&field1[i]; + + jtag_add_pathmove(3, path); + jtag_add_dr_scan(3, fields, TAP_RTI); + words_scheduled++; + } + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while receiving data from debug handler"); + break; + } + + /* examine results */ + for (i = words_done; i < num_words; i++) + { + if (!(field0[0] & 1)) + { + /* move backwards if necessary */ + int j; + for (j = i; j < num_words - 1; j++) + { + field0[j] = field0[j+1]; + field1[j] = field1[j+1]; + } + words_scheduled--; + } + } + if (words_scheduled == 0) + { + if (attempts++ == 1000) + { + ERROR("Failed to receiving data from debug handler after 1000 attempts"); + retval = ERROR_JTAG_QUEUE_FAILED; + break; + } + } + + words_done += words_scheduled; + } + + for (i = 0; i < num_words; i++) + *(buffer++) = buf_get_u32((u8*)&field1[i], 0, 32); + + free(field1); + + return retval; +} + +int xscale_read_tx(target_t *target, int consume) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + enum tap_state path[3]; + enum tap_state noconsume_path[9]; + + int retval; + struct timeval timeout, now; + + scan_field_t fields[3]; + u8 field0_in = 0x0; + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x6; + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + + jtag_add_end_state(TAP_RTI); + + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgtx); + + path[0] = TAP_SDS; + path[1] = TAP_CD; + path[2] = TAP_SD; + + noconsume_path[0] = TAP_SDS; + noconsume_path[1] = TAP_CD; + noconsume_path[2] = TAP_E1D; + noconsume_path[3] = TAP_PD; + noconsume_path[4] = TAP_E2D; + noconsume_path[5] = TAP_UD; + noconsume_path[6] = TAP_SDS; + noconsume_path[7] = TAP_CD; + noconsume_path[8] = TAP_SD; + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = &field0_in; + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_TX].value; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + + + fields[2].device = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = NULL; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, 5, 0); + + do + { + /* if we want to consume the register content (i.e. clear TX_READY), + * we have to go straight from Capture-DR to Shift-DR + * otherwise, we go from Capture-DR to Exit1-DR to Pause-DR + */ + if (consume) + jtag_add_pathmove(3, path); + else + jtag_add_pathmove(sizeof(noconsume_path)/sizeof(*noconsume_path), noconsume_path); + + jtag_add_dr_scan(3, fields, TAP_RTI); + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while reading TX"); + return ERROR_TARGET_TIMEOUT; + } + + gettimeofday(&now, NULL); + if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec)&& (now.tv_usec > timeout.tv_usec))) + { + ERROR("time out reading TX register"); + return ERROR_TARGET_TIMEOUT; + } + } while ((!(field0_in & 1)) && consume); + + if (!(field0_in & 1)) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + + return ERROR_OK; +} + +int xscale_write_rx(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + int retval; + struct timeval timeout, now; + + scan_field_t fields[3]; + u8 field0_out = 0x0; + u8 field0_in = 0x0; + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x6; + u8 field2 = 0x0; + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + + jtag_add_end_state(TAP_RTI); + + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgrx); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = &field0_out; + fields[0].out_mask = NULL; + fields[0].in_value = &field0_in; + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_RX].value; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + + + fields[2].device = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = &field2; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, 5, 0); + + /* poll until rx_read is low */ + DEBUG("polling RX"); + do + { + jtag_add_dr_scan(3, fields, TAP_RTI); + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while writing RX"); + return retval; + } + + gettimeofday(&now, NULL); + if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec)&& (now.tv_usec > timeout.tv_usec))) + { + ERROR("time out writing RX register"); + return ERROR_TARGET_TIMEOUT; + } + } while (field0_in & 1); + + /* set rx_valid */ + field2 = 0x1; + jtag_add_dr_scan(3, fields, TAP_RTI); + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while writing RX"); + return retval; + } + + return ERROR_OK; +} + +/* send count elements of size byte to the debug handler */ +int xscale_send(target_t *target, u8 *buffer, int count, int size) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + int retval; + + int done_count = 0; + u8 output[4] = {0, 0, 0, 0}; + + scan_field_t fields[3]; + u8 field0_out = 0x0; + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x6; + u8 field2 = 0x1; + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + + jtag_add_end_state(TAP_RTI); + + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgrx); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = &field0_out; + fields[0].out_mask = NULL; + fields[0].in_handler = NULL; + if (!xscale->fast_memory_access) + { + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + } + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = output; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + + + fields[2].device = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = &field2; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_handler = NULL; + if (!xscale->fast_memory_access) + { + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + } + + if (size==4) + { + int endianness = target->endianness; + while (done_count++ < count) + { + if (endianness == TARGET_LITTLE_ENDIAN) + { + output[0]=buffer[0]; + output[1]=buffer[1]; + output[2]=buffer[2]; + output[3]=buffer[3]; + } else + { + output[0]=buffer[3]; + output[1]=buffer[2]; + output[2]=buffer[1]; + output[3]=buffer[0]; + } + jtag_add_dr_scan(3, fields, TAP_RTI); + buffer += size; + } + + } else + { + while (done_count++ < count) + { + /* extract sized element from target-endian buffer, and put it + * into little-endian output buffer + */ + switch (size) + { + case 2: + buf_set_u32(output, 0, 32, target_buffer_get_u16(target, buffer)); + break; + case 1: + output[0] = *buffer; + break; + default: + ERROR("BUG: size neither 4, 2 nor 1"); + exit(-1); + } + + jtag_add_dr_scan(3, fields, TAP_RTI); + buffer += size; + } + + } + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while sending data to debug handler"); + return retval; + } + + return ERROR_OK; +} + +int xscale_send_u32(target_t *target, u32 value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value); + return xscale_write_rx(target); +} + +int xscale_write_dcsr(target_t *target, int hold_rst, int ext_dbg_brk) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + int retval; + + scan_field_t fields[3]; + u8 field0 = 0x0; + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x7; + u8 field2 = 0x0; + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + + if (hold_rst != -1) + xscale->hold_rst = hold_rst; + + if (ext_dbg_brk != -1) + xscale->external_debug_break = ext_dbg_brk; + + jtag_add_end_state(TAP_RTI); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr); + + buf_set_u32(&field0, 1, 1, xscale->hold_rst); + buf_set_u32(&field0, 2, 1, xscale->external_debug_break); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = &field0; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + + + fields[2].device = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = &field2; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + + jtag_add_dr_scan(3, fields, -1); + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while writing DCSR"); + return retval; + } + + xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = 0; + xscale->reg_cache->reg_list[XSCALE_DCSR].valid = 1; + + return ERROR_OK; +} + +/* parity of the number of bits 0 if even; 1 if odd. for 32 bit words */ +unsigned int parity (unsigned int v) +{ + unsigned int ov = v; + v ^= v >> 16; + v ^= v >> 8; + v ^= v >> 4; + v &= 0xf; + DEBUG("parity of 0x%x is %i", ov, (0x6996 >> v) & 1); + return (0x6996 >> v) & 1; +} + +int xscale_load_ic(target_t *target, int mini, u32 va, u32 buffer[8]) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u8 packet[4]; + u8 cmd; + int word; + + scan_field_t fields[2]; + + DEBUG("loading miniIC at 0x%8.8x", va); + + jtag_add_end_state(TAP_RTI); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.ldic); /* LDIC */ + + /* CMD is b010 for Main IC and b011 for Mini IC */ + if (mini) + buf_set_u32(&cmd, 0, 3, 0x3); + else + buf_set_u32(&cmd, 0, 3, 0x2); + + buf_set_u32(&cmd, 3, 3, 0x0); + + /* virtual address of desired cache line */ + buf_set_u32(packet, 0, 27, va >> 5); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 6; + fields[0].out_value = &cmd; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 27; + fields[1].out_value = packet; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + jtag_add_dr_scan(2, fields, -1); + + fields[0].num_bits = 32; + fields[0].out_value = packet; + + fields[1].num_bits = 1; + fields[1].out_value = &cmd; + + for (word = 0; word < 8; word++) + { + buf_set_u32(packet, 0, 32, buffer[word]); + cmd = parity(*((u32*)packet)); + jtag_add_dr_scan(2, fields, -1); + } + + jtag_execute_queue(); + + return ERROR_OK; +} + +int xscale_invalidate_ic_line(target_t *target, u32 va) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u8 packet[4]; + u8 cmd; + + scan_field_t fields[2]; + + jtag_add_end_state(TAP_RTI); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.ldic); /* LDIC */ + + /* CMD for invalidate IC line b000, bits [6:4] b000 */ + buf_set_u32(&cmd, 0, 6, 0x0); + + /* virtual address of desired cache line */ + buf_set_u32(packet, 0, 27, va >> 5); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 6; + fields[0].out_value = &cmd; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 27; + fields[1].out_value = packet; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + jtag_add_dr_scan(2, fields, -1); + + return ERROR_OK; +} + +int xscale_update_vectors(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + int i; + + u32 low_reset_branch, high_reset_branch; + + for (i = 1; i < 8; i++) + { + /* if there's a static vector specified for this exception, override */ + if (xscale->static_high_vectors_set & (1 << i)) + { + xscale->high_vectors[i] = xscale->static_high_vectors[i]; + } + else + { + if (target_read_u32(target, 0xffff0000 + 4*i, &xscale->high_vectors[i]) != ERROR_OK) + { + xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0); + } + } + } + + for (i = 1; i < 8; i++) + { + if (xscale->static_low_vectors_set & (1 << i)) + { + xscale->low_vectors[i] = xscale->static_low_vectors[i]; + } + else + { + if (target_read_u32(target, 0x0 + 4*i, &xscale->low_vectors[i]) != ERROR_OK) + { + xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0); + } + } + } + + /* calculate branches to debug handler */ + low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2; + high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2; + + xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0); + xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0); + + /* invalidate and load exception vectors in mini i-cache */ + xscale_invalidate_ic_line(target, 0x0); + xscale_invalidate_ic_line(target, 0xffff0000); + + xscale_load_ic(target, 1, 0x0, xscale->low_vectors); + xscale_load_ic(target, 1, 0xffff0000, xscale->high_vectors); + + return ERROR_OK; +} + +int xscale_arch_state(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + char *state[] = + { + "disabled", "enabled" + }; + + char *arch_dbg_reason[] = + { + "", "\n(processor reset)", "\n(trace buffer full)" + }; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + ERROR("BUG: called for a non-ARMv4/5 target"); + exit(-1); + } + + USER("target halted in %s state due to %s, current mode: %s\n" + "cpsr: 0x%8.8x pc: 0x%8.8x\n" + "MMU: %s, D-Cache: %s, I-Cache: %s" + "%s", + armv4_5_state_strings[armv4_5->core_state], + target_debug_reason_strings[target->debug_reason], + armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)], + buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), + buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32), + state[xscale->armv4_5_mmu.mmu_enabled], + state[xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], + state[xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled], + arch_dbg_reason[xscale->arch_debug_reason]); + + return ERROR_OK; +} + +int xscale_poll(target_t *target) +{ + int retval=ERROR_OK; + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if ((target->state == TARGET_RUNNING) || (target->state == TARGET_DEBUG_RUNNING)) + { + enum target_state previous_state = target->state; + if ((retval = xscale_read_tx(target, 0)) == ERROR_OK) + { + + /* there's data to read from the tx register, we entered debug state */ + xscale->handler_running = 1; + + target->state = TARGET_HALTED; + + /* process debug entry, fetching current mode regs */ + retval = xscale_debug_entry(target); + } + else if (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + { + USER("error while polling TX register, reset CPU"); + /* here we "lie" so GDB won't get stuck and a reset can be perfomed */ + target->state = TARGET_HALTED; + } + + /* debug_entry could have overwritten target state (i.e. immediate resume) + * don't signal event handlers in that case + */ + if (target->state != TARGET_HALTED) + return ERROR_OK; + + /* if target was running, signal that we halted + * otherwise we reentered from debug execution */ + if (previous_state == TARGET_RUNNING) + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + else + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); + } + return retval; +} + +int xscale_debug_entry(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 pc; + u32 buffer[10]; + int i; + + u32 moe; + + /* clear external dbg break (will be written on next DCSR read) */ + xscale->external_debug_break = 0; + xscale_read_dcsr(target); + + /* get r0, pc, r1 to r7 and cpsr */ + xscale_receive(target, buffer, 10); + + /* move r0 from buffer to register cache */ + buf_set_u32(armv4_5->core_cache->reg_list[0].value, 0, 32, buffer[0]); + armv4_5->core_cache->reg_list[15].dirty = 1; + armv4_5->core_cache->reg_list[15].valid = 1; + DEBUG("r0: 0x%8.8x", buffer[0]); + + /* move pc from buffer to register cache */ + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, buffer[1]); + armv4_5->core_cache->reg_list[15].dirty = 1; + armv4_5->core_cache->reg_list[15].valid = 1; + DEBUG("pc: 0x%8.8x", buffer[1]); + + /* move data from buffer to register cache */ + for (i = 1; i <= 7; i++) + { + buf_set_u32(armv4_5->core_cache->reg_list[i].value, 0, 32, buffer[1 + i]); + armv4_5->core_cache->reg_list[i].dirty = 1; + armv4_5->core_cache->reg_list[i].valid = 1; + DEBUG("r%i: 0x%8.8x", i, buffer[i + 1]); + } + + buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32, buffer[9]); + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1; + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1; + DEBUG("cpsr: 0x%8.8x", buffer[9]); + + armv4_5->core_mode = buffer[9] & 0x1f; + if (armv4_5_mode_to_number(armv4_5->core_mode) == -1) + { + target->state = TARGET_UNKNOWN; + ERROR("cpsr contains invalid mode value - communication failure"); + return ERROR_TARGET_FAILURE; + } + DEBUG("target entered debug state in %s mode", armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)]); + + if (buffer[9] & 0x20) + armv4_5->core_state = ARMV4_5_STATE_THUMB; + else + armv4_5->core_state = ARMV4_5_STATE_ARM; + + /* get banked registers, r8 to r14, and spsr if not in USR/SYS mode */ + if ((armv4_5->core_mode != ARMV4_5_MODE_USR) && (armv4_5->core_mode != ARMV4_5_MODE_SYS)) + { + xscale_receive(target, buffer, 8); + buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32, buffer[7]); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).dirty = 0; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).valid = 1; + } + else + { + /* r8 to r14, but no spsr */ + xscale_receive(target, buffer, 7); + } + + /* move data from buffer to register cache */ + for (i = 8; i <= 14; i++) + { + buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).value, 0, 32, buffer[i - 8]); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).dirty = 0; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).valid = 1; + } + + /* examine debug reason */ + xscale_read_dcsr(target); + moe = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 2, 3); + + /* stored PC (for calculating fixup) */ + pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + + switch (moe) + { + case 0x0: /* Processor reset */ + target->debug_reason = DBG_REASON_DBGRQ; + xscale->arch_debug_reason = XSCALE_DBG_REASON_RESET; + pc -= 4; + break; + case 0x1: /* Instruction breakpoint hit */ + target->debug_reason = DBG_REASON_BREAKPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x2: /* Data breakpoint hit */ + target->debug_reason = DBG_REASON_WATCHPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x3: /* BKPT instruction executed */ + target->debug_reason = DBG_REASON_BREAKPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x4: /* Ext. debug event */ + target->debug_reason = DBG_REASON_DBGRQ; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x5: /* Vector trap occured */ + target->debug_reason = DBG_REASON_BREAKPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x6: /* Trace buffer full break */ + target->debug_reason = DBG_REASON_DBGRQ; + xscale->arch_debug_reason = XSCALE_DBG_REASON_TB_FULL; + pc -= 4; + break; + case 0x7: /* Reserved */ + default: + ERROR("Method of Entry is 'Reserved'"); + exit(-1); + break; + } + + /* apply PC fixup */ + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, pc); + + /* on the first debug entry, identify cache type */ + if (xscale->armv4_5_mmu.armv4_5_cache.ctype == -1) + { + u32 cache_type_reg; + + /* read cp15 cache type register */ + xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CACHETYPE]); + cache_type_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CACHETYPE].value, 0, 32); + + armv4_5_identify_cache(cache_type_reg, &xscale->armv4_5_mmu.armv4_5_cache); + } + + /* examine MMU and Cache settings */ + /* read cp15 control register */ + xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); + xscale->cp15_control_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); + xscale->armv4_5_mmu.mmu_enabled = (xscale->cp15_control_reg & 0x1U) ? 1 : 0; + xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (xscale->cp15_control_reg & 0x4U) ? 1 : 0; + xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (xscale->cp15_control_reg & 0x1000U) ? 1 : 0; + + /* tracing enabled, read collected trace data */ + if (xscale->trace.buffer_enabled) + { + xscale_read_trace(target); + xscale->trace.buffer_fill--; + + /* resume if we're still collecting trace data */ + if ((xscale->arch_debug_reason == XSCALE_DBG_REASON_TB_FULL) + && (xscale->trace.buffer_fill > 0)) + { + xscale_resume(target, 1, 0x0, 1, 0); + } + else + { + xscale->trace.buffer_enabled = 0; + } + } + + return ERROR_OK; +} + +int xscale_halt(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + DEBUG("target->state: %s", target_state_strings[target->state]); + + if (target->state == TARGET_HALTED) + { + WARNING("target was already halted"); + return ERROR_TARGET_ALREADY_HALTED; + } + else if (target->state == TARGET_UNKNOWN) + { + /* this must not happen for a xscale target */ + ERROR("target was in unknown state when halt was requested"); + return ERROR_TARGET_INVALID; + } + else if (target->state == TARGET_RESET) + { + DEBUG("target->state == TARGET_RESET"); + } + else + { + /* assert external dbg break */ + xscale->external_debug_break = 1; + xscale_read_dcsr(target); + + target->debug_reason = DBG_REASON_DBGRQ; + } + + return ERROR_OK; +} + +int xscale_enable_single_step(struct target_s *target, u32 next_pc) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale= armv4_5->arch_info; + reg_t *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0]; + + if (xscale->ibcr0_used) + { + breakpoint_t *ibcr0_bp = breakpoint_find(target, buf_get_u32(ibcr0->value, 0, 32) & 0xfffffffe); + + if (ibcr0_bp) + { + xscale_unset_breakpoint(target, ibcr0_bp); + } + else + { + ERROR("BUG: xscale->ibcr0_used is set, but no breakpoint with that address found"); + exit(-1); + } + } + + xscale_set_reg_u32(ibcr0, next_pc | 0x1); + + return ERROR_OK; +} + +int xscale_disable_single_step(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale= armv4_5->arch_info; + reg_t *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0]; + + xscale_set_reg_u32(ibcr0, 0x0); + + return ERROR_OK; +} + +int xscale_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale= armv4_5->arch_info; + breakpoint_t *breakpoint = target->breakpoints; + + u32 current_pc; + + int retval; + int i; + + DEBUG("-"); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!debug_execution) + { + target_free_all_working_areas(target); + } + + /* update vector tables */ + xscale_update_vectors(target); + + /* current = 1: continue on current pc, otherwise continue at <address> */ + if (!current) + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, address); + + current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + + /* if we're at the reset vector, we have to simulate the branch */ + if (current_pc == 0x0) + { + arm_simulate_step(target, NULL); + current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + } + + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) + { + if ((breakpoint = breakpoint_find(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)))) + { + u32 next_pc; + + /* there's a breakpoint at the current PC, we have to step over it */ + DEBUG("unset breakpoint at 0x%8.8x", breakpoint->address); + xscale_unset_breakpoint(target, breakpoint); + + /* calculate PC of next instruction */ + if ((retval = arm_simulate_step(target, &next_pc)) != ERROR_OK) + { + u32 current_opcode; + target_read_u32(target, current_pc, ¤t_opcode); + ERROR("BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8x", current_opcode); + } + + DEBUG("enable single-step"); + xscale_enable_single_step(target, next_pc); + + /* restore banked registers */ + xscale_restore_context(target); + + /* send resume request (command 0x30 or 0x31) + * clean the trace buffer if it is to be enabled (0x62) */ + if (xscale->trace.buffer_enabled) + { + xscale_send_u32(target, 0x62); + xscale_send_u32(target, 0x31); + } + else + xscale_send_u32(target, 0x30); + + /* send CPSR */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + + for (i = 7; i >= 0; i--) + { + /* send register */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + } + + /* send PC */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + + /* wait for and process debug entry */ + xscale_debug_entry(target); + + DEBUG("disable single-step"); + xscale_disable_single_step(target); + + DEBUG("set breakpoint at 0x%8.8x", breakpoint->address); + xscale_set_breakpoint(target, breakpoint); + } + } + + /* enable any pending breakpoints and watchpoints */ + xscale_enable_breakpoints(target); + xscale_enable_watchpoints(target); + + /* restore banked registers */ + xscale_restore_context(target); + + /* send resume request (command 0x30 or 0x31) + * clean the trace buffer if it is to be enabled (0x62) */ + if (xscale->trace.buffer_enabled) + { + xscale_send_u32(target, 0x62); + xscale_send_u32(target, 0x31); + } + else + xscale_send_u32(target, 0x30); + + /* send CPSR */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + + for (i = 7; i >= 0; i--) + { + /* send register */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + } + + /* send PC */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + + target->debug_reason = DBG_REASON_NOTHALTED; + + if (!debug_execution) + { + /* registers are now invalid */ + armv4_5_invalidate_core_regs(target); + target->state = TARGET_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + } + else + { + target->state = TARGET_DEBUG_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); + } + + DEBUG("target resumed"); + + xscale->handler_running = 1; + + return ERROR_OK; +} + +int xscale_step(struct target_s *target, int current, u32 address, int handle_breakpoints) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + breakpoint_t *breakpoint = target->breakpoints; + + u32 current_pc, next_pc; + int i; + int retval; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* current = 1: continue on current pc, otherwise continue at <address> */ + if (!current) + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, address); + + current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + + /* if we're at the reset vector, we have to simulate the step */ + if (current_pc == 0x0) + { + arm_simulate_step(target, NULL); + current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + + target->debug_reason = DBG_REASON_SINGLESTEP; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + + return ERROR_OK; + } + + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) + if ((breakpoint = breakpoint_find(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)))) + { + xscale_unset_breakpoint(target, breakpoint); + } + + target->debug_reason = DBG_REASON_SINGLESTEP; + + /* calculate PC of next instruction */ + if ((retval = arm_simulate_step(target, &next_pc)) != ERROR_OK) + { + u32 current_opcode; + target_read_u32(target, current_pc, ¤t_opcode); + ERROR("BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8x", current_opcode); + } + + DEBUG("enable single-step"); + xscale_enable_single_step(target, next_pc); + + /* restore banked registers */ + xscale_restore_context(target); + + /* send resume request (command 0x30 or 0x31) + * clean the trace buffer if it is to be enabled (0x62) */ + if (xscale->trace.buffer_enabled) + { + xscale_send_u32(target, 0x62); + xscale_send_u32(target, 0x31); + } + else + xscale_send_u32(target, 0x30); + + /* send CPSR */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + + for (i = 7; i >= 0; i--) + { + /* send register */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + } + + /* send PC */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + + /* registers are now invalid */ + armv4_5_invalidate_core_regs(target); + + /* wait for and process debug entry */ + xscale_debug_entry(target); + + DEBUG("disable single-step"); + xscale_disable_single_step(target); + + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + + if (breakpoint) + { + xscale_set_breakpoint(target, breakpoint); + } + + DEBUG("target stepped"); + + return ERROR_OK; + +} + +int xscale_assert_reset(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + DEBUG("target->state: %s", target_state_strings[target->state]); + + /* select DCSR instruction (set endstate to R-T-I to ensure we don't + * end up in T-L-R, which would reset JTAG + */ + jtag_add_end_state(TAP_RTI); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr); + + /* set Hold reset, Halt mode and Trap Reset */ + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); + xscale_write_dcsr(target, 1, 0); + + /* select BYPASS, because having DCSR selected caused problems on the PXA27x */ + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, 0x7f); + jtag_execute_queue(); + + /* assert reset */ + jtag_add_reset(0, 1); + + /* sleep 1ms, to be sure we fulfill any requirements */ + jtag_add_sleep(1000); + jtag_execute_queue(); + + target->state = TARGET_RESET; + + return ERROR_OK; +} + +int xscale_deassert_reset(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + fileio_t debug_handler; + u32 address; + u32 binary_size; + + u32 buf_cnt; + int i; + int retval; + + breakpoint_t *breakpoint = target->breakpoints; + + DEBUG("-"); + + xscale->ibcr_available = 2; + xscale->ibcr0_used = 0; + xscale->ibcr1_used = 0; + + xscale->dbr_available = 2; + xscale->dbr0_used = 0; + xscale->dbr1_used = 0; + + /* mark all hardware breakpoints as unset */ + while (breakpoint) + { + if (breakpoint->type == BKPT_HARD) + { + breakpoint->set = 0; + } + breakpoint = breakpoint->next; + } + + if (!xscale->handler_installed) + { + /* release SRST */ + jtag_add_reset(0, 0); + + /* wait 300ms; 150 and 100ms were not enough */ + jtag_add_sleep(300*1000); + + jtag_add_runtest(2030, TAP_RTI); + jtag_execute_queue(); + + /* set Hold reset, Halt mode and Trap Reset */ + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); + xscale_write_dcsr(target, 1, 0); + + /* Load debug handler */ + if (fileio_open(&debug_handler, PKGLIBDIR "/xscale/debug_handler.bin", FILEIO_READ, FILEIO_BINARY) != ERROR_OK) + { + ERROR("file open error: %s", debug_handler.error_str); + return ERROR_OK; + } + + if ((binary_size = debug_handler.size) % 4) + { + ERROR("debug_handler.bin: size not a multiple of 4"); + exit(-1); + } + + if (binary_size > 0x800) + { + ERROR("debug_handler.bin: larger than 2kb"); + exit(-1); + } + + binary_size = CEIL(binary_size, 32) * 32; + + address = xscale->handler_address; + while (binary_size > 0) + { + u32 cache_line[8]; + u8 buffer[32]; + + if ((retval = fileio_read(&debug_handler, 32, buffer, &buf_cnt)) != ERROR_OK) + { + ERROR("reading debug handler failed: %s", debug_handler.error_str); + } + + for (i = 0; i < buf_cnt; i += 4) + { + /* convert LE buffer to host-endian u32 */ + cache_line[i / 4] = le_to_h_u32(&buffer[i]); + } + + for (; buf_cnt < 32; buf_cnt += 4) + { + cache_line[buf_cnt / 4] = 0xe1a08008; + } + + /* only load addresses other than the reset vectors */ + if ((address % 0x400) != 0x0) + { + xscale_load_ic(target, 1, address, cache_line); + } + + address += buf_cnt; + binary_size -= buf_cnt; + }; + + xscale_load_ic(target, 1, 0x0, xscale->low_vectors); + xscale_load_ic(target, 1, 0xffff0000, xscale->high_vectors); + + jtag_add_runtest(30, TAP_RTI); + + jtag_add_sleep(100000); + + /* set Hold reset, Halt mode and Trap Reset */ + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); + xscale_write_dcsr(target, 1, 0); + + /* clear Hold reset to let the target run (should enter debug handler) */ + xscale_write_dcsr(target, 0, 1); + target->state = TARGET_RUNNING; + + if ((target->reset_mode != RESET_HALT) && (target->reset_mode != RESET_INIT)) + { + jtag_add_sleep(10000); + + /* we should have entered debug now */ + xscale_debug_entry(target); + target->state = TARGET_HALTED; + + /* resume the target */ + xscale_resume(target, 1, 0x0, 1, 0); + } + + fileio_close(&debug_handler); + } + else + { + jtag_add_reset(0, 0); + } + + + return ERROR_OK; +} + +int xscale_soft_reset_halt(struct target_s *target) +{ + + return ERROR_OK; +} + +int xscale_prepare_reset_halt(struct target_s *target) +{ + /* nothing to be done for reset_halt on XScale targets + * we always halt after a reset to upload the debug handler + */ + return ERROR_OK; +} + +int xscale_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode) +{ + + return ERROR_OK; +} + +int xscale_write_core_reg(struct target_s *target, int num, enum armv4_5_mode mode, u32 value) +{ + + return ERROR_OK; +} + +int xscale_full_context(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + + u32 *buffer; + + int i, j; + + DEBUG("-"); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + buffer = malloc(4 * 8); + + /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS) + * we can't enter User mode on an XScale (unpredictable), + * but User shares registers with SYS + */ + for(i = 1; i < 7; i++) + { + int valid = 1; + + /* check if there are invalid registers in the current mode + */ + for (j = 0; j <= 16; j++) + { + if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid == 0) + valid = 0; + } + + if (!valid) + { + u32 tmp_cpsr; + + /* request banked registers */ + xscale_send_u32(target, 0x0); + + tmp_cpsr = 0x0; + tmp_cpsr |= armv4_5_number_to_mode(i); + tmp_cpsr |= 0xc0; /* I/F bits */ + + /* send CPSR for desired mode */ + xscale_send_u32(target, tmp_cpsr); + + /* get banked registers, r8 to r14, and spsr if not in USR/SYS mode */ + if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS)) + { + xscale_receive(target, buffer, 8); + buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32, buffer[7]); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).valid = 1; + } + else + { + xscale_receive(target, buffer, 7); + } + + /* move data from buffer to register cache */ + for (j = 8; j <= 14; j++) + { + buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).value, 0, 32, buffer[j - 8]); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty = 0; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid = 1; + } + } + } + + free(buffer); + + return ERROR_OK; +} + +int xscale_restore_context(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + + int i, j; + + DEBUG("-"); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS) + * we can't enter User mode on an XScale (unpredictable), + * but User shares registers with SYS + */ + for(i = 1; i < 7; i++) + { + int dirty = 0; + + /* check if there are invalid registers in the current mode + */ + for (j = 8; j <= 14; j++) + { + if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty == 1) + dirty = 1; + } + + /* if not USR/SYS, check if the SPSR needs to be written */ + if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS)) + { + if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty == 1) + dirty = 1; + } + + if (dirty) + { + u32 tmp_cpsr; + + /* send banked registers */ + xscale_send_u32(target, 0x1); + + tmp_cpsr = 0x0; + tmp_cpsr |= armv4_5_number_to_mode(i); + tmp_cpsr |= 0xc0; /* I/F bits */ + + /* send CPSR for desired mode */ + xscale_send_u32(target, tmp_cpsr); + + /* send banked registers, r8 to r14, and spsr if not in USR/SYS mode */ + for (j = 8; j <= 14; j++) + { + xscale_send_u32(target, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, j).value, 0, 32)); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty = 0; + } + + if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS)) + { + xscale_send_u32(target, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32)); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0; + } + } + } + + return ERROR_OK; +} + +int xscale_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 *buf32; + int i; + + DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* sanitize arguments */ + if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) + return ERROR_INVALID_ARGUMENTS; + + if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) + return ERROR_TARGET_UNALIGNED_ACCESS; + + /* send memory read request (command 0x1n, n: access size) */ + xscale_send_u32(target, 0x10 | size); + + /* send base address for read request */ + xscale_send_u32(target, address); + + /* send number of requested data words */ + xscale_send_u32(target, count); + + /* receive data from target (count times 32-bit words in host endianness) */ + buf32 = malloc(4 * count); + xscale_receive(target, buf32, count); + + /* extract data from host-endian buffer into byte stream */ + for (i = 0; i < count; i++) + { + switch (size) + { + case 4: + target_buffer_set_u32(target, buffer, buf32[i]); + buffer += 4; + break; + case 2: + target_buffer_set_u16(target, buffer, buf32[i] & 0xffff); + buffer += 2; + break; + case 1: + *buffer++ = buf32[i] & 0xff; + break; + default: + ERROR("should never get here"); + exit(-1); + } + } + + free(buf32); + + /* examine DCSR, to see if Sticky Abort (SA) got set */ + xscale_read_dcsr(target); + if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1) + { + /* clear SA bit */ + xscale_send_u32(target, 0x60); + + return ERROR_TARGET_DATA_ABORT; + } + + return ERROR_OK; +} + +int xscale_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* sanitize arguments */ + if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) + return ERROR_INVALID_ARGUMENTS; + + if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) + return ERROR_TARGET_UNALIGNED_ACCESS; + + /* send memory write request (command 0x2n, n: access size) */ + xscale_send_u32(target, 0x20 | size); + + /* send base address for read request */ + xscale_send_u32(target, address); + + /* send number of requested data words to be written*/ + xscale_send_u32(target, count); + + /* extract data from host-endian buffer into byte stream */ +#if 0 + for (i = 0; i < count; i++) + { + switch (size) + { + case 4: + value = target_buffer_get_u32(target, buffer); + xscale_send_u32(target, value); + buffer += 4; + break; + case 2: + value = target_buffer_get_u16(target, buffer); + xscale_send_u32(target, value); + buffer += 2; + break; + case 1: + value = *buffer; + xscale_send_u32(target, value); + buffer += 1; + break; + default: + ERROR("should never get here"); + exit(-1); + } + } +#endif + xscale_send(target, buffer, count, size); + + /* examine DCSR, to see if Sticky Abort (SA) got set */ + xscale_read_dcsr(target); + if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1) + { + /* clear SA bit */ + xscale_send_u32(target, 0x60); + + return ERROR_TARGET_DATA_ABORT; + } + + return ERROR_OK; +} + +int xscale_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer) +{ + return xscale_write_memory(target, address, 4, count, buffer); +} + +int xscale_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum) +{ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; +} + +u32 xscale_get_ttb(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 ttb; + + xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_TTB]); + ttb = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_TTB].value, 0, 32); + + return ttb; +} + +void xscale_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 cp15_control; + + /* read cp15 control register */ + xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); + cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); + + if (mmu) + cp15_control &= ~0x1U; + + if (d_u_cache) + { + /* clean DCache */ + xscale_send_u32(target, 0x50); + xscale_send_u32(target, xscale->cache_clean_address); + + /* invalidate DCache */ + xscale_send_u32(target, 0x51); + + cp15_control &= ~0x4U; + } + + if (i_cache) + { + /* invalidate ICache */ + xscale_send_u32(target, 0x52); + cp15_control &= ~0x1000U; + } + + /* write new cp15 control register */ + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); + + /* execute cpwait to ensure outstanding operations complete */ + xscale_send_u32(target, 0x53); +} + +void xscale_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 cp15_control; + + /* read cp15 control register */ + xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); + cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); + + if (mmu) + cp15_control |= 0x1U; + + if (d_u_cache) + cp15_control |= 0x4U; + + if (i_cache) + cp15_control |= 0x1000U; + + /* write new cp15 control register */ + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); + + /* execute cpwait to ensure outstanding operations complete */ + xscale_send_u32(target, 0x53); +} + +int xscale_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (xscale->force_hw_bkpts) + breakpoint->type = BKPT_HARD; + + if (breakpoint->set) + { + WARNING("breakpoint already set"); + return ERROR_OK; + } + + if (breakpoint->type == BKPT_HARD) + { + u32 value = breakpoint->address | 1; + if (!xscale->ibcr0_used) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], value); + xscale->ibcr0_used = 1; + breakpoint->set = 1; /* breakpoint set on first breakpoint register */ + } + else if (!xscale->ibcr1_used) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], value); + xscale->ibcr1_used = 1; + breakpoint->set = 2; /* breakpoint set on second breakpoint register */ + } + else + { + ERROR("BUG: no hardware comparator available"); + return ERROR_OK; + } + } + else if (breakpoint->type == BKPT_SOFT) + { + if (breakpoint->length == 4) + { + /* keep the original instruction in target endianness */ + target->type->read_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); + /* write the original instruction in target endianness (arm7_9->arm_bkpt is host endian) */ + target_write_u32(target, breakpoint->address, xscale->arm_bkpt); + } + else + { + /* keep the original instruction in target endianness */ + target->type->read_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); + /* write the original instruction in target endianness (arm7_9->arm_bkpt is host endian) */ + target_write_u32(target, breakpoint->address, xscale->thumb_bkpt); + } + breakpoint->set = 1; + } + + return ERROR_OK; + +} + +int xscale_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (xscale->force_hw_bkpts) + { + DEBUG("forcing use of hardware breakpoint at address 0x%8.8x", breakpoint->address); + breakpoint->type = BKPT_HARD; + } + + if ((breakpoint->type == BKPT_HARD) && (xscale->ibcr_available < 1)) + { + INFO("no breakpoint unit available for hardware breakpoint"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + else + { + xscale->ibcr_available--; + } + + if ((breakpoint->length != 2) && (breakpoint->length != 4)) + { + INFO("only breakpoints of two (Thumb) or four (ARM) bytes length supported"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + return ERROR_OK; +} + +int xscale_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!breakpoint->set) + { + WARNING("breakpoint not set"); + return ERROR_OK; + } + + if (breakpoint->type == BKPT_HARD) + { + if (breakpoint->set == 1) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], 0x0); + xscale->ibcr0_used = 0; + } + else if (breakpoint->set == 2) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], 0x0); + xscale->ibcr1_used = 0; + } + breakpoint->set = 0; + } + else + { + /* restore original instruction (kept in target endianness) */ + if (breakpoint->length == 4) + { + target->type->write_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); + } + else + { + target->type->write_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); + } + breakpoint->set = 0; + } + + return ERROR_OK; +} + +int xscale_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (breakpoint->set) + { + xscale_unset_breakpoint(target, breakpoint); + } + + if (breakpoint->type == BKPT_HARD) + xscale->ibcr_available++; + + return ERROR_OK; +} + +int xscale_set_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u8 enable = 0; + reg_t *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON]; + u32 dbcon_value = buf_get_u32(dbcon->value, 0, 32); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + xscale_get_reg(dbcon); + + switch (watchpoint->rw) + { + case WPT_READ: + enable = 0x3; + break; + case WPT_ACCESS: + enable = 0x2; + break; + case WPT_WRITE: + enable = 0x1; + break; + default: + ERROR("BUG: watchpoint->rw neither read, write nor access"); + } + + if (!xscale->dbr0_used) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR0], watchpoint->address); + dbcon_value |= enable; + xscale_set_reg_u32(dbcon, dbcon_value); + watchpoint->set = 1; + xscale->dbr0_used = 1; + } + else if (!xscale->dbr1_used) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR1], watchpoint->address); + dbcon_value |= enable << 2; + xscale_set_reg_u32(dbcon, dbcon_value); + watchpoint->set = 2; + xscale->dbr1_used = 1; + } + else + { + ERROR("BUG: no hardware comparator available"); + return ERROR_OK; + } + + return ERROR_OK; +} + +int xscale_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (xscale->dbr_available < 1) + { + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + if ((watchpoint->length != 1) && (watchpoint->length != 2) && (watchpoint->length != 4)) + { + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + xscale->dbr_available--; + + return ERROR_OK; +} + +int xscale_unset_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + reg_t *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON]; + u32 dbcon_value = buf_get_u32(dbcon->value, 0, 32); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!watchpoint->set) + { + WARNING("breakpoint not set"); + return ERROR_OK; + } + + if (watchpoint->set == 1) + { + dbcon_value &= ~0x3; + xscale_set_reg_u32(dbcon, dbcon_value); + xscale->dbr0_used = 0; + } + else if (watchpoint->set == 2) + { + dbcon_value &= ~0xc; + xscale_set_reg_u32(dbcon, dbcon_value); + xscale->dbr1_used = 0; + } + watchpoint->set = 0; + + return ERROR_OK; +} + +int xscale_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (watchpoint->set) + { + xscale_unset_watchpoint(target, watchpoint); + } + + xscale->dbr_available++; + + return ERROR_OK; +} + +void xscale_enable_watchpoints(struct target_s *target) +{ + watchpoint_t *watchpoint = target->watchpoints; + + while (watchpoint) + { + if (watchpoint->set == 0) + xscale_set_watchpoint(target, watchpoint); + watchpoint = watchpoint->next; + } +} + +void xscale_enable_breakpoints(struct target_s *target) +{ + breakpoint_t *breakpoint = target->breakpoints; + + /* set any pending breakpoints */ + while (breakpoint) + { + if (breakpoint->set == 0) + xscale_set_breakpoint(target, breakpoint); + breakpoint = breakpoint->next; + } +} + +int xscale_get_reg(reg_t *reg) +{ + xscale_reg_t *arch_info = reg->arch_info; + target_t *target = arch_info->target; + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + /* DCSR, TX and RX are accessible via JTAG */ + if (strcmp(reg->name, "XSCALE_DCSR") == 0) + { + return xscale_read_dcsr(arch_info->target); + } + else if (strcmp(reg->name, "XSCALE_TX") == 0) + { + /* 1 = consume register content */ + return xscale_read_tx(arch_info->target, 1); + } + else if (strcmp(reg->name, "XSCALE_RX") == 0) + { + /* can't read from RX register (host -> debug handler) */ + return ERROR_OK; + } + else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0) + { + /* can't (explicitly) read from TXRXCTRL register */ + return ERROR_OK; + } + else /* Other DBG registers have to be transfered by the debug handler */ + { + /* send CP read request (command 0x40) */ + xscale_send_u32(target, 0x40); + + /* send CP register number */ + xscale_send_u32(target, arch_info->dbg_handler_number); + + /* read register value */ + xscale_read_tx(target, 1); + buf_cpy(xscale->reg_cache->reg_list[XSCALE_TX].value, reg->value, 32); + + reg->dirty = 0; + reg->valid = 1; + } + + return ERROR_OK; +} + +int xscale_set_reg(reg_t *reg, u8* buf) +{ + xscale_reg_t *arch_info = reg->arch_info; + target_t *target = arch_info->target; + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 value = buf_get_u32(buf, 0, 32); + + /* DCSR, TX and RX are accessible via JTAG */ + if (strcmp(reg->name, "XSCALE_DCSR") == 0) + { + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32, value); + return xscale_write_dcsr(arch_info->target, -1, -1); + } + else if (strcmp(reg->name, "XSCALE_RX") == 0) + { + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value); + return xscale_write_rx(arch_info->target); + } + else if (strcmp(reg->name, "XSCALE_TX") == 0) + { + /* can't write to TX register (debug-handler -> host) */ + return ERROR_OK; + } + else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0) + { + /* can't (explicitly) write to TXRXCTRL register */ + return ERROR_OK; + } + else /* Other DBG registers have to be transfered by the debug handler */ + { + /* send CP write request (command 0x41) */ + xscale_send_u32(target, 0x41); + + /* send CP register number */ + xscale_send_u32(target, arch_info->dbg_handler_number); + + /* send CP register value */ + xscale_send_u32(target, value); + buf_set_u32(reg->value, 0, 32, value); + } + + return ERROR_OK; +} + +/* convenience wrapper to access XScale specific registers */ +int xscale_set_reg_u32(reg_t *reg, u32 value) +{ + u8 buf[4]; + + buf_set_u32(buf, 0, 32, value); + + return xscale_set_reg(reg, buf); +} + +int xscale_write_dcsr_sw(target_t *target, u32 value) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + reg_t *dcsr = &xscale->reg_cache->reg_list[XSCALE_DCSR]; + xscale_reg_t *dcsr_arch_info = dcsr->arch_info; + + /* send CP write request (command 0x41) */ + xscale_send_u32(target, 0x41); + + /* send CP register number */ + xscale_send_u32(target, dcsr_arch_info->dbg_handler_number); + + /* send CP register value */ + xscale_send_u32(target, value); + buf_set_u32(dcsr->value, 0, 32, value); + + return ERROR_OK; +} + +int xscale_read_trace(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + xscale_trace_data_t **trace_data_p; + + /* 258 words from debug handler + * 256 trace buffer entries + * 2 checkpoint addresses + */ + u32 trace_buffer[258]; + int is_address[256]; + int i, j; + + if (target->state != TARGET_HALTED) + { + WARNING("target must be stopped to read trace data"); + return ERROR_TARGET_NOT_HALTED; + } + + /* send read trace buffer command (command 0x61) */ + xscale_send_u32(target, 0x61); + + /* receive trace buffer content */ + xscale_receive(target, trace_buffer, 258); + + /* parse buffer backwards to identify address entries */ + for (i = 255; i >= 0; i--) + { + is_address[i] = 0; + if (((trace_buffer[i] & 0xf0) == 0x90) || + ((trace_buffer[i] & 0xf0) == 0xd0)) + { + if (i >= 3) + is_address[--i] = 1; + if (i >= 2) + is_address[--i] = 1; + if (i >= 1) + is_address[--i] = 1; + if (i >= 0) + is_address[--i] = 1; + } + } + + + /* search first non-zero entry */ + for (j = 0; (j < 256) && (trace_buffer[j] == 0) && (!is_address[j]); j++) + ; + + if (j == 256) + { + DEBUG("no trace data collected"); + return ERROR_XSCALE_NO_TRACE_DATA; + } + + for (trace_data_p = &xscale->trace.data; *trace_data_p; trace_data_p = &(*trace_data_p)->next) + ; + + *trace_data_p = malloc(sizeof(xscale_trace_data_t)); + (*trace_data_p)->next = NULL; + (*trace_data_p)->chkpt0 = trace_buffer[256]; + (*trace_data_p)->chkpt1 = trace_buffer[257]; + (*trace_data_p)->last_instruction = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + (*trace_data_p)->entries = malloc(sizeof(xscale_trace_entry_t) * (256 - j)); + (*trace_data_p)->depth = 256 - j; + + for (i = j; i < 256; i++) + { + (*trace_data_p)->entries[i - j].data = trace_buffer[i]; + if (is_address[i]) + (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_ADDRESS; + else + (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_MESSAGE; + } + + return ERROR_OK; +} + +int xscale_read_instruction(target_t *target, arm_instruction_t *instruction) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + int i; + int section = -1; + u32 size_read; + u32 opcode; + int retval; + + if (!xscale->trace.image) + return ERROR_TRACE_IMAGE_UNAVAILABLE; + + /* search for the section the current instruction belongs to */ + for (i = 0; i < xscale->trace.image->num_sections; i++) + { + if ((xscale->trace.image->sections[i].base_address <= xscale->trace.current_pc) && + (xscale->trace.image->sections[i].base_address + xscale->trace.image->sections[i].size > xscale->trace.current_pc)) + { + section = i; + break; + } + } + + if (section == -1) + { + /* current instruction couldn't be found in the image */ + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + + if (xscale->trace.core_state == ARMV4_5_STATE_ARM) + { + u8 buf[4]; + if ((retval = image_read_section(xscale->trace.image, section, + xscale->trace.current_pc - xscale->trace.image->sections[section].base_address, + 4, buf, &size_read)) != ERROR_OK) + { + ERROR("error while reading instruction: %i", retval); + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + opcode = target_buffer_get_u32(target, buf); + arm_evaluate_opcode(opcode, xscale->trace.current_pc, instruction); + } + else if (xscale->trace.core_state == ARMV4_5_STATE_THUMB) + { + u8 buf[2]; + if ((retval = image_read_section(xscale->trace.image, section, + xscale->trace.current_pc - xscale->trace.image->sections[section].base_address, + 2, buf, &size_read)) != ERROR_OK) + { + ERROR("error while reading instruction: %i", retval); + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + opcode = target_buffer_get_u16(target, buf); + thumb_evaluate_opcode(opcode, xscale->trace.current_pc, instruction); + } + else + { + ERROR("BUG: unknown core state encountered"); + exit(-1); + } + + return ERROR_OK; +} + +int xscale_branch_address(xscale_trace_data_t *trace_data, int i, u32 *target) +{ + /* if there are less than four entries prior to the indirect branch message + * we can't extract the address */ + if (i < 4) + { + return -1; + } + + *target = (trace_data->entries[i-1].data) | (trace_data->entries[i-2].data << 8) | + (trace_data->entries[i-3].data << 16) | (trace_data->entries[i-4].data << 24); + + return 0; +} + +int xscale_analyze_trace(target_t *target, command_context_t *cmd_ctx) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + int next_pc_ok = 0; + u32 next_pc = 0x0; + xscale_trace_data_t *trace_data = xscale->trace.data; + int retval; + + while (trace_data) + { + int i, chkpt; + int rollover; + int branch; + int exception; + xscale->trace.core_state = ARMV4_5_STATE_ARM; + + chkpt = 0; + rollover = 0; + + for (i = 0; i < trace_data->depth; i++) + { + next_pc_ok = 0; + branch = 0; + exception = 0; + + if (trace_data->entries[i].type == XSCALE_TRACE_ADDRESS) + continue; + + switch ((trace_data->entries[i].data & 0xf0) >> 4) + { + case 0: /* Exceptions */ + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + exception = (trace_data->entries[i].data & 0x70) >> 4; + next_pc_ok = 1; + next_pc = (trace_data->entries[i].data & 0xf0) >> 2; + command_print(cmd_ctx, "--- exception %i ---", (trace_data->entries[i].data & 0xf0) >> 4); + break; + case 8: /* Direct Branch */ + branch = 1; + break; + case 9: /* Indirect Branch */ + branch = 1; + if (xscale_branch_address(trace_data, i, &next_pc) == 0) + { + next_pc_ok = 1; + } + break; + case 13: /* Checkpointed Indirect Branch */ + if (xscale_branch_address(trace_data, i, &next_pc) == 0) + { + next_pc_ok = 1; + if (((chkpt == 0) && (next_pc != trace_data->chkpt0)) + || ((chkpt == 1) && (next_pc != trace_data->chkpt1))) + WARNING("checkpointed indirect branch target address doesn't match checkpoint"); + } + /* explicit fall-through */ + case 12: /* Checkpointed Direct Branch */ + branch = 1; + if (chkpt == 0) + { + next_pc_ok = 1; + next_pc = trace_data->chkpt0; + chkpt++; + } + else if (chkpt == 1) + { + next_pc_ok = 1; + next_pc = trace_data->chkpt0; + chkpt++; + } + else + { + WARNING("more than two checkpointed branches encountered"); + } + break; + case 15: /* Roll-over */ + rollover++; + continue; + default: /* Reserved */ + command_print(cmd_ctx, "--- reserved trace message ---"); + ERROR("BUG: trace message %i is reserved", (trace_data->entries[i].data & 0xf0) >> 4); + return ERROR_OK; + } + + if (xscale->trace.pc_ok) + { + int executed = (trace_data->entries[i].data & 0xf) + rollover * 16; + arm_instruction_t instruction; + + if ((exception == 6) || (exception == 7)) + { + /* IRQ or FIQ exception, no instruction executed */ + executed -= 1; + } + + while (executed-- >= 0) + { + if ((retval = xscale_read_instruction(target, &instruction)) != ERROR_OK) + { + /* can't continue tracing with no image available */ + if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE) + { + return retval; + } + else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) + { + /* TODO: handle incomplete images */ + } + } + + /* a precise abort on a load to the PC is included in the incremental + * word count, other instructions causing data aborts are not included + */ + if ((executed == 0) && (exception == 4) + && ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDM))) + { + if ((instruction.type == ARM_LDM) + && ((instruction.info.load_store_multiple.register_list & 0x8000) == 0)) + { + executed--; + } + else if (((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDRSH)) + && (instruction.info.load_store.Rd != 15)) + { + executed--; + } + } + + /* only the last instruction executed + * (the one that caused the control flow change) + * could be a taken branch + */ + if (((executed == -1) && (branch == 1)) && + (((instruction.type == ARM_B) || + (instruction.type == ARM_BL) || + (instruction.type == ARM_BLX)) && + (instruction.info.b_bl_bx_blx.target_address != -1))) + { + xscale->trace.current_pc = instruction.info.b_bl_bx_blx.target_address; + } + else + { + xscale->trace.current_pc += (xscale->trace.core_state == ARMV4_5_STATE_ARM) ? 4 : 2; + } + command_print(cmd_ctx, "%s", instruction.text); + } + + rollover = 0; + } + + if (next_pc_ok) + { + xscale->trace.current_pc = next_pc; + xscale->trace.pc_ok = 1; + } + } + + for (; xscale->trace.current_pc < trace_data->last_instruction; xscale->trace.current_pc += (xscale->trace.core_state == ARMV4_5_STATE_ARM) ? 4 : 2) + { + arm_instruction_t instruction; + if ((retval = xscale_read_instruction(target, &instruction)) != ERROR_OK) + { + /* can't continue tracing with no image available */ + if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE) + { + return retval; + } + else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) + { + /* TODO: handle incomplete images */ + } + } + command_print(cmd_ctx, "%s", instruction.text); + } + + trace_data = trace_data->next; + } + + return ERROR_OK; +} + +void xscale_build_reg_cache(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache); + xscale_reg_t *arch_info = malloc(sizeof(xscale_reg_arch_info)); + int i; + int num_regs = sizeof(xscale_reg_arch_info) / sizeof(xscale_reg_t); + + (*cache_p) = armv4_5_build_reg_cache(target, armv4_5); + armv4_5->core_cache = (*cache_p); + + /* register a register arch-type for XScale dbg registers only once */ + if (xscale_reg_arch_type == -1) + xscale_reg_arch_type = register_reg_arch_type(xscale_get_reg, xscale_set_reg); + + (*cache_p)->next = malloc(sizeof(reg_cache_t)); + cache_p = &(*cache_p)->next; + + /* fill in values for the xscale reg cache */ + (*cache_p)->name = "XScale registers"; + (*cache_p)->next = NULL; + (*cache_p)->reg_list = malloc(num_regs * sizeof(reg_t)); + (*cache_p)->num_regs = num_regs; + + for (i = 0; i < num_regs; i++) + { + (*cache_p)->reg_list[i].name = xscale_reg_list[i]; + (*cache_p)->reg_list[i].value = calloc(4, 1); + (*cache_p)->reg_list[i].dirty = 0; + (*cache_p)->reg_list[i].valid = 0; + (*cache_p)->reg_list[i].size = 32; + (*cache_p)->reg_list[i].bitfield_desc = NULL; + (*cache_p)->reg_list[i].num_bitfields = 0; + (*cache_p)->reg_list[i].arch_info = &arch_info[i]; + (*cache_p)->reg_list[i].arch_type = xscale_reg_arch_type; + arch_info[i] = xscale_reg_arch_info[i]; + arch_info[i].target = target; + } + + xscale->reg_cache = (*cache_p); +} + +int xscale_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + if (startup_mode != DAEMON_RESET) + { + ERROR("XScale target requires a reset"); + ERROR("Reset target to enable debug"); + } + + /* assert TRST once during startup */ + jtag_add_reset(1, 0); + jtag_add_sleep(5000); + jtag_add_reset(0, 0); + jtag_execute_queue(); + + return ERROR_OK; +} + +int xscale_quit() +{ + + return ERROR_OK; +} + +int xscale_init_arch_info(target_t *target, xscale_common_t *xscale, int chain_pos, char *variant) +{ + armv4_5_common_t *armv4_5; + u32 high_reset_branch, low_reset_branch; + int i; + + armv4_5 = &xscale->armv4_5_common; + + /* store architecture specfic data (none so far) */ + xscale->arch_info = NULL; + xscale->common_magic = XSCALE_COMMON_MAGIC; + + /* remember the variant (PXA25x, PXA27x, IXP42x, ...) */ + xscale->variant = strdup(variant); + + /* prepare JTAG information for the new target */ + xscale->jtag_info.chain_pos = chain_pos; + jtag_register_event_callback(xscale_jtag_callback, target); + + xscale->jtag_info.dbgrx = 0x02; + xscale->jtag_info.dbgtx = 0x10; + xscale->jtag_info.dcsr = 0x09; + xscale->jtag_info.ldic = 0x07; + + if ((strcmp(xscale->variant, "pxa250") == 0) || + (strcmp(xscale->variant, "pxa255") == 0) || + (strcmp(xscale->variant, "pxa26x") == 0)) + { + xscale->jtag_info.ir_length = 5; + } + else if ((strcmp(xscale->variant, "pxa27x") == 0) || + (strcmp(xscale->variant, "ixp42x") == 0) || + (strcmp(xscale->variant, "ixp45x") == 0) || + (strcmp(xscale->variant, "ixp46x") == 0)) + { + xscale->jtag_info.ir_length = 7; + } + + /* the debug handler isn't installed (and thus not running) at this time */ + xscale->handler_installed = 0; + xscale->handler_running = 0; + xscale->handler_address = 0xfe000800; + + /* clear the vectors we keep locally for reference */ + memset(xscale->low_vectors, 0, sizeof(xscale->low_vectors)); + memset(xscale->high_vectors, 0, sizeof(xscale->high_vectors)); + + /* no user-specified vectors have been configured yet */ + xscale->static_low_vectors_set = 0x0; + xscale->static_high_vectors_set = 0x0; + + /* calculate branches to debug handler */ + low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2; + high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2; + + xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0); + xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0); + + for (i = 1; i <= 7; i++) + { + xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0); + xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0); + } + + /* 64kB aligned region used for DCache cleaning */ + xscale->cache_clean_address = 0xfffe0000; + + xscale->hold_rst = 0; + xscale->external_debug_break = 0; + + xscale->force_hw_bkpts = 1; + + xscale->ibcr_available = 2; + xscale->ibcr0_used = 0; + xscale->ibcr1_used = 0; + + xscale->dbr_available = 2; + xscale->dbr0_used = 0; + xscale->dbr1_used = 0; + + xscale->arm_bkpt = ARMV5_BKPT(0x0); + xscale->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; + + xscale->vector_catch = 0x1; + + xscale->trace.capture_status = TRACE_IDLE; + xscale->trace.data = NULL; + xscale->trace.image = NULL; + xscale->trace.buffer_enabled = 0; + xscale->trace.buffer_fill = 0; + + /* prepare ARMv4/5 specific information */ + armv4_5->arch_info = xscale; + armv4_5->read_core_reg = xscale_read_core_reg; + armv4_5->write_core_reg = xscale_write_core_reg; + armv4_5->full_context = xscale_full_context; + + armv4_5_init_arch_info(target, armv4_5); + + xscale->armv4_5_mmu.armv4_5_cache.ctype = -1; + xscale->armv4_5_mmu.get_ttb = xscale_get_ttb; + xscale->armv4_5_mmu.read_memory = xscale_read_memory; + xscale->armv4_5_mmu.write_memory = xscale_write_memory; + xscale->armv4_5_mmu.disable_mmu_caches = xscale_disable_mmu_caches; + xscale->armv4_5_mmu.enable_mmu_caches = xscale_enable_mmu_caches; + xscale->armv4_5_mmu.has_tiny_pages = 1; + xscale->armv4_5_mmu.mmu_enabled = 0; + + xscale->fast_memory_access = 0; + + return ERROR_OK; +} + +/* target xscale <endianess> <startup_mode> <chain_pos> <variant> */ +int xscale_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + int chain_pos; + char *variant = NULL; + xscale_common_t *xscale = malloc(sizeof(xscale_common_t)); + + if (argc < 5) + { + ERROR("'target xscale' requires four arguments: <endianess> <startup_mode> <chain_pos> <variant>"); + return ERROR_OK; + } + + chain_pos = strtoul(args[3], NULL, 0); + + variant = args[4]; + + xscale_init_arch_info(target, xscale, chain_pos, variant); + xscale_build_reg_cache(target); + + return ERROR_OK; +} + +int xscale_handle_debug_handler_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = NULL; + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + u32 handler_address; + + if (argc < 2) + { + ERROR("'xscale debug_handler <target#> <address>' command takes two required operands"); + return ERROR_OK; + } + + if ((target = get_target_by_num(strtoul(args[0], NULL, 0))) == NULL) + { + ERROR("no target '%s' configured", args[0]); + return ERROR_OK; + } + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + handler_address = strtoul(args[1], NULL, 0); + + if (((handler_address >= 0x800) && (handler_address <= 0x1fef800)) || + ((handler_address >= 0xfe000800) && (handler_address <= 0xfffff800))) + { + xscale->handler_address = handler_address; + } + else + { + ERROR("xscale debug_handler <address> must be between 0x800 and 0x1fef800 or between 0xfe000800 and 0xfffff800"); + } + + return ERROR_OK; +} + +int xscale_handle_cache_clean_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = NULL; + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + u32 cache_clean_address; + + if (argc < 2) + { + ERROR("'xscale cache_clean_address <target#> <address>' command takes two required operands"); + return ERROR_OK; + } + + if ((target = get_target_by_num(strtoul(args[0], NULL, 0))) == NULL) + { + ERROR("no target '%s' configured", args[0]); + return ERROR_OK; + } + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + cache_clean_address = strtoul(args[1], NULL, 0); + + if (cache_clean_address & 0xffff) + { + ERROR("xscale cache_clean_address <address> must be 64kb aligned"); + } + else + { + xscale->cache_clean_address = cache_clean_address; + } + + return ERROR_OK; +} + +int xscale_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + return armv4_5_handle_cache_info_command(cmd_ctx, &xscale->armv4_5_mmu.armv4_5_cache); +} + +static int xscale_virt2phys(struct target_s *target, u32 virtual, u32 *physical) +{ + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + int retval; + int type; + u32 cb; + int domain; + u32 ap; + + if ((retval = xscale_get_arch_pointers(target, &armv4_5, &xscale)) != ERROR_OK) + { + return retval; + } + u32 ret = armv4_5_mmu_translate_va(target, &xscale->armv4_5_mmu, virtual, &type, &cb, &domain, &ap); + if (type == -1) + { + return ret; + } + + *physical = ret; + return ERROR_OK; +} + +static int xscale_mmu(struct target_s *target, int *enabled) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + ERROR("Target not halted"); + return ERROR_TARGET_INVALID; + } + + *enabled = xscale->armv4_5_mmu.mmu_enabled; + return ERROR_OK; +} + +int xscale_handle_mmu_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + if (argc >= 1) + { + if (strcmp("enable", args[0]) == 0) + { + xscale_enable_mmu_caches(target, 1, 0, 0); + xscale->armv4_5_mmu.mmu_enabled = 1; + } + else if (strcmp("disable", args[0]) == 0) + { + xscale_disable_mmu_caches(target, 1, 0, 0); + xscale->armv4_5_mmu.mmu_enabled = 0; + } + } + + command_print(cmd_ctx, "mmu %s", (xscale->armv4_5_mmu.mmu_enabled) ? "enabled" : "disabled"); + + return ERROR_OK; +} + +int xscale_handle_idcache_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + int icache = 0, dcache = 0; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + if (strcmp(cmd, "icache") == 0) + icache = 1; + else if (strcmp(cmd, "dcache") == 0) + dcache = 1; + + if (argc >= 1) + { + if (strcmp("enable", args[0]) == 0) + { + xscale_enable_mmu_caches(target, 0, dcache, icache); + + if (icache) + xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 1; + else if (dcache) + xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 1; + } + else if (strcmp("disable", args[0]) == 0) + { + xscale_disable_mmu_caches(target, 0, dcache, icache); + + if (icache) + xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + else if (dcache) + xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; + } + } + + if (icache) + command_print(cmd_ctx, "icache %s", (xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled) ? "enabled" : "disabled"); + + if (dcache) + command_print(cmd_ctx, "dcache %s", (xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) ? "enabled" : "disabled"); + + return ERROR_OK; +} + +int xscale_handle_vector_catch_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (argc < 1) + { + command_print(cmd_ctx, "usage: xscale vector_catch [mask]"); + } + else + { + xscale->vector_catch = strtoul(args[0], NULL, 0); + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 8, xscale->vector_catch); + xscale_write_dcsr(target, -1, -1); + } + + command_print(cmd_ctx, "vector catch mask: 0x%2.2x", xscale->vector_catch); + + return ERROR_OK; +} + +int xscale_handle_force_hw_bkpts_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if ((argc >= 1) && (strcmp("enable", args[0]) == 0)) + { + xscale->force_hw_bkpts = 1; + } + else if ((argc >= 1) && (strcmp("disable", args[0]) == 0)) + { + xscale->force_hw_bkpts = 0; + } + else + { + command_print(cmd_ctx, "usage: xscale force_hw_bkpts <enable|disable>"); + } + + command_print(cmd_ctx, "force hardware breakpoints %s", (xscale->force_hw_bkpts) ? "enabled" : "disabled"); + + return ERROR_OK; +} + +int xscale_handle_trace_buffer_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + u32 dcsr_value; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + if ((argc >= 1) && (strcmp("enable", args[0]) == 0)) + { + xscale_trace_data_t *td, *next_td; + xscale->trace.buffer_enabled = 1; + + /* free old trace data */ + td = xscale->trace.data; + while (td) + { + next_td = td->next; + + if (td->entries) + free(td->entries); + free(td); + td = next_td; + } + xscale->trace.data = NULL; + } + else if ((argc >= 1) && (strcmp("disable", args[0]) == 0)) + { + xscale->trace.buffer_enabled = 0; + } + + if ((argc >= 2) && (strcmp("fill", args[1]) == 0)) + { + if (argc >= 3) + xscale->trace.buffer_fill = strtoul(args[2], NULL, 0); + else + xscale->trace.buffer_fill = 1; + } + else if ((argc >= 2) && (strcmp("wrap", args[1]) == 0)) + { + xscale->trace.buffer_fill = -1; + } + + if (xscale->trace.buffer_enabled) + { + /* if we enable the trace buffer in fill-once + * mode we know the address of the first instruction */ + xscale->trace.pc_ok = 1; + xscale->trace.current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + } + else + { + /* otherwise the address is unknown, and we have no known good PC */ + xscale->trace.pc_ok = 0; + } + + command_print(cmd_ctx, "trace buffer %s (%s)", + (xscale->trace.buffer_enabled) ? "enabled" : "disabled", + (xscale->trace.buffer_fill > 0) ? "fill" : "wrap"); + + dcsr_value = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32); + if (xscale->trace.buffer_fill >= 0) + xscale_write_dcsr_sw(target, (dcsr_value & 0xfffffffc) | 2); + else + xscale_write_dcsr_sw(target, dcsr_value & 0xfffffffc); + + return ERROR_OK; +} + +int xscale_handle_trace_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + if (argc < 1) + { + command_print(cmd_ctx, "usage: xscale trace_image <file> [base address] [type]"); + return ERROR_OK; + } + + target = get_current_target(cmd_ctx); + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (xscale->trace.image) + { + image_close(xscale->trace.image); + free(xscale->trace.image); + command_print(cmd_ctx, "previously loaded image found and closed"); + } + + xscale->trace.image = malloc(sizeof(image_t)); + xscale->trace.image->base_address_set = 0; + xscale->trace.image->start_address_set = 0; + + /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ + if (argc >= 2) + { + xscale->trace.image->base_address_set = 1; + xscale->trace.image->base_address = strtoul(args[1], NULL, 0); + } + else + { + xscale->trace.image->base_address_set = 0; + } + + if (image_open(xscale->trace.image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK) + { + command_print(cmd_ctx, "image opening error: %s", xscale->trace.image->error_str); + free(xscale->trace.image); + xscale->trace.image = NULL; + return ERROR_OK; + } + + return ERROR_OK; +} + +int xscale_handle_dump_trace_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + xscale_trace_data_t *trace_data; + fileio_t file; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + if (argc < 1) + { + command_print(cmd_ctx, "usage: xscale dump_trace <file>"); + return ERROR_OK; + } + + trace_data = xscale->trace.data; + + if (!trace_data) + { + command_print(cmd_ctx, "no trace data collected"); + return ERROR_OK; + } + + if (fileio_open(&file, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) + { + command_print(cmd_ctx, "file open error: %s", file.error_str); + return ERROR_OK; + } + + while (trace_data) + { + int i; + + fileio_write_u32(&file, trace_data->chkpt0); + fileio_write_u32(&file, trace_data->chkpt1); + fileio_write_u32(&file, trace_data->last_instruction); + fileio_write_u32(&file, trace_data->depth); + + for (i = 0; i < trace_data->depth; i++) + fileio_write_u32(&file, trace_data->entries[i].data | ((trace_data->entries[i].type & 0xffff) << 16)); + + trace_data = trace_data->next; + } + + fileio_close(&file); + + return ERROR_OK; +} + +int xscale_handle_analyze_trace_buffer_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + xscale_analyze_trace(target, cmd_ctx); + + return ERROR_OK; +} + +int xscale_handle_cp15(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + u32 reg_no = 0; + reg_t *reg = NULL; + if(argc > 0) + { + reg_no = strtoul(args[0], NULL, 0); + /*translate from xscale cp15 register no to openocd register*/ + switch(reg_no) + { + case 0: + reg_no = XSCALE_MAINID; + break; + case 1: + reg_no = XSCALE_CTRL; + break; + case 2: + reg_no = XSCALE_TTB; + break; + case 3: + reg_no = XSCALE_DAC; + break; + case 5: + reg_no = XSCALE_FSR; + break; + case 6: + reg_no = XSCALE_FAR; + break; + case 13: + reg_no = XSCALE_PID; + break; + case 15: + reg_no = XSCALE_CPACCESS; + break; + default: + command_print(cmd_ctx, "invalid register number"); + return ERROR_INVALID_ARGUMENTS; + } + reg = &xscale->reg_cache->reg_list[reg_no]; + + } + if(argc == 1) + { + u32 value; + + /* read cp15 control register */ + xscale_get_reg(reg); + value = buf_get_u32(reg->value, 0, 32); + command_print(cmd_ctx, "%s (/%i): 0x%x", reg->name, reg->size, value); + } + else if(argc == 2) + { + + u32 value = strtoul(args[1], NULL, 0); + + /* send CP write request (command 0x41) */ + xscale_send_u32(target, 0x41); + + /* send CP register number */ + xscale_send_u32(target, reg_no); + + /* send CP register value */ + xscale_send_u32(target, value); + + /* execute cpwait to ensure outstanding operations complete */ + xscale_send_u32(target, 0x53); + } + else + { + command_print(cmd_ctx, "usage: cp15 [register]<, [value]>"); + } + + return ERROR_OK; +} + +int handle_xscale_fast_memory_access_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (argc == 1) + { + if (strcmp("enable", args[0]) == 0) + { + xscale->fast_memory_access = 1; + } + else if (strcmp("disable", args[0]) == 0) + { + xscale->fast_memory_access = 0; + } + else + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + } else if (argc!=0) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + command_print(cmd_ctx, "fast memory access is %s", (xscale->fast_memory_access) ? "enabled" : "disabled"); + + return ERROR_OK; +} + +int xscale_register_commands(struct command_context_s *cmd_ctx) +{ + command_t *xscale_cmd; + + xscale_cmd = register_command(cmd_ctx, NULL, "xscale", NULL, COMMAND_ANY, "xscale specific commands"); + + register_command(cmd_ctx, xscale_cmd, "debug_handler", xscale_handle_debug_handler_command, COMMAND_ANY, "'xscale debug_handler <target#> <address>' command takes two required operands"); + register_command(cmd_ctx, xscale_cmd, "cache_clean_address", xscale_handle_cache_clean_address_command, COMMAND_ANY, NULL); + + register_command(cmd_ctx, xscale_cmd, "cache_info", xscale_handle_cache_info_command, COMMAND_EXEC, NULL); + register_command(cmd_ctx, xscale_cmd, "mmu", xscale_handle_mmu_command, COMMAND_EXEC, "['enable'|'disable'] the MMU"); + register_command(cmd_ctx, xscale_cmd, "icache", xscale_handle_idcache_command, COMMAND_EXEC, "['enable'|'disable'] the ICache"); + register_command(cmd_ctx, xscale_cmd, "dcache", xscale_handle_idcache_command, COMMAND_EXEC, "['enable'|'disable'] the DCache"); + + register_command(cmd_ctx, xscale_cmd, "vector_catch", xscale_handle_idcache_command, COMMAND_EXEC, "<mask> of vectors that should be catched"); + + register_command(cmd_ctx, xscale_cmd, "trace_buffer", xscale_handle_trace_buffer_command, COMMAND_EXEC, "<enable|disable> ['fill' [n]|'wrap']"); + + register_command(cmd_ctx, xscale_cmd, "dump_trace", xscale_handle_dump_trace_command, COMMAND_EXEC, "dump content of trace buffer to <file>"); + register_command(cmd_ctx, xscale_cmd, "analyze_trace", xscale_handle_analyze_trace_buffer_command, COMMAND_EXEC, "analyze content of trace buffer"); + register_command(cmd_ctx, xscale_cmd, "trace_image", xscale_handle_trace_image_command, + COMMAND_EXEC, "load image from <file> [base address]"); + + register_command(cmd_ctx, xscale_cmd, "cp15", xscale_handle_cp15, COMMAND_EXEC, "access coproc 15 <register> [value]"); + register_command(cmd_ctx, xscale_cmd, "fast_memory_access", handle_xscale_fast_memory_access_command, + COMMAND_ANY, "use fast memory accesses instead of slower but potentially unsafe slow accesses <enable|disable>"); + + armv4_5_register_commands(cmd_ctx); + + return ERROR_OK; +} diff --git a/src/xsvf/xsvf.c b/src/xsvf/xsvf.c index 298377d..b589a8a 100644 --- a/src/xsvf/xsvf.c +++ b/src/xsvf/xsvf.c @@ -1,501 +1,501 @@ -/***************************************************************************
- * 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 "xsvf.h"
-
-#include "jtag.h"
-#include "command.h"
-#include "log.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <string.h>
-
-#include <sys/time.h>
-#include <time.h>
-
-#define XSTATE_MAX_PATH (12)
-
-int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-int xsvf_fd = 0;
-
-u8 *dr_out_buf; /* from host to device (TDI) */
-u8 *dr_in_buf; /* from device to host (TDO) */
-u8 *dr_in_mask;
-
-int xsdrsize = 0;
-int xruntest = 0; /* number of TCK cycles / microseconds */
-int xrepeat = 0x20; /* number of XC9500 retries */
-
-int xendir = 0;
-int xenddr = 0;
-
-enum tap_state xsvf_to_tap[] =
-{
- TAP_TLR, TAP_RTI,
- TAP_SDS, TAP_CD, TAP_SD, TAP_E1D, TAP_PD, TAP_E2D, TAP_UD,
- TAP_SIS, TAP_CI, TAP_SI, TAP_E1I, TAP_PI, TAP_E2I, TAP_UI,
-};
-
-int tap_to_xsvf[] =
-{
- 0x0, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x1, 0x9, 0xa, 0xb, 0xc, 0xe, 0xf
-};
-
-int xsvf_register_commands(struct command_context_s *cmd_ctx)
-{
- register_command(cmd_ctx, NULL, "xsvf", handle_xsvf_command,
- COMMAND_EXEC, "run xsvf <file>");
-
- return ERROR_OK;
-}
-
-int xsvf_read_buffer(int num_bits, int fd, u8* buf)
-{
- int num_bytes;
-
- for (num_bytes = (num_bits + 7) / 8; num_bytes > 0; num_bytes--)
- {
- if (read(fd, buf + num_bytes - 1, 1) < 0)
- return ERROR_XSVF_EOF;
- }
-
- return ERROR_OK;
-}
-
-int xsvf_read_xstates(int fd, enum tap_state *path, int max_path, int *path_len)
-{
- char c;
- unsigned char uc;
-
- while ((read(fd, &c, 1) > 0) && (c == 0x12))
- {
- if (*path_len > max_path)
- {
- WARNING("XSTATE path longer than max_path");
- break;
- }
- if (read(fd, &uc, 1) < 0)
- {
- return ERROR_XSVF_EOF;
- }
- path[(*path_len)++] = xsvf_to_tap[uc];
- }
-
- lseek(fd, -1, SEEK_CUR);
-
- return ERROR_OK;
-}
-
-int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- char c;
- u8 buf4[4], buf2[2];
- unsigned char uc, uc2;
- unsigned int ui;
- unsigned short us;
-
- int do_abort = 0;
- int unsupported = 0;
- int tdo_mismatch = 0;
-
- int runtest_requires_tck = 0;
-
- int device = -1; /* use -1 to indicate a "plain" xsvf file which accounts for additional devices in the scan chain, otherwise the device that should be affected */
-
- if (argc < 2)
- {
- command_print(cmd_ctx, "usage: xsvf <device#|plain> <file> <variant>");
- return ERROR_OK;
- }
-
- if (strcmp(args[0], "plain") != 0)
- {
- device = strtoul(args[0], NULL, 0);
- }
-
- if ((xsvf_fd = open(args[1], O_RDONLY)) < 0)
- {
- command_print(cmd_ctx, "file %s not found", args[0]);
- return ERROR_OK;
- }
-
- if ((argc > 2) && (strcmp(args[2], "virt2") == 0))
- {
- runtest_requires_tck = 1;
- }
-
- while (read(xsvf_fd, &c, 1) > 0)
- {
- switch (c)
- {
- case 0x00: /* XCOMPLETE */
- DEBUG("XCOMPLETE");
- if (jtag_execute_queue() != ERROR_OK)
- {
- tdo_mismatch = 1;
- break;
- }
- break;
- case 0x01: /* XTDOMASK */
- DEBUG("XTDOMASK");
- if (dr_in_mask && (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_in_mask) != ERROR_OK))
- do_abort = 1;
- break;
- case 0x02: /* XSIR */
- DEBUG("XSIR");
- if (read(xsvf_fd, &c, 1) < 0)
- do_abort = 1;
- else
- {
- u8 *ir_buf = malloc((c + 7) / 8);
- if (xsvf_read_buffer(c, xsvf_fd, ir_buf) != ERROR_OK)
- do_abort = 1;
- else
- {
- scan_field_t field;
- field.device = device;
- field.num_bits = c;
- field.out_value = ir_buf;
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
- if (device == -1)
- jtag_add_plain_ir_scan(1, &field, TAP_PI);
- else
- jtag_add_ir_scan(1, &field, TAP_PI);
- if (jtag_execute_queue() != ERROR_OK)
- {
- tdo_mismatch = 1;
- free(ir_buf);
- break;
- }
- if (xruntest)
- {
- if (runtest_requires_tck)
- jtag_add_runtest(xruntest, xsvf_to_tap[xendir]);
- else
- {
- jtag_add_statemove(TAP_RTI);
- jtag_add_sleep(xruntest);
- jtag_add_statemove(xsvf_to_tap[xendir]);
- }
- }
- else if (xendir != 0xd) /* Pause-IR */
- jtag_add_statemove(xsvf_to_tap[xendir]);
- }
- free(ir_buf);
- }
- break;
- case 0x03: /* XSDR */
- DEBUG("XSDR");
- if (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_out_buf) != ERROR_OK)
- do_abort = 1;
- else
- {
- scan_field_t field;
- field.device = device;
- field.num_bits = xsdrsize;
- field.out_value = dr_out_buf;
- field.out_mask = NULL;
- field.in_value = NULL;
- jtag_set_check_value(&field, dr_in_buf, dr_in_mask, NULL);
- if (device == -1)
- jtag_add_plain_dr_scan(1, &field, TAP_PD);
- else
- jtag_add_dr_scan(1, &field, TAP_PD);
- if (jtag_execute_queue() != ERROR_OK)
- {
- tdo_mismatch = 1;
- break;
- }
- if (xruntest)
- {
- if (runtest_requires_tck)
- jtag_add_runtest(xruntest, xsvf_to_tap[xenddr]);
- else
- {
- jtag_add_statemove(TAP_RTI);
- jtag_add_sleep(xruntest);
- jtag_add_statemove(xsvf_to_tap[xenddr]);
- }
- }
- else if (xendir != 0x6) /* Pause-DR */
- jtag_add_statemove(xsvf_to_tap[xenddr]);
- }
- break;
- case 0x04: /* XRUNTEST */
- DEBUG("XRUNTEST");
- if (read(xsvf_fd, buf4, 4) < 0)
- do_abort = 1;
- else
- {
- xruntest = be_to_h_u32(buf4);
- }
- break;
- case 0x07: /* XREPEAT */
- DEBUG("XREPEAT");
- if (read(xsvf_fd, &c, 1) < 0)
- do_abort = 1;
- else
- {
- xrepeat = c;
- }
- break;
- case 0x08: /* XSDRSIZE */
- DEBUG("XSDRSIZE");
- if (read(xsvf_fd, buf4, 4) < 0)
- do_abort = 1;
- else
- {
- xsdrsize = be_to_h_u32(buf4);
- free(dr_out_buf);
- free(dr_in_buf);
- free(dr_in_mask);
- dr_out_buf = malloc((xsdrsize + 7) / 8);
- dr_in_buf = malloc((xsdrsize + 7) / 8);
- dr_in_mask = malloc((xsdrsize + 7) / 8);
- }
- break;
- case 0x09: /* XSDRTDO */
- DEBUG("XSDRTDO");
- if (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_out_buf) != ERROR_OK)
- do_abort = 1;
- else
- {
- if (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_in_buf) != ERROR_OK)
- do_abort = 1;
- else
- {
- scan_field_t field;
- field.device = device;
- field.num_bits = xsdrsize;
- field.out_value = dr_out_buf;
- field.out_mask = NULL;
- field.in_value = NULL;
- jtag_set_check_value(&field, dr_in_buf, dr_in_mask, NULL);
- if (device == -1)
- jtag_add_plain_dr_scan(1, &field, TAP_PD);
- else
- jtag_add_dr_scan(1, &field, TAP_PD);
- if (jtag_execute_queue() != ERROR_OK)
- {
- tdo_mismatch = 1;
- break;
- }
- if (xruntest)
- {
- if (runtest_requires_tck)
- jtag_add_runtest(xruntest, xsvf_to_tap[xenddr]);
- else
- {
- jtag_add_statemove(TAP_RTI);
- jtag_add_sleep(xruntest);
- jtag_add_statemove(xsvf_to_tap[xenddr]);
- }
- }
- else if (xendir != 0x6) /* Pause-DR */
- jtag_add_statemove(xsvf_to_tap[xenddr]);
- }
- }
- break;
- case 0x0a: /* XSETDRMASKS */
- ERROR("unsupported XSETSDRMASKS\n");
- unsupported = 1;
- break;
- case 0x0b: /* XSDRINC */
- ERROR("unsupported XSDRINC\n");
- unsupported = 1;
- break;
- case 0x0c: /* XSDRB */
- unsupported = 1;
- break;
- case 0x0d: /* XSDRC */
- unsupported = 1;
- break;
- case 0x0e: /* XSDRE */
- unsupported = 1;
- break;
- case 0x0f: /* XSDRTDOB */
- unsupported = 1;
- break;
- case 0x10: /* XSDRTDOB */
- unsupported = 1;
- break;
- case 0x11: /* XSDRTDOB */
- unsupported = 1;
- break;
- case 0x12: /* XSTATE */
- DEBUG("XSTATE");
- if (read(xsvf_fd, &uc, 1) < 0)
- do_abort = 1;
- else
- {
- enum tap_state *path = calloc(XSTATE_MAX_PATH, 4);
- int path_len = 1;
- path[0] = xsvf_to_tap[uc];
- if (xsvf_read_xstates(xsvf_fd, path, XSTATE_MAX_PATH, &path_len) != ERROR_OK)
- do_abort = 1;
- else
- {
- jtag_add_pathmove(path_len, path);
- }
- free(path);
- }
- break;
- case 0x13: /* XENDIR */
- DEBUG("XENDIR");
- if (read(xsvf_fd, &c, 1) < 0)
- do_abort = 1;
- else
- {
- if (c == 0)
- xendir = 1;
- else if (c == 1)
- xendir = 0xd;
- else
- {
- ERROR("unknown XENDIR endstate");
- unsupported = 1;
- }
- }
- break;
- case 0x14: /* XENDDR */
- DEBUG("XENDDR");
- if (read(xsvf_fd, &c, 1) < 0)
- do_abort = 1;
- else
- {
- if (c == 0)
- xenddr = 1;
- else if (c == 1)
- xenddr = 0x6;
- else
- {
- ERROR("unknown XENDDR endstate");
- unsupported = 1;
- }
- }
- break;
- case 0x15: /* XSIR2 */
- DEBUG("XSIR2");
- if (read(xsvf_fd, buf2, 2) < 0)
- do_abort = 1;
- else
- {
- u8 *ir_buf;
- us = be_to_h_u16(buf2);
- ir_buf = malloc((us + 7) / 8);
- if (xsvf_read_buffer(us, xsvf_fd, ir_buf) != ERROR_OK)
- do_abort = 1;
- else
- {
- scan_field_t field;
- field.device = device;
- field.num_bits = us;
- field.out_value = ir_buf;
- field.out_mask = NULL;
- field.in_value = NULL;
- field.in_check_value = NULL;
- field.in_check_mask = NULL;
- field.in_handler = NULL;
- field.in_handler_priv = NULL;
- if (device == -1)
- jtag_add_plain_ir_scan(1, &field, xsvf_to_tap[xendir]);
- else
- jtag_add_ir_scan(1, &field, xsvf_to_tap[xendir]);
- }
- free(ir_buf);
- }
- break;
- case 0x16: /* XCOMMENT */
- do
- {
- if (read(xsvf_fd, &c, 1) < 0)
- {
- do_abort = 1;
- break;
- }
- } while (c != 0);
- break;
- case 0x17: /* XWAIT */
- DEBUG("XWAIT");
- if ((read(xsvf_fd, &uc, 1) < 0) || (read(xsvf_fd, &uc2, 1) < 0) || (read(xsvf_fd, buf4, 4) < 0))
- do_abort = 1;
- else
- {
- jtag_add_statemove(xsvf_to_tap[uc]);
- ui = be_to_h_u32(buf4);
- jtag_add_sleep(ui);
- jtag_add_statemove(xsvf_to_tap[uc2]);
- }
- break;
- default:
- ERROR("unknown xsvf command (0x%2.2x)\n", c);
- unsupported = 1;
- }
-
- if (do_abort || unsupported || tdo_mismatch)
- break;
- }
-
- if (tdo_mismatch)
- {
- command_print(cmd_ctx, "TDO mismatch, aborting");
- return ERROR_OK;
- }
-
- if (unsupported)
- {
- command_print(cmd_ctx, "unsupported xsvf command encountered, aborting");
- return ERROR_OK;
- }
-
- if (do_abort)
- {
- command_print(cmd_ctx, "premature end detected, aborting");
- return ERROR_OK;
- }
-
- if (dr_out_buf)
- free(dr_out_buf);
-
- if (dr_in_buf)
- free(dr_in_buf);
-
- if (dr_in_mask)
- free(dr_in_mask);
-
- close(xsvf_fd);
-
- command_print(cmd_ctx, "XSVF file programmed successfully");
-
- return ERROR_OK;
-}
+/*************************************************************************** + * 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 "xsvf.h" + +#include "jtag.h" +#include "command.h" +#include "log.h" + +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> + +#include <sys/time.h> +#include <time.h> + +#define XSTATE_MAX_PATH (12) + +int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int xsvf_fd = 0; + +u8 *dr_out_buf; /* from host to device (TDI) */ +u8 *dr_in_buf; /* from device to host (TDO) */ +u8 *dr_in_mask; + +int xsdrsize = 0; +int xruntest = 0; /* number of TCK cycles / microseconds */ +int xrepeat = 0x20; /* number of XC9500 retries */ + +int xendir = 0; +int xenddr = 0; + +enum tap_state xsvf_to_tap[] = +{ + TAP_TLR, TAP_RTI, + TAP_SDS, TAP_CD, TAP_SD, TAP_E1D, TAP_PD, TAP_E2D, TAP_UD, + TAP_SIS, TAP_CI, TAP_SI, TAP_E1I, TAP_PI, TAP_E2I, TAP_UI, +}; + +int tap_to_xsvf[] = +{ + 0x0, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x1, 0x9, 0xa, 0xb, 0xc, 0xe, 0xf +}; + +int xsvf_register_commands(struct command_context_s *cmd_ctx) +{ + register_command(cmd_ctx, NULL, "xsvf", handle_xsvf_command, + COMMAND_EXEC, "run xsvf <file>"); + + return ERROR_OK; +} + +int xsvf_read_buffer(int num_bits, int fd, u8* buf) +{ + int num_bytes; + + for (num_bytes = (num_bits + 7) / 8; num_bytes > 0; num_bytes--) + { + if (read(fd, buf + num_bytes - 1, 1) < 0) + return ERROR_XSVF_EOF; + } + + return ERROR_OK; +} + +int xsvf_read_xstates(int fd, enum tap_state *path, int max_path, int *path_len) +{ + char c; + unsigned char uc; + + while ((read(fd, &c, 1) > 0) && (c == 0x12)) + { + if (*path_len > max_path) + { + WARNING("XSTATE path longer than max_path"); + break; + } + if (read(fd, &uc, 1) < 0) + { + return ERROR_XSVF_EOF; + } + path[(*path_len)++] = xsvf_to_tap[uc]; + } + + lseek(fd, -1, SEEK_CUR); + + return ERROR_OK; +} + +int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + char c; + u8 buf4[4], buf2[2]; + unsigned char uc, uc2; + unsigned int ui; + unsigned short us; + + int do_abort = 0; + int unsupported = 0; + int tdo_mismatch = 0; + + int runtest_requires_tck = 0; + + int device = -1; /* use -1 to indicate a "plain" xsvf file which accounts for additional devices in the scan chain, otherwise the device that should be affected */ + + if (argc < 2) + { + command_print(cmd_ctx, "usage: xsvf <device#|plain> <file> <variant>"); + return ERROR_OK; + } + + if (strcmp(args[0], "plain") != 0) + { + device = strtoul(args[0], NULL, 0); + } + + if ((xsvf_fd = open(args[1], O_RDONLY)) < 0) + { + command_print(cmd_ctx, "file %s not found", args[0]); + return ERROR_OK; + } + + if ((argc > 2) && (strcmp(args[2], "virt2") == 0)) + { + runtest_requires_tck = 1; + } + + while (read(xsvf_fd, &c, 1) > 0) + { + switch (c) + { + case 0x00: /* XCOMPLETE */ + DEBUG("XCOMPLETE"); + if (jtag_execute_queue() != ERROR_OK) + { + tdo_mismatch = 1; + break; + } + break; + case 0x01: /* XTDOMASK */ + DEBUG("XTDOMASK"); + if (dr_in_mask && (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_in_mask) != ERROR_OK)) + do_abort = 1; + break; + case 0x02: /* XSIR */ + DEBUG("XSIR"); + if (read(xsvf_fd, &c, 1) < 0) + do_abort = 1; + else + { + u8 *ir_buf = malloc((c + 7) / 8); + if (xsvf_read_buffer(c, xsvf_fd, ir_buf) != ERROR_OK) + do_abort = 1; + else + { + scan_field_t field; + field.device = device; + field.num_bits = c; + field.out_value = ir_buf; + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + if (device == -1) + jtag_add_plain_ir_scan(1, &field, TAP_PI); + else + jtag_add_ir_scan(1, &field, TAP_PI); + if (jtag_execute_queue() != ERROR_OK) + { + tdo_mismatch = 1; + free(ir_buf); + break; + } + if (xruntest) + { + if (runtest_requires_tck) + jtag_add_runtest(xruntest, xsvf_to_tap[xendir]); + else + { + jtag_add_statemove(TAP_RTI); + jtag_add_sleep(xruntest); + jtag_add_statemove(xsvf_to_tap[xendir]); + } + } + else if (xendir != 0xd) /* Pause-IR */ + jtag_add_statemove(xsvf_to_tap[xendir]); + } + free(ir_buf); + } + break; + case 0x03: /* XSDR */ + DEBUG("XSDR"); + if (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_out_buf) != ERROR_OK) + do_abort = 1; + else + { + scan_field_t field; + field.device = device; + field.num_bits = xsdrsize; + field.out_value = dr_out_buf; + field.out_mask = NULL; + field.in_value = NULL; + jtag_set_check_value(&field, dr_in_buf, dr_in_mask, NULL); + if (device == -1) + jtag_add_plain_dr_scan(1, &field, TAP_PD); + else + jtag_add_dr_scan(1, &field, TAP_PD); + if (jtag_execute_queue() != ERROR_OK) + { + tdo_mismatch = 1; + break; + } + if (xruntest) + { + if (runtest_requires_tck) + jtag_add_runtest(xruntest, xsvf_to_tap[xenddr]); + else + { + jtag_add_statemove(TAP_RTI); + jtag_add_sleep(xruntest); + jtag_add_statemove(xsvf_to_tap[xenddr]); + } + } + else if (xendir != 0x6) /* Pause-DR */ + jtag_add_statemove(xsvf_to_tap[xenddr]); + } + break; + case 0x04: /* XRUNTEST */ + DEBUG("XRUNTEST"); + if (read(xsvf_fd, buf4, 4) < 0) + do_abort = 1; + else + { + xruntest = be_to_h_u32(buf4); + } + break; + case 0x07: /* XREPEAT */ + DEBUG("XREPEAT"); + if (read(xsvf_fd, &c, 1) < 0) + do_abort = 1; + else + { + xrepeat = c; + } + break; + case 0x08: /* XSDRSIZE */ + DEBUG("XSDRSIZE"); + if (read(xsvf_fd, buf4, 4) < 0) + do_abort = 1; + else + { + xsdrsize = be_to_h_u32(buf4); + free(dr_out_buf); + free(dr_in_buf); + free(dr_in_mask); + dr_out_buf = malloc((xsdrsize + 7) / 8); + dr_in_buf = malloc((xsdrsize + 7) / 8); + dr_in_mask = malloc((xsdrsize + 7) / 8); + } + break; + case 0x09: /* XSDRTDO */ + DEBUG("XSDRTDO"); + if (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_out_buf) != ERROR_OK) + do_abort = 1; + else + { + if (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_in_buf) != ERROR_OK) + do_abort = 1; + else + { + scan_field_t field; + field.device = device; + field.num_bits = xsdrsize; + field.out_value = dr_out_buf; + field.out_mask = NULL; + field.in_value = NULL; + jtag_set_check_value(&field, dr_in_buf, dr_in_mask, NULL); + if (device == -1) + jtag_add_plain_dr_scan(1, &field, TAP_PD); + else + jtag_add_dr_scan(1, &field, TAP_PD); + if (jtag_execute_queue() != ERROR_OK) + { + tdo_mismatch = 1; + break; + } + if (xruntest) + { + if (runtest_requires_tck) + jtag_add_runtest(xruntest, xsvf_to_tap[xenddr]); + else + { + jtag_add_statemove(TAP_RTI); + jtag_add_sleep(xruntest); + jtag_add_statemove(xsvf_to_tap[xenddr]); + } + } + else if (xendir != 0x6) /* Pause-DR */ + jtag_add_statemove(xsvf_to_tap[xenddr]); + } + } + break; + case 0x0a: /* XSETDRMASKS */ + ERROR("unsupported XSETSDRMASKS\n"); + unsupported = 1; + break; + case 0x0b: /* XSDRINC */ + ERROR("unsupported XSDRINC\n"); + unsupported = 1; + break; + case 0x0c: /* XSDRB */ + unsupported = 1; + break; + case 0x0d: /* XSDRC */ + unsupported = 1; + break; + case 0x0e: /* XSDRE */ + unsupported = 1; + break; + case 0x0f: /* XSDRTDOB */ + unsupported = 1; + break; + case 0x10: /* XSDRTDOB */ + unsupported = 1; + break; + case 0x11: /* XSDRTDOB */ + unsupported = 1; + break; + case 0x12: /* XSTATE */ + DEBUG("XSTATE"); + if (read(xsvf_fd, &uc, 1) < 0) + do_abort = 1; + else + { + enum tap_state *path = calloc(XSTATE_MAX_PATH, 4); + int path_len = 1; + path[0] = xsvf_to_tap[uc]; + if (xsvf_read_xstates(xsvf_fd, path, XSTATE_MAX_PATH, &path_len) != ERROR_OK) + do_abort = 1; + else + { + jtag_add_pathmove(path_len, path); + } + free(path); + } + break; + case 0x13: /* XENDIR */ + DEBUG("XENDIR"); + if (read(xsvf_fd, &c, 1) < 0) + do_abort = 1; + else + { + if (c == 0) + xendir = 1; + else if (c == 1) + xendir = 0xd; + else + { + ERROR("unknown XENDIR endstate"); + unsupported = 1; + } + } + break; + case 0x14: /* XENDDR */ + DEBUG("XENDDR"); + if (read(xsvf_fd, &c, 1) < 0) + do_abort = 1; + else + { + if (c == 0) + xenddr = 1; + else if (c == 1) + xenddr = 0x6; + else + { + ERROR("unknown XENDDR endstate"); + unsupported = 1; + } + } + break; + case 0x15: /* XSIR2 */ + DEBUG("XSIR2"); + if (read(xsvf_fd, buf2, 2) < 0) + do_abort = 1; + else + { + u8 *ir_buf; + us = be_to_h_u16(buf2); + ir_buf = malloc((us + 7) / 8); + if (xsvf_read_buffer(us, xsvf_fd, ir_buf) != ERROR_OK) + do_abort = 1; + else + { + scan_field_t field; + field.device = device; + field.num_bits = us; + field.out_value = ir_buf; + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + if (device == -1) + jtag_add_plain_ir_scan(1, &field, xsvf_to_tap[xendir]); + else + jtag_add_ir_scan(1, &field, xsvf_to_tap[xendir]); + } + free(ir_buf); + } + break; + case 0x16: /* XCOMMENT */ + do + { + if (read(xsvf_fd, &c, 1) < 0) + { + do_abort = 1; + break; + } + } while (c != 0); + break; + case 0x17: /* XWAIT */ + DEBUG("XWAIT"); + if ((read(xsvf_fd, &uc, 1) < 0) || (read(xsvf_fd, &uc2, 1) < 0) || (read(xsvf_fd, buf4, 4) < 0)) + do_abort = 1; + else + { + jtag_add_statemove(xsvf_to_tap[uc]); + ui = be_to_h_u32(buf4); + jtag_add_sleep(ui); + jtag_add_statemove(xsvf_to_tap[uc2]); + } + break; + default: + ERROR("unknown xsvf command (0x%2.2x)\n", c); + unsupported = 1; + } + + if (do_abort || unsupported || tdo_mismatch) + break; + } + + if (tdo_mismatch) + { + command_print(cmd_ctx, "TDO mismatch, aborting"); + return ERROR_OK; + } + + if (unsupported) + { + command_print(cmd_ctx, "unsupported xsvf command encountered, aborting"); + return ERROR_OK; + } + + if (do_abort) + { + command_print(cmd_ctx, "premature end detected, aborting"); + return ERROR_OK; + } + + if (dr_out_buf) + free(dr_out_buf); + + if (dr_in_buf) + free(dr_in_buf); + + if (dr_in_mask) + free(dr_in_mask); + + close(xsvf_fd); + + command_print(cmd_ctx, "XSVF file programmed successfully"); + + return ERROR_OK; +} |