- native win32 now handles WSAECONNRESET - no longer exits openocd - qCRC packet now works correctly under cygwin (gdb compare-sections command) - removed __USE_GNU define from gdbserver.c - gdb qSupported packet is now handled, with this we are able to tell gdb packet size, memory map of target - added new target script gdb_program_config - called before gdb flash programming - new gdb server command gdb_memory_map (enable|disable> - default is disable - new gdb server command gdb_flash_program (enable|disable> - default is disable - gdb flash programming supported - vFlash packets - image_elf_read_section now does not clear any remaining data, this was causing the gdb checksum to fail with certain files - reformat of usbprog.c - memory leak in command_print fixed - updated texi doc to include new commands - added gdb programming section to docs git-svn-id: svn://svn.berlios.de/openocd/trunk@246 b42882b7-edfa-0310-969c-e2dbd0fdcd60tags/v0.1.0
@@ -1,3 +1,4 @@ | |||
AC_PREREQ(2.59) | |||
AC_INIT(configure.in) | |||
AC_SEARCH_LIBS([ioperm], [ioperm]) | |||
@@ -30,6 +30,7 @@ This is edition @value{EDITION} of the openocd manual for version | |||
* Configuration:: Openocd Configuration. | |||
* Commands:: Openocd Commands | |||
* Sample Scripts:: Sample Target Scripts | |||
* GDB and Openocd:: Using GDB and Openocd | |||
* FAQ:: Frequently Asked Questions | |||
* License:: GNU Free Documentation License | |||
* Index:: Main index. | |||
@@ -194,6 +195,22 @@ Port on which to listen for incoming telnet connections | |||
@cindex gdb_port | |||
First port on which to listen for incoming GDB connections. The GDB port for the | |||
first target will be gdb_port, the second target will listen on gdb_port + 1, and so on. | |||
@item @b{gdb_detach} <@var{resume|reset|halt|nothing}> | |||
@cindex gdb_detach | |||
Configures what openocd will do when gdb detaches from the daeman. | |||
Default behaviour is <@var{resume}> | |||
@item @b{gdb_memory_map} <@var{enable|disable}> | |||
@cindex gdb_memory_map | |||
Set to <@var{enable}> so that openocd will send the memory configuration to gdb when | |||
requested. gdb will then know when to set hardware breakpoints, and program flash | |||
using the gdb load command. @option{gdb_flash_program enable} will also need enabling | |||
for flash programming to work. | |||
Default behaviour is <@var{disable}> | |||
@item @b{gdb_flash_program} <@var{enable|disable}> | |||
@cindex gdb_flash_program | |||
Set to <@var{enable}> so that openocd will program the flash memory when a | |||
vFlash packet is received. | |||
Default behaviour is <@var{disable}> | |||
@item @b{daemon_startup} <@var{mode}> either @samp{attach} or @samp{reset} | |||
@cindex daemon_startup | |||
Tells the OpenOCD whether it should reset the target when the daemon is launched, or | |||
@@ -441,8 +458,9 @@ unavailable for some time during startup (like the STR7 series), you can't use | |||
@item @b{target_script} <@var{target#}> <@var{event}> <@var{script_file}> | |||
@cindex target_script | |||
Event is either @var{reset} or @var{post_halt} or @var{pre_resume}. | |||
TODO: describe exact semantic of events | |||
Event is either @option{reset}, @option{post_halt}, @option{pre_resume} or @option{gdb_program_config} | |||
TODO: describe exact semantic of events | |||
@item @b{run_and_halt_time} <@var{target#}> <@var{time_in_ms}> | |||
@cindex run_and_halt_time | |||
The amount of time the debugger should wait after releasing reset before it asserts | |||
@@ -866,8 +884,8 @@ mass erase flash memory. | |||
@end itemize | |||
@page | |||
@section Arcitecture Specific Commands | |||
@cindex Arcitecture Specific Commands | |||
@section Architecture Specific Commands | |||
@cindex Architecture Specific Commands | |||
@subsection ARMV4/5 specific commands | |||
@cindex ARMV4/5 specific commands | |||
@@ -1014,7 +1032,7 @@ This page will collect some script examples for different CPUs. | |||
The configuration script can be divided in the following section: | |||
@itemize @bullet | |||
@item deamon configuration | |||
@item daemon configuration | |||
@item interface | |||
@item jtag scan chain | |||
@item target configuration | |||
@@ -1025,9 +1043,9 @@ Detailed information about each section can be found at OpenOCD configuration | |||
@section OMAP5912 Flash Debug | |||
@cindex OMAP5912 Flash Debug | |||
The following two scripts was used with an wiggler PP and and a TI OMAP5912 | |||
dual core processor (@uref{http://www.ti.com}) on a OMAP5912 OSK board | |||
(@uref{http://www.spectrumdigital.com}). | |||
The following two scripts were used with a wiggler PP and and a TI OMAP5912 | |||
dual core processor - (@uref{http://www.ti.com}), on a OMAP5912 OSK board | |||
- (@uref{http://www.spectrumdigital.com}). | |||
@subsection Openocd config | |||
@smallexample | |||
#daemon configuration | |||
@@ -1280,7 +1298,7 @@ run_and_halt_time 0 30 | |||
working_area 0 0x20000000 16384 nobackup | |||
#flash bank <driver> <base> <size> <chip_width> <bus_width> | |||
flash bank stm32x 0x08000000 0x00010000 0 0 0 | |||
flash bank stm32x 0x08000000 0x00020000 0 0 0 | |||
@end smallexample | |||
@section STM32x Performance Stick | |||
@@ -1320,7 +1338,7 @@ run_and_halt_time 0 30 | |||
working_area 0 0x20000000 16384 nobackup | |||
#flash bank <driver> <base> <size> <chip_width> <bus_width> | |||
flash bank stm32x 0x08000000 0x00010000 0 0 0 | |||
flash bank stm32x 0x08000000 0x00020000 0 0 0 | |||
@end smallexample | |||
@section LPC2129 Script | |||
@@ -1673,6 +1691,71 @@ run_and_halt_time 0 30 | |||
flash bank cfi 0x00000000 0x1000000 2 4 0 | |||
@end smallexample | |||
@node GDB and Openocd | |||
@chapter GDB and Openocd | |||
@cindex GDB and Openocd | |||
Openocd complies with the remote gdbserver protocol, and as such can be used | |||
to debug remote targets. | |||
@section Connecting to gdb | |||
@cindex Connecting to gdb | |||
A connection is typically started as follows: | |||
@smallexample | |||
target remote localhost:3333 | |||
@end smallexample | |||
This would cause gdb to connect to the gdbserver on the local pc using port 3333. | |||
To see a list of available openocd commands type @option{monitor help} on the | |||
gdb commandline. | |||
Openocd supports the gdb @option{qSupported} packet, this enables information | |||
to be sent by the gdb server (openocd) to gdb. Typical information includes | |||
packet size and device memory map. | |||
Previous versions of openocd required the following gdb options to increase | |||
the packet size and speed up gdb communication. | |||
@smallexample | |||
set remote memory-write-packet-size 1024 | |||
set remote memory-write-packet-size fixed | |||
set remote memory-read-packet-size 1024 | |||
set remote memory-read-packet-size fixed | |||
@end smallexample | |||
This is now handled in the @option{qSupported} PacketSize. | |||
@section Programming using gdb | |||
@cindex Programming using gdb | |||
By default the target memory map is not sent to gdb, this can be enabled by | |||
the following openocd config option: | |||
@smallexample | |||
gdb_memory_map enable | |||
@end smallexample | |||
For this to function correctly a valid flash config must also be configured | |||
in openocd. For speed also configure a valid working area. | |||
Informing gdb of the memory map of the target will enable gdb to protect any | |||
flash area of the target and use hardware breakpoints by default. This means | |||
that the openocd option @option{arm7_9 force_hw_bkpts} is not required when | |||
using a memory map. | |||
To view the configured memory map in gdb, use the gdb command @option{info mem} | |||
All other unasigned addresses within gdb are treated as ram. | |||
If @option{gdb_flash_program enable} is also used, gdb will be able to | |||
program any flash memory using the vFlash interface. | |||
gdb will look at the target memory map when a load command is given, if any | |||
areas to be programmed lie within the target flash area the vFlash packets | |||
will be used. | |||
Incase the target needs configuring before gdb programming, a script can be executed. | |||
@smallexample | |||
target_script 0 gdb_program_config config.script | |||
@end smallexample | |||
To verify any flash programming the gdb command @option{compare-sections} | |||
can be used. | |||
@node FAQ | |||
@chapter FAQ | |||
@cindex faq | |||
@@ -393,6 +393,9 @@ int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char * | |||
return ERROR_INVALID_ARGUMENTS; | |||
} | |||
/* We can't know if we did a resume + halt, in which case we no longer know the erased state */ | |||
flash_set_dirty(); | |||
duration_start_measure(&duration); | |||
if ((retval = flash_erase(target, address, length)) != ERROR_OK) | |||
@@ -766,6 +769,21 @@ int handle_flash_write_binary_command(struct command_context_s *cmd_ctx, char *c | |||
return ERROR_OK; | |||
} | |||
void flash_set_dirty(void) | |||
{ | |||
flash_bank_t *c; | |||
int i; | |||
/* set all flash to require erasing */ | |||
for (c = flash_banks; c; c = c->next) | |||
{ | |||
for (i = 0; i < c->num_sectors; i++) | |||
{ | |||
c->sectors[i].is_erased = 0; | |||
} | |||
} | |||
} | |||
/* lookup flash bank by address */ | |||
flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr) | |||
{ | |||
@@ -852,14 +870,8 @@ int flash_write(target_t *target, image_t *image, u32 *written, char **error_str | |||
{ | |||
/* assume all sectors need erasing - stops any problems | |||
* when flash_write is called multiple times */ | |||
for (c = flash_banks; c; c = c->next) | |||
{ | |||
for (i = 0; i < c->num_sectors; i++) | |||
{ | |||
c->sectors[i].is_erased = 0; | |||
} | |||
} | |||
flash_set_dirty(); | |||
} | |||
/* loop until we reach end of the image */ | |||
@@ -68,6 +68,7 @@ extern int flash_init(struct command_context_s *cmd_ctx); | |||
extern int flash_erase(target_t *target, u32 addr, u32 length); | |||
extern int flash_write(target_t *target, image_t *image, u32 *written, char **error, int *failed, int erase); | |||
extern void flash_set_dirty(void); | |||
extern flash_bank_t *get_flash_bank_by_num(int num); | |||
extern flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr); | |||
@@ -200,25 +200,24 @@ int parse_line(char *line, char *words[], int max_words) | |||
/* 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; | |||
} | |||
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; | |||
@@ -226,9 +225,9 @@ int parse_line(char *line, char *words[], int max_words) | |||
/* skip over trailing quote or whitespace*/ | |||
if (inquote || isspace(*p)) | |||
p++; | |||
while (isspace(*p)) | |||
p++; | |||
while (isspace(*p)) | |||
p++; | |||
inquote = 0; | |||
word_start = 0; | |||
} | |||
@@ -267,14 +266,23 @@ void command_print(command_context_t *context, char *format, ...) | |||
{ | |||
/* increase buffer until it fits the whole string */ | |||
if (!(p = realloc(buffer, size += 4096))) | |||
{ | |||
/* gotta free up */ | |||
if (buffer) | |||
free(buffer); | |||
return; | |||
} | |||
buffer = p; | |||
} | |||
/* vsnprintf failed */ | |||
if (n < 0) | |||
{ | |||
if (buffer) | |||
free(buffer); | |||
return; | |||
} | |||
p = buffer; | |||
@@ -1,14 +1,14 @@ | |||
/*************************************************************************** | |||
* 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 * | |||
* 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 * | |||
@@ -42,7 +42,7 @@ | |||
#define VID 0x1781 | |||
#define PID 0x0c63 | |||
// Pins at usbprog | |||
/* Pins at usbprog */ | |||
#define TDO_BIT 0 | |||
#define TDI_BIT 3 | |||
#define TCK_BIT 2 | |||
@@ -54,7 +54,6 @@ 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); | |||
@@ -96,7 +95,6 @@ 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); | |||
@@ -126,111 +124,110 @@ 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: | |||
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); | |||
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: | |||
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); | |||
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: | |||
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); | |||
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: | |||
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); | |||
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: | |||
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]); | |||
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: | |||
usbprog_path_move(cmd->cmd.pathmove); | |||
break; | |||
case JTAG_SCAN: | |||
#ifdef _DEBUG_JTAG_IO_ | |||
DEBUG("scan end in %i", cmd->cmd.scan->end_state); | |||
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: | |||
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); | |||
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; | |||
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){ | |||
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; | |||
} | |||
@@ -246,200 +243,194 @@ void usbprog_end_state(enum tap_state state) | |||
} | |||
} | |||
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; | |||
} | |||
void usbprog_state_move(void) | |||
{ | |||
int i = 0, tms = 0; | |||
u8 tms_scan = TAP_MOVE(cur_state, end_state); | |||
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]) | |||
{ | |||
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]) | |||
{ | |||
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; | |||
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; | |||
enum tap_state saved_end_state = end_state; | |||
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) | |||
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 { | |||
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 */ | |||
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(); | |||
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; | |||
int bit_cnt; | |||
if (ir_scan) | |||
usbprog_end_state(TAP_SI); | |||
else | |||
usbprog_end_state(TAP_SD); | |||
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_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(); | |||
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); | |||
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); | |||
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 usb_bus *busses; | |||
struct usbprog_jtag* usbprog_jtag_open() | |||
{ | |||
struct usb_dev_handle* usb_handle; | |||
struct usb_bus *bus; | |||
struct usb_device *dev; | |||
struct usbprog_jtag * tmp; | |||
struct usbprog_jtag *tmp; | |||
tmp = (struct usbprog_jtag*)malloc(sizeof(struct usbprog_jtag)); | |||
usb_set_debug(10); | |||
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){ | |||
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) { | |||
if (dev->descriptor.idVendor == VID && dev->descriptor.idProduct == PID) | |||
{ | |||
tmp->usb_handle = usb_open(dev); | |||
usb_set_configuration (tmp->usb_handle,1); | |||
usb_set_configuration(tmp->usb_handle, 1); | |||
usb_claim_interface(tmp->usb_handle, 0); | |||
usb_set_altinterface(tmp->usb_handle,0); | |||
usb_set_altinterface(tmp->usb_handle, 0); | |||
return tmp; | |||
} | |||
} | |||
@@ -447,22 +438,22 @@ usb_set_debug(10); | |||
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) | |||
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) { | |||
if (res == msglen) | |||
{ | |||
//INFO("HALLLLOOO %i",(int)msg[0]); | |||
res = usb_bulk_read(usbprog_jtag->usb_handle,0x82, msg, 2, 100); | |||
res = usb_bulk_read(usbprog_jtag->usb_handle, 0x82, msg, 2, 100); | |||
if (res > 0) | |||
return (unsigned char)msg[1]; | |||
else | |||
@@ -478,92 +469,103 @@ 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,j,complete=size,loops; | |||
int send_bits, bufindex = 0, fillindex = 0, i, loops; | |||
char swap; | |||
// 61 byte can be transfered (488 bit) | |||
while(size > 0) { | |||
if(size > 488) { | |||
while (size > 0) | |||
{ | |||
if (size > 488) | |||
{ | |||
send_bits = 488; | |||
size = size - 488; | |||
loops = 61; | |||
} else { | |||
} | |||
else | |||
{ | |||
send_bits = size; | |||
loops = size/8; | |||
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]; | |||
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) | |||
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){ | |||
int timeout = 0; | |||
while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 1000) < 1) | |||
{ | |||
timeout++; | |||
if(timeout>10) | |||
if (timeout > 10) | |||
break; | |||
} | |||
for(i=0;i<loops ;i++) { | |||
swap = tmp[3+i]; | |||
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,bufindex=0,fillindex=0,i,j,complete=size,loops; | |||
int send_bits, fillindex = 0, i, loops; | |||
char swap; | |||
// 61 byte can be transfered (488 bit) | |||
while(size > 0) { | |||
if(size > 488) { | |||
while (size > 0) | |||
{ | |||
if (size > 488) | |||
{ | |||
send_bits = 488; | |||
size = size - 488; | |||
loops = 61; | |||
} else { | |||
} | |||
else | |||
{ | |||
send_bits = size; | |||
loops = size/8; | |||
loops = size / 8; | |||
loops++; | |||
size = 0; | |||
} | |||
tmp[0] = WRITE_AND_READ; | |||
tmp[1] = (char)(send_bits>>8); // high | |||
tmp[2] = (char)(send_bits); // low | |||
tmp[1] = (char)(send_bits >> 8); // high | |||
tmp[2] = (char)(send_bits); // low | |||
usb_bulk_write(usbprog_jtag->usb_handle,3,tmp,3,1000); | |||
usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 3, 1000); | |||
//INFO("HALLLLOOO3 %i",(int)tmp[0]); | |||
int timeout=0; | |||
int timeout = 0; | |||
usleep(1); | |||
while(usb_bulk_read(usbprog_jtag->usb_handle,0x82, tmp, 64, 10) < 1){ | |||
while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 10) < 1) | |||
{ | |||
timeout++; | |||
if(timeout>10) | |||
if (timeout > 10) | |||
break; | |||
} | |||
for(i=0;i<loops ;i++) { | |||
swap = tmp[3+i]; | |||
for (i = 0; i < loops; i++) | |||
{ | |||
swap = tmp[3 + i]; | |||
buffer[fillindex++] = swap; | |||
} | |||
} | |||
@@ -572,15 +574,19 @@ void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char * buffer, int | |||
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,fillindex=0,i,j,complete=size,loops; | |||
char swap; | |||
int send_bits, bufindex = 0, i, loops; | |||
// 61 byte can be transfered (488 bit) | |||
while(size > 0) { | |||
if(size > 488) { | |||
while (size > 0) | |||
{ | |||
if (size > 488) | |||
{ | |||
send_bits = 488; | |||
size = size - 488; | |||
loops = 61; | |||
} else { | |||
} | |||
else | |||
{ | |||
send_bits = size; | |||
loops = size/8; | |||
//if(loops==0) | |||
@@ -588,31 +594,30 @@ void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char * buffer, in | |||
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]; | |||
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); | |||
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); | |||
usbprog_jtag_message(usbprog_jtag, tmp, 2); | |||
} | |||
void usbprog_jtag_write_slice(struct usbprog_jtag *usbprog_jtag,unsigned char value) | |||
@@ -620,7 +625,7 @@ void usbprog_jtag_write_slice(struct usbprog_jtag *usbprog_jtag,unsigned char va | |||
char tmp[2]; | |||
tmp[0] = PORT_SET; | |||
tmp[1] = (char)value; | |||
usbprog_jtag_message(usbprog_jtag,tmp,2); | |||
usbprog_jtag_message(usbprog_jtag, tmp, 2); | |||
} | |||
unsigned char usbprog_jtag_get_port(struct usbprog_jtag *usbprog_jtag) | |||
@@ -628,20 +633,19 @@ 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); | |||
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) | |||
if (value == 1) | |||
tmp[2] = 0x01; | |||
else | |||
tmp[2] = 0x00; | |||
usbprog_jtag_message(usbprog_jtag,tmp,3); | |||
usbprog_jtag_message(usbprog_jtag, tmp, 3); | |||
} | |||
int usbprog_jtag_get_bit(struct usbprog_jtag *usbprog_jtag, int bit) | |||
@@ -649,29 +653,31 @@ 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) | |||
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; | |||
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){ | |||
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]; | |||
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; | |||
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; | |||
} | |||
} | |||
@@ -1,4 +1,4 @@ | |||
INCLUDES = -I$(top_srcdir)/src/helper -I$(top_srcdir)/src/target -I$(top_srcdir)/src/flash $(all_includes) | |||
INCLUDES = -I$(top_srcdir)/src/helper -I$(top_srcdir)/src/target -I$(top_srcdir)/src/flash -I$(top_srcdir)/src/jtag $(all_includes) | |||
METASOURCES = AUTO | |||
noinst_LIBRARIES = libserver.a | |||
noinst_HEADERS = server.h telnet_server.h gdb_server.h | |||
@@ -28,11 +28,11 @@ | |||
#include "server.h" | |||
#include "log.h" | |||
#include "binarybuffer.h" | |||
#include "jtag.h" | |||
#include "breakpoints.h" | |||
#include "flash.h" | |||
#include "target_request.h" | |||
#define __USE_GNU | |||
#include <string.h> | |||
#include <errno.h> | |||
#include <unistd.h> | |||
@@ -52,8 +52,14 @@ enum gdb_detach_mode | |||
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; | |||
int gdb_last_signal(target_t *target) | |||
{ | |||
switch (target->debug_reason) | |||
@@ -77,7 +83,10 @@ int gdb_last_signal(target_t *target) | |||
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) | |||
{ | |||
@@ -109,6 +118,8 @@ int gdb_get_char(connection_t *connection, int* next_char) | |||
break; | |||
case WSAECONNABORTED: | |||
return ERROR_SERVER_REMOTE_CLOSED; | |||
case WSAECONNRESET: | |||
return ERROR_SERVER_REMOTE_CLOSED; | |||
default: | |||
ERROR("read: %d", errno); | |||
exit(-1); | |||
@@ -130,11 +141,13 @@ int gdb_get_char(connection_t *connection, int* next_char) | |||
#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--; | |||
@@ -245,7 +258,9 @@ int gdb_get_packet(connection_t *connection, char *buffer, int *len) | |||
if ((retval = gdb_get_char(connection, &character)) != ERROR_OK) | |||
return retval; | |||
#ifdef _DEBUG_GDB_IO_ | |||
DEBUG("character: '%c'", character); | |||
#endif | |||
switch (character) | |||
{ | |||
@@ -325,9 +340,17 @@ int gdb_get_packet(connection_t *connection, char *buffer, int *len) | |||
int gdb_output(struct command_context_s *context, char* line) | |||
{ | |||
connection_t *connection = context->output_handler_priv; | |||
gdb_connection_t *gdb_connection = connection->priv; | |||
char *hex_buffer; | |||
int i, bin_size; | |||
/* check if output is enabled */ | |||
if (gdb_connection->output_disable) | |||
{ | |||
return ERROR_OK; | |||
} | |||
bin_size = strlen(line); | |||
hex_buffer = malloc(bin_size*2 + 4); | |||
@@ -345,6 +368,30 @@ int gdb_output(struct command_context_s *context, char* 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 = fopen(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; | |||
@@ -378,6 +425,9 @@ int gdb_target_callback_event_handler(struct target_s *target, enum target_event | |||
gdb_connection->frontend_state = TARGET_RUNNING; | |||
} | |||
break; | |||
case TARGET_EVENT_GDB_PROGRAM: | |||
gdb_program_handler(target, event, connection->cmd_ctx); | |||
break; | |||
default: | |||
break; | |||
} | |||
@@ -400,7 +450,8 @@ int gdb_new_connection(connection_t *connection) | |||
gdb_connection->ctrl_c = 0; | |||
gdb_connection->frontend_state = TARGET_HALTED; | |||
gdb_connection->vflash_image = NULL; | |||
gdb_connection->output_disable = 0; | |||
/* output goes through gdb connection */ | |||
command_set_output_handler(connection->cmd_ctx, gdb_output, connection); | |||
@@ -1172,10 +1223,76 @@ int gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target, | |||
return ERROR_OK; | |||
} | |||
/* print out XML and allocate more space as needed */ | |||
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; | |||
*xml = realloc(*xml, *size); | |||
if (*xml == NULL) | |||
{ | |||
*retval = 1; | |||
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_query_packet(connection_t *connection, target_t *target, char *packet, int packet_size) | |||
{ | |||
char buffer[GDB_BUFFER_SIZE]; | |||
command_context_t *cmd_ctx = connection->cmd_ctx; | |||
if (strstr(packet, "qRcmd,")) | |||
{ | |||
if (packet_size > 6) | |||
@@ -1196,13 +1313,12 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i | |||
gdb_put_packet(connection, "OK", 2); | |||
return ERROR_OK; | |||
} | |||
if (strstr(packet, "qCRC:")) | |||
else if (strstr(packet, "qCRC:")) | |||
{ | |||
if (packet_size > 5) | |||
{ | |||
int retval; | |||
u8 gdb_reply[9]; | |||
u8 gdb_reply[10]; | |||
char *separator; | |||
u32 checksum; | |||
u32 addr = 0; | |||
@@ -1219,13 +1335,13 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i | |||
return ERROR_SERVER_REMOTE_CLOSED; | |||
} | |||
len = strtoul(separator+1, NULL, 16); | |||
len = strtoul(separator + 1, NULL, 16); | |||
retval = target_checksum_memory(target, addr, len, &checksum); | |||
if (retval == ERROR_OK) | |||
{ | |||
snprintf(gdb_reply, 9, "C%2.2x", checksum); | |||
snprintf(gdb_reply, 10, "C%8.8x", checksum); | |||
gdb_put_packet(connection, gdb_reply, 9); | |||
} | |||
else | |||
@@ -1237,6 +1353,119 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i | |||
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 */ | |||
sprintf(buffer, "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-", | |||
(GDB_BUFFER_SIZE - 1), gdb_use_memory_map == 1 ? '+' : '-'); | |||
gdb_put_packet(connection, buffer, strlen(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; | |||
/* 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; | |||
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, p->size/p->num_sectors); | |||
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; | |||
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; | |||
@@ -1248,10 +1477,19 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p | |||
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') | |||
{ | |||
@@ -1274,7 +1512,17 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p | |||
ERROR("incomplete vFlashErase packet received, dropping connection"); | |||
return ERROR_SERVER_REMOTE_CLOSED; | |||
} | |||
/* disable gdb output while programming */ | |||
gdb_connection->output_disable = 1; | |||
/* 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(gdb_service->target, addr, length)) != ERROR_OK) | |||
{ | |||
@@ -1286,7 +1534,10 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p | |||
} | |||
else | |||
gdb_put_packet(connection, "OK", 2); | |||
/* reenable gdb output */ | |||
gdb_connection->output_disable = 0; | |||
return ERROR_OK; | |||
} | |||
@@ -1309,6 +1560,9 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p | |||
} | |||
length = packet_size - (parse - packet); | |||
/* disable gdb output while programming */ | |||
gdb_connection->output_disable = 1; | |||
/* create a new image if there isn't already one */ | |||
if (gdb_connection->vflash_image == NULL) | |||
{ | |||
@@ -1321,6 +1575,9 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p | |||
gdb_put_packet(connection, "OK", 2); | |||
/* reenable gdb output */ | |||
gdb_connection->output_disable = 0; | |||
return ERROR_OK; | |||
} | |||
@@ -1329,6 +1586,9 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p | |||
u32 written; | |||
char *error_str; | |||
/* disable gdb output while programming */ | |||
gdb_connection->output_disable = 1; | |||
/* process the flashing buffer */ | |||
if ((result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, &error_str, NULL, 0)) != ERROR_OK) | |||
{ | |||
@@ -1352,7 +1612,10 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p | |||
image_close(gdb_connection->vflash_image); | |||
free(gdb_connection->vflash_image); | |||
gdb_connection->vflash_image = NULL; | |||
/* reenable gdb output */ | |||
gdb_connection->output_disable = 0; | |||
return ERROR_OK; | |||
} | |||
@@ -1580,12 +1843,55 @@ int handle_gdb_detach_command(struct command_context_s *cmd_ctx, char *cmd, char | |||
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 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, ""); | |||
return ERROR_OK; | |||
} |
@@ -34,6 +34,7 @@ typedef struct gdb_connection_s | |||
int ctrl_c; | |||
enum target_state frontend_state; | |||
image_t *vflash_image; | |||
int output_disable; | |||
} gdb_connection_t; | |||
typedef struct gdb_service_s | |||
@@ -360,12 +360,12 @@ int image_elf_read_headers(image_t *image) | |||
return ERROR_FILEIO_OPERATION_FAILED; | |||
} | |||
if (strncmp((char*)elf->header->e_ident,ELFMAG,SELFMAG)!=0) | |||
if (strncmp((char*)elf->header->e_ident,ELFMAG,SELFMAG) != 0) | |||
{ | |||
ERROR("invalid ELF file, bad magic number"); | |||
return ERROR_IMAGE_FORMAT_ERROR; | |||
} | |||
if (elf->header->e_ident[EI_CLASS]!=ELFCLASS32) | |||
if (elf->header->e_ident[EI_CLASS] != ELFCLASS32) | |||
{ | |||
ERROR("invalid ELF file, only 32bits files are supported"); | |||
return ERROR_IMAGE_FORMAT_ERROR; | |||
@@ -373,28 +373,28 @@ int image_elf_read_headers(image_t *image) | |||
elf->endianness = elf->header->e_ident[EI_DATA]; | |||
if ((elf->endianness!=ELFDATA2LSB) | |||
&&(elf->endianness!=ELFDATA2MSB)) | |||
if ((elf->endianness != ELFDATA2LSB) | |||
&&(elf->endianness != ELFDATA2MSB)) | |||
{ | |||
ERROR("invalid ELF file, unknown endianess setting"); | |||
return ERROR_IMAGE_FORMAT_ERROR; | |||
} | |||
elf->segment_count = field16(elf,elf->header->e_phnum); | |||
if (elf->segment_count==0) | |||
elf->segment_count = field16(elf, elf->header->e_phnum); | |||
if (elf->segment_count == 0) | |||
{ | |||
ERROR("invalid ELF file, no program headers"); | |||
return ERROR_IMAGE_FORMAT_ERROR; | |||
} | |||
elf->segments = malloc(elf->segment_count*sizeof(Elf32_Phdr)); | |||
elf->segments = malloc(elf->segment_count * sizeof(Elf32_Phdr)); | |||
if ((retval = fileio_read(&elf->fileio, elf->segment_count*sizeof(Elf32_Phdr), (u8*)elf->segments, &read_bytes)) != ERROR_OK) | |||
if ((retval = fileio_read(&elf->fileio, elf->segment_count * sizeof(Elf32_Phdr), (u8*)elf->segments, &read_bytes)) != ERROR_OK) | |||
{ | |||
ERROR("cannot read ELF segment headers, read failed"); | |||
return retval; | |||
} | |||
if (read_bytes != elf->segment_count*sizeof(Elf32_Phdr)) | |||
if (read_bytes != elf->segment_count * sizeof(Elf32_Phdr)) | |||
{ | |||
ERROR("cannot read ELF segment headers, only partially read"); | |||
return ERROR_FILEIO_OPERATION_FAILED; | |||
@@ -411,16 +411,16 @@ int image_elf_read_headers(image_t *image) | |||
{ | |||
if ((field32(elf, elf->segments[i].p_type) == PT_LOAD) && (field32(elf, elf->segments[i].p_filesz) != 0)) | |||
{ | |||
image->sections[j].size = field32(elf,elf->segments[i].p_memsz); | |||
image->sections[j].base_address = field32(elf,elf->segments[i].p_paddr); | |||
image->sections[j].size = field32(elf, elf->segments[i].p_memsz); | |||
image->sections[j].base_address = field32(elf, elf->segments[i].p_paddr); | |||
image->sections[j].private = &elf->segments[i]; | |||
image->sections[j].flags = field32(elf,elf->segments[i].p_flags); | |||
image->sections[j].flags = field32(elf, elf->segments[i].p_flags); | |||
j++; | |||
} | |||
} | |||
image->start_address_set = 1; | |||
image->start_address = field32(elf,elf->header->e_entry); | |||
image->start_address = field32(elf, elf->header->e_entry); | |||
return ERROR_OK; | |||
} | |||
@@ -442,9 +442,9 @@ int image_elf_read_section(image_t *image, int section, u32 offset, u32 size, u8 | |||
/* maximal size present in file for the current segment */ | |||
read_size = MIN(size, field32(elf, segment->p_filesz) - offset); | |||
DEBUG("read elf: size = 0x%x at 0x%x", read_size, | |||
field32(elf,segment->p_offset) + offset); | |||
field32(elf, segment->p_offset) + offset); | |||
/* read initialized area of the segment */ | |||
if ((retval = fileio_seek(&elf->fileio, field32(elf,segment->p_offset) + offset)) != ERROR_OK) | |||
if ((retval = fileio_seek(&elf->fileio, field32(elf, segment->p_offset) + offset)) != ERROR_OK) | |||
{ | |||
ERROR("cannot find ELF segment content, seek failed"); | |||
return retval; | |||
@@ -462,16 +462,7 @@ int image_elf_read_section(image_t *image, int section, u32 offset, u32 size, u8 | |||
if (!size) | |||
return ERROR_OK; | |||
} | |||
/* if there is remaining zeroed area in current segment */ | |||
if (offset < field32(elf, segment->p_memsz)) | |||
{ | |||
/* fill zeroed part (BSS) of the segment */ | |||
read_size = MIN(size, field32(elf, segment->p_memsz) - offset); | |||
DEBUG("zero fill: size = 0x%x", read_size); | |||
memset(buffer, 0, read_size); | |||
*size_read += read_size; | |||
} | |||
return ERROR_OK; | |||
} | |||
@@ -1040,6 +1040,7 @@ int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **a | |||
(*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; | |||
@@ -1120,6 +1121,12 @@ int handle_target_script_command(struct command_context_s *cmd_ctx, char *cmd, c | |||
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]); | |||
@@ -157,6 +157,7 @@ typedef struct target_s | |||
char *reset_script; /* script file to initialize the target after a reset */ | |||
char *post_halt_script; /* script file to execute after the target halted */ | |||
char *pre_resume_script; /* script file to execute before the target resumed */ | |||
char *gdb_program_script; /* script file to execute before programming vis gdb */ | |||
u32 working_area; /* working area (initialized RAM) */ | |||
u32 working_area_size; /* size in bytes */ | |||
u32 backup_working_area; /* whether the content of the working area has to be preserved */ | |||
@@ -180,6 +181,7 @@ enum target_event | |||
TARGET_EVENT_RESET, /* target entered reset */ | |||
TARGET_EVENT_DEBUG_HALTED, /* target entered debug state, but was executing on behalf of the debugger */ | |||
TARGET_EVENT_DEBUG_RESUMED, /* target resumed to execute on behalf of the debugger */ | |||
TARGET_EVENT_GDB_PROGRAM /* target about to be be programmed by gdb */ | |||
}; | |||
typedef struct target_event_callback_s | |||