- minimum autoconf 2.59 is now required and verified - due to issues with AS_HELP_STRING

- 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-e2dbd0fdcd60
__archive__
ntfreak 2007-12-29 13:51:48 +00:00
parent 2ec5bd2864
commit 6c9b804d61
12 changed files with 791 additions and 373 deletions

View File

@ -1,3 +1,4 @@
AC_PREREQ(2.59)
AC_INIT(configure.in) AC_INIT(configure.in)
AC_SEARCH_LIBS([ioperm], [ioperm]) AC_SEARCH_LIBS([ioperm], [ioperm])

View File

@ -30,6 +30,7 @@ This is edition @value{EDITION} of the openocd manual for version
* Configuration:: Openocd Configuration. * Configuration:: Openocd Configuration.
* Commands:: Openocd Commands * Commands:: Openocd Commands
* Sample Scripts:: Sample Target Scripts * Sample Scripts:: Sample Target Scripts
* GDB and Openocd:: Using GDB and Openocd
* FAQ:: Frequently Asked Questions * FAQ:: Frequently Asked Questions
* License:: GNU Free Documentation License * License:: GNU Free Documentation License
* Index:: Main index. * Index:: Main index.
@ -194,6 +195,22 @@ Port on which to listen for incoming telnet connections
@cindex gdb_port @cindex gdb_port
First port on which to listen for incoming GDB connections. The GDB port for the 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. 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} @item @b{daemon_startup} <@var{mode}> either @samp{attach} or @samp{reset}
@cindex daemon_startup @cindex daemon_startup
Tells the OpenOCD whether it should reset the target when the daemon is launched, or 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}> @item @b{target_script} <@var{target#}> <@var{event}> <@var{script_file}>
@cindex target_script @cindex target_script
Event is either @var{reset} or @var{post_halt} or @var{pre_resume}. Event is either @option{reset}, @option{post_halt}, @option{pre_resume} or @option{gdb_program_config}
TODO: describe exact semantic of events
TODO: describe exact semantic of events
@item @b{run_and_halt_time} <@var{target#}> <@var{time_in_ms}> @item @b{run_and_halt_time} <@var{target#}> <@var{time_in_ms}>
@cindex run_and_halt_time @cindex run_and_halt_time
The amount of time the debugger should wait after releasing reset before it asserts The amount of time the debugger should wait after releasing reset before it asserts
@ -866,8 +884,8 @@ mass erase flash memory.
@end itemize @end itemize
@page @page
@section Arcitecture Specific Commands @section Architecture Specific Commands
@cindex Arcitecture Specific Commands @cindex Architecture Specific Commands
@subsection ARMV4/5 specific commands @subsection ARMV4/5 specific commands
@cindex 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: The configuration script can be divided in the following section:
@itemize @bullet @itemize @bullet
@item deamon configuration @item daemon configuration
@item interface @item interface
@item jtag scan chain @item jtag scan chain
@item target configuration @item target configuration
@ -1025,9 +1043,9 @@ Detailed information about each section can be found at OpenOCD configuration
@section OMAP5912 Flash Debug @section OMAP5912 Flash Debug
@cindex OMAP5912 Flash Debug @cindex OMAP5912 Flash Debug
The following two scripts was used with an wiggler PP and and a TI OMAP5912 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 dual core processor - (@uref{http://www.ti.com}), on a OMAP5912 OSK board
(@uref{http://www.spectrumdigital.com}). - (@uref{http://www.spectrumdigital.com}).
@subsection Openocd config @subsection Openocd config
@smallexample @smallexample
#daemon configuration #daemon configuration
@ -1280,7 +1298,7 @@ run_and_halt_time 0 30
working_area 0 0x20000000 16384 nobackup working_area 0 0x20000000 16384 nobackup
#flash bank <driver> <base> <size> <chip_width> <bus_width> #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 @end smallexample
@section STM32x Performance Stick @section STM32x Performance Stick
@ -1320,7 +1338,7 @@ run_and_halt_time 0 30
working_area 0 0x20000000 16384 nobackup working_area 0 0x20000000 16384 nobackup
#flash bank <driver> <base> <size> <chip_width> <bus_width> #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 @end smallexample
@section LPC2129 Script @section LPC2129 Script
@ -1673,6 +1691,71 @@ run_and_halt_time 0 30
flash bank cfi 0x00000000 0x1000000 2 4 0 flash bank cfi 0x00000000 0x1000000 2 4 0
@end smallexample @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 @node FAQ
@chapter FAQ @chapter FAQ
@cindex faq @cindex faq

View File

@ -393,6 +393,9 @@ int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *
return ERROR_INVALID_ARGUMENTS; 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); duration_start_measure(&duration);
if ((retval = flash_erase(target, address, length)) != ERROR_OK) 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; 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 */ /* lookup flash bank by address */
flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr) 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 /* assume all sectors need erasing - stops any problems
* when flash_write is called multiple times */ * when flash_write is called multiple times */
for (c = flash_banks; c; c = c->next) flash_set_dirty();
{
for (i = 0; i < c->num_sectors; i++)
{
c->sectors[i].is_erased = 0;
}
}
} }
/* loop until we reach end of the image */ /* loop until we reach end of the image */

View File

@ -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_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 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_num(int num);
extern flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr); extern flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr);

View File

@ -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*/ /* we're inside a word or quote, and reached its end*/
if (word_start) if (word_start)
{ {
int len; int len;
char *word_end=p; char *word_end=p;
/* This will handle extra whitespace within quotes */
while (isspace(*word_start)&&(word_start<word_end)) /* This will handle extra whitespace within quotes */
word_start++; while (isspace(*word_start)&&(word_start<word_end))
while (isspace(*(word_end-1))&&(word_start<word_end)) word_start++;
word_end--; while (isspace(*(word_end-1))&&(word_start<word_end))
word_end--;
len = word_end - word_start; len = word_end - word_start;
if (len>0) if (len>0)
{ {
/* copy the word */ /* copy the word */
memcpy(words[nwords] = malloc(len + 1), word_start, len); memcpy(words[nwords] = malloc(len + 1), word_start, len);
/* add terminating NUL */ /* add terminating NUL */
words[nwords++][len] = 0; words[nwords++][len] = 0;
} }
} }
/* we're done parsing the line */ /* we're done parsing the line */
if (!*p) if (!*p)
break; break;
@ -226,9 +225,9 @@ int parse_line(char *line, char *words[], int max_words)
/* skip over trailing quote or whitespace*/ /* skip over trailing quote or whitespace*/
if (inquote || isspace(*p)) if (inquote || isspace(*p))
p++; p++;
while (isspace(*p)) while (isspace(*p))
p++; p++;
inquote = 0; inquote = 0;
word_start = 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 */ /* increase buffer until it fits the whole string */
if (!(p = realloc(buffer, size += 4096))) if (!(p = realloc(buffer, size += 4096)))
{
/* gotta free up */
if (buffer)
free(buffer);
return; return;
}
buffer = p; buffer = p;
} }
/* vsnprintf failed */ /* vsnprintf failed */
if (n < 0) if (n < 0)
{
if (buffer)
free(buffer);
return; return;
}
p = buffer; p = buffer;

View File

@ -1,14 +1,14 @@
/*************************************************************************** /***************************************************************************
* Copyright (C) 2007 by Benedikt Sauter sauter@ixbat.de * * Copyright (C) 2007 by Benedikt Sauter sauter@ixbat.de *
* based on Dominic Rath's amt_jtagaccel.c * * based on Dominic Rath's amt_jtagaccel.c *
* * * *
* usbprog is a free programming adapter. You can easily install * * usbprog is a free programming adapter. You can easily install *
* different firmware versions from an "online pool" over USB. * * different firmware versions from an "online pool" over USB. *
* The adapter can be used for programming and debugging AVR and ARM * * The adapter can be used for programming and debugging AVR and ARM *
* processors, as USB to RS232 converter, as JTAG interface or as * * processors, as USB to RS232 converter, as JTAG interface or as *
* simple I/O interface (5 lines). * * simple I/O interface (5 lines). *
* * * *
* http://www.embedded-projects.net/usbprog * * http://www.embedded-projects.net/usbprog *
* * * *
* This program is free software; you can redistribute it and/or modify * * 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 * * it under the terms of the GNU General Public License as published by *
@ -42,7 +42,7 @@
#define VID 0x1781 #define VID 0x1781
#define PID 0x0c63 #define PID 0x0c63
// Pins at usbprog /* Pins at usbprog */
#define TDO_BIT 0 #define TDO_BIT 0
#define TDI_BIT 3 #define TDI_BIT 3
#define TCK_BIT 2 #define TCK_BIT 2
@ -54,7 +54,6 @@ int usbprog_register_commands(struct command_context_s *cmd_ctx);
int usbprog_init(void); int usbprog_init(void);
int usbprog_quit(void); int usbprog_quit(void);
void usbprog_end_state(enum tap_state state); void usbprog_end_state(enum tap_state state);
void usbprog_state_move(void); void usbprog_state_move(void);
void usbprog_path_move(pathmove_command_t *cmd); 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); void usbprog_jtag_init(struct usbprog_jtag *usbprog_jtag);
unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen); 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_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_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_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; return ERROR_OK;
} }
int usbprog_execute_queue(void) int usbprog_execute_queue(void)
{ {
jtag_command_t *cmd = jtag_command_queue; /* currently processed command */ jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
int scan_size; int scan_size;
enum scan_type type; enum scan_type type;
u8 *buffer; u8 *buffer;
while (cmd) while (cmd)
{ {
switch (cmd->type) switch (cmd->type)
{ {
case JTAG_END_STATE: case JTAG_END_STATE:
#ifdef _DEBUG_JTAG_IO_ #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 #endif
if (cmd->cmd.end_state->end_state != -1) if (cmd->cmd.end_state->end_state != -1)
usbprog_end_state(cmd->cmd.end_state->end_state); usbprog_end_state(cmd->cmd.end_state->end_state);
break; break;
case JTAG_RESET: case JTAG_RESET:
#ifdef _DEBUG_JTAG_IO_ #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 #endif
if (cmd->cmd.reset->trst == 1) if (cmd->cmd.reset->trst == 1)
{ {
cur_state = TAP_TLR; cur_state = TAP_TLR;
} }
usbprog_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); usbprog_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
break; break;
case JTAG_RUNTEST: case JTAG_RUNTEST:
#ifdef _DEBUG_JTAG_IO_ #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 #endif
if (cmd->cmd.runtest->end_state != -1) if (cmd->cmd.runtest->end_state != -1)
usbprog_end_state(cmd->cmd.runtest->end_state); usbprog_end_state(cmd->cmd.runtest->end_state);
usbprog_runtest(cmd->cmd.runtest->num_cycles); usbprog_runtest(cmd->cmd.runtest->num_cycles);
break; break;
case JTAG_STATEMOVE: case JTAG_STATEMOVE:
#ifdef _DEBUG_JTAG_IO_ #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 #endif
if (cmd->cmd.statemove->end_state != -1) if (cmd->cmd.statemove->end_state != -1)
usbprog_end_state(cmd->cmd.statemove->end_state); usbprog_end_state(cmd->cmd.statemove->end_state);
usbprog_state_move(); usbprog_state_move();
break; break;
case JTAG_PATHMOVE: case JTAG_PATHMOVE:
#ifdef _DEBUG_JTAG_IO_ #ifdef _DEBUG_JTAG_IO_
DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states,
cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
#endif #endif
usbprog_path_move(cmd->cmd.pathmove); usbprog_path_move(cmd->cmd.pathmove);
break; break;
case JTAG_SCAN: case JTAG_SCAN:
#ifdef _DEBUG_JTAG_IO_ #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 #endif
if (cmd->cmd.scan->end_state != -1) if (cmd->cmd.scan->end_state != -1)
usbprog_end_state(cmd->cmd.scan->end_state); usbprog_end_state(cmd->cmd.scan->end_state);
scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
type = jtag_scan_type(cmd->cmd.scan); type = jtag_scan_type(cmd->cmd.scan);
usbprog_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); usbprog_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
return ERROR_JTAG_QUEUE_FAILED; return ERROR_JTAG_QUEUE_FAILED;
if (buffer) if (buffer)
free(buffer); free(buffer);
break; break;
case JTAG_SLEEP: case JTAG_SLEEP:
#ifdef _DEBUG_JTAG_IO_ #ifdef _DEBUG_JTAG_IO_
DEBUG("sleep %i", cmd->cmd.sleep->us); DEBUG("sleep %i", cmd->cmd.sleep->us);
#endif #endif
jtag_sleep(cmd->cmd.sleep->us); jtag_sleep(cmd->cmd.sleep->us);
break; break;
default: default:
ERROR("BUG: unknown JTAG command type encountered"); ERROR("BUG: unknown JTAG command type encountered");
exit(-1); exit(-1);
} }
cmd = cmd->next;
} cmd = cmd->next;
}
return ERROR_OK;
return ERROR_OK;
} }
int usbprog_init(void) int usbprog_init(void)
{ {
usbprog_jtag_handle = usbprog_jtag_open(); usbprog_jtag_handle = usbprog_jtag_open();
tms_chain_index=0; tms_chain_index = 0;
if(usbprog_jtag_handle==0){ if (usbprog_jtag_handle == 0)
{
ERROR("Can't find USB JTAG Interface! Please check connection and permissions."); ERROR("Can't find USB JTAG Interface! Please check connection and permissions.");
return ERROR_JTAG_INIT_FAILED; return ERROR_JTAG_INIT_FAILED;
} }
INFO("USB JTAG Interface ready!"); INFO("USB JTAG Interface ready!");
usbprog_jtag_init(usbprog_jtag_handle); usbprog_jtag_init(usbprog_jtag_handle);
usbprog_reset(0, 0); usbprog_reset(0, 0);
usbprog_write(0, 0, 0); usbprog_write(0, 0, 0);
return ERROR_OK; return ERROR_OK;
} }
int usbprog_quit(void) int usbprog_quit(void)
{ {
return ERROR_OK; return ERROR_OK;
} }
@ -246,200 +243,194 @@ void usbprog_end_state(enum tap_state state)
} }
} }
void usbprog_state_move(void)
void usbprog_state_move(void) { {
int i = 0, tms = 0;
int i=0, tms=0; u8 tms_scan = TAP_MOVE(cur_state, end_state);
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; 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) void usbprog_path_move(pathmove_command_t *cmd)
{ {
int num_states = cmd->num_states; int num_states = cmd->num_states;
int state_count; int state_count;
state_count = 0; state_count = 0;
while (num_states) while (num_states)
{ {
if (tap_transitions[cur_state].low == cmd->path[state_count]) if (tap_transitions[cur_state].low == cmd->path[state_count])
{ {
//INFO("1"); //INFO("1");
usbprog_write(0, 0, 0); usbprog_write(0, 0, 0);
usbprog_write(1, 0, 0); usbprog_write(1, 0, 0);
} }
else if (tap_transitions[cur_state].high == cmd->path[state_count]) else if (tap_transitions[cur_state].high == cmd->path[state_count])
{ {
//INFO("2"); //INFO("2");
usbprog_write(0, 1, 0); usbprog_write(0, 1, 0);
usbprog_write(1, 1, 0); usbprog_write(1, 1, 0);
} }
else else
{ {
ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_strings[cur_state], tap_state_strings[cmd->path[state_count]]); ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_strings[cur_state], tap_state_strings[cmd->path[state_count]]);
exit(-1); exit(-1);
} }
cur_state = cmd->path[state_count]; cur_state = cmd->path[state_count];
state_count++; state_count++;
num_states--; num_states--;
} }
end_state = cur_state; end_state = cur_state;
} }
void usbprog_runtest(int num_cycles) void usbprog_runtest(int num_cycles)
{ {
int i; int i;
enum tap_state saved_end_state = end_state;
/* only do a state_move when we're not already in RTI */ /* only do a state_move when we're not already in RTI */
if (cur_state != TAP_RTI) if (cur_state != TAP_RTI)
{ {
usbprog_end_state(TAP_RTI); usbprog_end_state(TAP_RTI);
usbprog_state_move(); usbprog_state_move();
} }
/* execute num_cycles */ /* execute num_cycles */
if(num_cycles>0) if (num_cycles > 0)
{ {
usbprog_jtag_tms_send(usbprog_jtag_handle); usbprog_jtag_tms_send(usbprog_jtag_handle);
usbprog_write(0, 0, 0); usbprog_write(0, 0, 0);
} }
else { else
{
usbprog_jtag_tms_send(usbprog_jtag_handle); usbprog_jtag_tms_send(usbprog_jtag_handle);
//INFO("NUM CYCLES %i",num_cycles); //INFO("NUM CYCLES %i",num_cycles);
} }
for (i = 0; i < num_cycles; i++) for (i = 0; i < num_cycles; i++)
{ {
usbprog_write(1, 0, 0); usbprog_write(1, 0, 0);
usbprog_write(0, 0, 0); usbprog_write(0, 0, 0);
} }
/* finish in end_state */ /* finish in end_state */
/* /*
usbprog_end_state(saved_end_state); usbprog_end_state(saved_end_state);
if (cur_state != end_state) if (cur_state != end_state)
usbprog_state_move(); usbprog_state_move();
*/ */
} }
void usbprog_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size) void usbprog_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
{ {
enum tap_state saved_end_state = end_state; enum tap_state saved_end_state = end_state;
int bit_cnt;
if (ir_scan)
if (ir_scan) usbprog_end_state(TAP_SI);
usbprog_end_state(TAP_SI); else
else usbprog_end_state(TAP_SD);
usbprog_end_state(TAP_SD);
//usbprog_jtag_tms_send(usbprog_jtag_handle); //usbprog_jtag_tms_send(usbprog_jtag_handle);
usbprog_state_move(); usbprog_state_move();
usbprog_end_state(saved_end_state); usbprog_end_state(saved_end_state);
usbprog_jtag_tms_send(usbprog_jtag_handle); usbprog_jtag_tms_send(usbprog_jtag_handle);
if (type == SCAN_OUT) { if (type == SCAN_OUT)
usbprog_jtag_write_tdi(usbprog_jtag_handle,buffer, scan_size); {
} 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_IN)
} {
if (type == SCAN_IO) { usbprog_jtag_read_tdo(usbprog_jtag_handle,buffer, scan_size);
usbprog_jtag_write_and_read(usbprog_jtag_handle,buffer, scan_size); }
} if (type == SCAN_IO)
{
if (ir_scan) usbprog_jtag_write_and_read(usbprog_jtag_handle,buffer, scan_size);
cur_state = TAP_PI; }
else
cur_state = TAP_PD; if (ir_scan)
cur_state = TAP_PI;
if (cur_state != end_state) else
usbprog_state_move(); cur_state = TAP_PD;
if (cur_state != end_state)
usbprog_state_move();
} }
/*************** jtag wrapper functions *********************/ /*************** jtag wrapper functions *********************/
void usbprog_write(int tck, int tms, int tdi) void usbprog_write(int tck, int tms, int tdi)
{ {
unsigned char output_value=0x00; unsigned char output_value=0x00;
if (tms) if (tms)
output_value |= (1<<TMS_BIT); output_value |= (1<<TMS_BIT);
if (tdi) if (tdi)
output_value |= (1<<TDI_BIT); output_value |= (1<<TDI_BIT);
if (tck) if (tck)
output_value |= (1<<TCK_BIT); output_value |= (1<<TCK_BIT);
usbprog_jtag_write_slice(usbprog_jtag_handle,output_value); usbprog_jtag_write_slice(usbprog_jtag_handle,output_value);
} }
/* (1) assert or (0) deassert reset lines */ /* (1) assert or (0) deassert reset lines */
void usbprog_reset(int trst, int srst) void usbprog_reset(int trst, int srst)
{ {
DEBUG("trst: %i, srst: %i", trst, srst); DEBUG("trst: %i, srst: %i", trst, srst);
if(trst) if (trst)
usbprog_jtag_set_bit(usbprog_jtag_handle,5,0); usbprog_jtag_set_bit(usbprog_jtag_handle, 5, 0);
else else
usbprog_jtag_set_bit(usbprog_jtag_handle,5,1); usbprog_jtag_set_bit(usbprog_jtag_handle, 5, 1);
if(srst) if (srst)
usbprog_jtag_set_bit(usbprog_jtag_handle,4,0); usbprog_jtag_set_bit(usbprog_jtag_handle, 4, 0);
else else
usbprog_jtag_set_bit(usbprog_jtag_handle,4,1); usbprog_jtag_set_bit(usbprog_jtag_handle, 4, 1);
} }
/*************** jtag lowlevel functions ********************/ /*************** jtag lowlevel functions ********************/
struct usb_bus *busses;
struct usb_bus *busses;
struct usbprog_jtag* usbprog_jtag_open() struct usbprog_jtag* usbprog_jtag_open()
{ {
struct usb_dev_handle* usb_handle;
struct usb_bus *bus; struct usb_bus *bus;
struct usb_device *dev; struct usb_device *dev;
struct usbprog_jtag * tmp; struct usbprog_jtag *tmp;
tmp = (struct usbprog_jtag*)malloc(sizeof(struct usbprog_jtag)); tmp = (struct usbprog_jtag*)malloc(sizeof(struct usbprog_jtag));
usb_set_debug(10); usb_set_debug(10);
usb_init(); usb_init();
usb_find_busses(); usb_find_busses();
usb_find_devices(); usb_find_devices();
busses = usb_get_busses(); busses = usb_get_busses();
/* find usbprog_jtag device in usb bus */ /* find usbprog_jtag device in usb bus */
for (bus = busses; bus; bus = bus->next){ for (bus = busses; bus; bus = bus->next)
for (dev = bus->devices; dev; dev = dev->next){ {
for (dev = bus->devices; dev; dev = dev->next)
{
/* condition for sucessfully hit (too bad, I only check the vendor id)*/ /* 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); 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_claim_interface(tmp->usb_handle, 0);
usb_set_altinterface(tmp->usb_handle,0); usb_set_altinterface(tmp->usb_handle, 0);
return tmp; return tmp;
} }
} }
@ -447,22 +438,22 @@ usb_set_debug(10);
return 0; return 0;
} }
void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag) void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag)
{ {
usb_close(usbprog_jtag->usb_handle); usb_close(usbprog_jtag->usb_handle);
free(usbprog_jtag); free(usbprog_jtag);
} }
unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen) 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); 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) if ((msg[0] == 2) || (msg[0] == 1) || (msg[0] == 4) || (msg[0] == 0) || \
(msg[0] == 6) || (msg[0] == 0x0A) || (msg[0] == 9))
return 1; return 1;
if(res == msglen) { if (res == msglen)
{
//INFO("HALLLLOOO %i",(int)msg[0]); //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) if (res > 0)
return (unsigned char)msg[1]; return (unsigned char)msg[1];
else else
@ -478,92 +469,103 @@ void usbprog_jtag_init(struct usbprog_jtag *usbprog_jtag)
usbprog_jtag_set_direction(usbprog_jtag, 0xFE); usbprog_jtag_set_direction(usbprog_jtag, 0xFE);
} }
void usbprog_jtag_write_and_read(struct usbprog_jtag *usbprog_jtag, char * buffer, int size) void usbprog_jtag_write_and_read(struct usbprog_jtag *usbprog_jtag, char * buffer, int size)
{ {
char tmp[64]; // fastes packet size for usb controller 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; char swap;
// 61 byte can be transfered (488 bit) // 61 byte can be transfered (488 bit)
while(size > 0) { while (size > 0)
if(size > 488) { {
if (size > 488)
{
send_bits = 488; send_bits = 488;
size = size - 488; size = size - 488;
loops = 61; loops = 61;
} else { }
else
{
send_bits = size; send_bits = size;
loops = size/8; loops = size / 8;
loops++; loops++;
size = 0; size = 0;
} }
tmp[0] = WRITE_AND_READ; tmp[0] = WRITE_AND_READ;
tmp[1] = (char)(send_bits>>8); // high tmp[1] = (char)(send_bits >> 8); // high
tmp[2] = (char)(send_bits); // low tmp[2] = (char)(send_bits); // low
i=0; i = 0;
for(i=0;i < loops ;i++) { for (i = 0; i < loops; i++)
tmp[3+i]=buffer[bufindex]; {
tmp[3 + i] = buffer[bufindex];
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]); //INFO("HALLLLOOO2 %i",(int)tmp[0]);
usleep(1); usleep(1);
int timeout=0; int timeout = 0;
while(usb_bulk_read(usbprog_jtag->usb_handle,0x82, tmp, 64, 1000) < 1){ while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 1000) < 1)
{
timeout++; timeout++;
if(timeout>10) if (timeout > 10)
break; break;
} }
for(i=0;i<loops ;i++) { for (i = 0; i < loops; i++)
swap = tmp[3+i]; {
swap = tmp[3 + i];
buffer[fillindex++] = swap; buffer[fillindex++] = swap;
} }
} }
} }
} }
void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char * buffer, int size) void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char * buffer, int size)
{ {
char tmp[64]; // fastes packet size for usb controller 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; char swap;
// 61 byte can be transfered (488 bit) // 61 byte can be transfered (488 bit)
while(size > 0) { while (size > 0)
if(size > 488) { {
if (size > 488)
{
send_bits = 488; send_bits = 488;
size = size - 488; size = size - 488;
loops = 61; loops = 61;
} else { }
else
{
send_bits = size; send_bits = size;
loops = size/8; loops = size / 8;
loops++; loops++;
size = 0; size = 0;
} }
tmp[0] = WRITE_AND_READ; tmp[0] = WRITE_AND_READ;
tmp[1] = (char)(send_bits>>8); // high tmp[1] = (char)(send_bits >> 8); // high
tmp[2] = (char)(send_bits); // low 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]); //INFO("HALLLLOOO3 %i",(int)tmp[0]);
int timeout=0; int timeout = 0;
usleep(1); 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++; timeout++;
if(timeout>10) if (timeout > 10)
break; break;
} }
for(i=0;i<loops ;i++) { for (i = 0; i < loops; i++)
swap = tmp[3+i]; {
swap = tmp[3 + i];
buffer[fillindex++] = swap; 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) void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char * buffer, int size)
{ {
char tmp[64]; // fastes packet size for usb controller 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, i, loops;
char swap;
// 61 byte can be transfered (488 bit) // 61 byte can be transfered (488 bit)
while(size > 0) { while (size > 0)
if(size > 488) { {
if (size > 488)
{
send_bits = 488; send_bits = 488;
size = size - 488; size = size - 488;
loops = 61; loops = 61;
} else { }
else
{
send_bits = size; send_bits = size;
loops = size/8; loops = size/8;
//if(loops==0) //if(loops==0)
@ -588,31 +594,30 @@ void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char * buffer, in
size = 0; size = 0;
} }
tmp[0] = WRITE_TDI; tmp[0] = WRITE_TDI;
tmp[1] = (char)(send_bits>>8); // high tmp[1] = (char)(send_bits >> 8); // high
tmp[2] = (char)(send_bits); // low tmp[2] = (char)(send_bits); // low
i=0; i = 0;
for(i=0;i < loops ;i++) { for (i = 0; i < loops; i++)
tmp[3+i]=buffer[bufindex]; {
tmp[3 + i] = buffer[bufindex];
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) void usbprog_jtag_write_tms(struct usbprog_jtag *usbprog_jtag, char tms_scan)
{ {
usbprog_jtag_tms_collect(tms_scan); usbprog_jtag_tms_collect(tms_scan);
} }
void usbprog_jtag_set_direction(struct usbprog_jtag *usbprog_jtag, unsigned char direction) void usbprog_jtag_set_direction(struct usbprog_jtag *usbprog_jtag, unsigned char direction)
{ {
char tmp[2]; char tmp[2];
tmp[0] = PORT_DIRECTION; tmp[0] = PORT_DIRECTION;
tmp[1] = (char)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) 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]; char tmp[2];
tmp[0] = PORT_SET; tmp[0] = PORT_SET;
tmp[1] = (char)value; 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) 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]; char tmp[2];
tmp[0] = PORT_GET; tmp[0] = PORT_GET;
tmp[1] = 0x00; 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) void usbprog_jtag_set_bit(struct usbprog_jtag *usbprog_jtag,int bit, int value)
{ {
char tmp[3]; char tmp[3];
tmp[0] = PORT_SETBIT; tmp[0] = PORT_SETBIT;
tmp[1] = (char)bit; tmp[1] = (char)bit;
if(value==1) if (value == 1)
tmp[2] = 0x01; tmp[2] = 0x01;
else else
tmp[2] = 0x00; 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) 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]; char tmp[2];
tmp[0] = PORT_GETBIT; tmp[0] = PORT_GETBIT;
tmp[1] = (char)bit; tmp[1] = (char)bit;
if(usbprog_jtag_message(usbprog_jtag,tmp,2)>0) if (usbprog_jtag_message(usbprog_jtag, tmp, 2) > 0)
return 1; return 1;
else else
return 0; return 0;
} }
void usbprog_jtag_tms_collect(char tms_scan){ void usbprog_jtag_tms_collect(char tms_scan)
tms_chain[tms_chain_index]=tms_scan; {
tms_chain[tms_chain_index] = tms_scan;
tms_chain_index++; 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; int i;
//INFO("TMS SEND"); //INFO("TMS SEND");
if(tms_chain_index>0) { if (tms_chain_index > 0)
char tmp[tms_chain_index+2]; {
char tmp[tms_chain_index + 2];
tmp[0] = WRITE_TMS_CHAIN; tmp[0] = WRITE_TMS_CHAIN;
tmp[1] = (char)(tms_chain_index); tmp[1] = (char)(tms_chain_index);
for(i=0;i<tms_chain_index+1;i++) for (i = 0; i < tms_chain_index + 1; i++)
tmp[2+i] = tms_chain[i]; tmp[2 + i] = tms_chain[i];
usb_bulk_write(usbprog_jtag->usb_handle,3,tmp,tms_chain_index+2,1000); usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, tms_chain_index + 2, 1000);
tms_chain_index=0; tms_chain_index = 0;
} }
} }

View File

@ -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 METASOURCES = AUTO
noinst_LIBRARIES = libserver.a noinst_LIBRARIES = libserver.a
noinst_HEADERS = server.h telnet_server.h gdb_server.h noinst_HEADERS = server.h telnet_server.h gdb_server.h

View File

@ -28,11 +28,11 @@
#include "server.h" #include "server.h"
#include "log.h" #include "log.h"
#include "binarybuffer.h" #include "binarybuffer.h"
#include "jtag.h"
#include "breakpoints.h" #include "breakpoints.h"
#include "flash.h" #include "flash.h"
#include "target_request.h" #include "target_request.h"
#define __USE_GNU
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
@ -52,8 +52,14 @@ enum gdb_detach_mode
GDB_DETACH_NOTHING GDB_DETACH_NOTHING
}; };
/* target behaviour on gdb detach */
enum gdb_detach_mode detach_mode = GDB_DETACH_RESUME; 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) int gdb_last_signal(target_t *target)
{ {
switch (target->debug_reason) 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) int gdb_get_char(connection_t *connection, int* next_char)
{ {
gdb_connection_t *gdb_con = connection->priv; gdb_connection_t *gdb_con = connection->priv;
#ifdef _DEBUG_GDB_IO_
char *debug_buffer; char *debug_buffer;
#endif
if (gdb_con->buf_cnt-- > 0) if (gdb_con->buf_cnt-- > 0)
{ {
@ -109,6 +118,8 @@ int gdb_get_char(connection_t *connection, int* next_char)
break; break;
case WSAECONNABORTED: case WSAECONNABORTED:
return ERROR_SERVER_REMOTE_CLOSED; return ERROR_SERVER_REMOTE_CLOSED;
case WSAECONNRESET:
return ERROR_SERVER_REMOTE_CLOSED;
default: default:
ERROR("read: %d", errno); ERROR("read: %d", errno);
exit(-1); exit(-1);
@ -130,11 +141,13 @@ int gdb_get_char(connection_t *connection, int* next_char)
#endif #endif
} }
#ifdef _DEBUG_GDB_IO_
debug_buffer = malloc(gdb_con->buf_cnt + 1); debug_buffer = malloc(gdb_con->buf_cnt + 1);
memcpy(debug_buffer, gdb_con->buffer, gdb_con->buf_cnt); memcpy(debug_buffer, gdb_con->buffer, gdb_con->buf_cnt);
debug_buffer[gdb_con->buf_cnt] = 0; debug_buffer[gdb_con->buf_cnt] = 0;
DEBUG("received '%s'", debug_buffer); DEBUG("received '%s'", debug_buffer);
free(debug_buffer); free(debug_buffer);
#endif
gdb_con->buf_p = gdb_con->buffer; gdb_con->buf_p = gdb_con->buffer;
gdb_con->buf_cnt--; 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) if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
return retval; return retval;
#ifdef _DEBUG_GDB_IO_
DEBUG("character: '%c'", character); DEBUG("character: '%c'", character);
#endif
switch (character) 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) int gdb_output(struct command_context_s *context, char* line)
{ {
connection_t *connection = context->output_handler_priv; connection_t *connection = context->output_handler_priv;
gdb_connection_t *gdb_connection = connection->priv;
char *hex_buffer; char *hex_buffer;
int i, bin_size; int i, bin_size;
/* check if output is enabled */
if (gdb_connection->output_disable)
{
return ERROR_OK;
}
bin_size = strlen(line); bin_size = strlen(line);
hex_buffer = malloc(bin_size*2 + 4); hex_buffer = malloc(bin_size*2 + 4);
@ -345,6 +368,30 @@ int gdb_output(struct command_context_s *context, char* line)
return ERROR_OK; 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) int gdb_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv)
{ {
connection_t *connection = 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; gdb_connection->frontend_state = TARGET_RUNNING;
} }
break; break;
case TARGET_EVENT_GDB_PROGRAM:
gdb_program_handler(target, event, connection->cmd_ctx);
break;
default: default:
break; break;
} }
@ -400,7 +450,8 @@ int gdb_new_connection(connection_t *connection)
gdb_connection->ctrl_c = 0; gdb_connection->ctrl_c = 0;
gdb_connection->frontend_state = TARGET_HALTED; gdb_connection->frontend_state = TARGET_HALTED;
gdb_connection->vflash_image = NULL; gdb_connection->vflash_image = NULL;
gdb_connection->output_disable = 0;
/* output goes through gdb connection */ /* output goes through gdb connection */
command_set_output_handler(connection->cmd_ctx, gdb_output, 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; 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) 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; command_context_t *cmd_ctx = connection->cmd_ctx;
if (strstr(packet, "qRcmd,")) if (strstr(packet, "qRcmd,"))
{ {
if (packet_size > 6) 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); gdb_put_packet(connection, "OK", 2);
return ERROR_OK; return ERROR_OK;
} }
else if (strstr(packet, "qCRC:"))
if (strstr(packet, "qCRC:"))
{ {
if (packet_size > 5) if (packet_size > 5)
{ {
int retval; int retval;
u8 gdb_reply[9]; u8 gdb_reply[10];
char *separator; char *separator;
u32 checksum; u32 checksum;
u32 addr = 0; 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; 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); retval = target_checksum_memory(target, addr, len, &checksum);
if (retval == ERROR_OK) 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); gdb_put_packet(connection, gdb_reply, 9);
} }
else else
@ -1237,6 +1353,119 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i
return ERROR_OK; 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); gdb_put_packet(connection, "", 0);
return ERROR_OK; 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; gdb_service_t *gdb_service = connection->service->priv;
int result; 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:")) if (strstr(packet, "vFlashErase:"))
{ {
unsigned long addr; unsigned long addr;
unsigned long length; unsigned long length;
char *parse = packet + 12; char *parse = packet + 12;
if (*parse == '\0') 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"); ERROR("incomplete vFlashErase packet received, dropping connection");
return ERROR_SERVER_REMOTE_CLOSED; 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 */ /* perform erase */
if ((result = flash_erase(gdb_service->target, addr, length)) != ERROR_OK) 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 else
gdb_put_packet(connection, "OK", 2); gdb_put_packet(connection, "OK", 2);
/* reenable gdb output */
gdb_connection->output_disable = 0;
return ERROR_OK; 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); 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 */ /* create a new image if there isn't already one */
if (gdb_connection->vflash_image == NULL) 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); gdb_put_packet(connection, "OK", 2);
/* reenable gdb output */
gdb_connection->output_disable = 0;
return ERROR_OK; return ERROR_OK;
} }
@ -1329,6 +1586,9 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p
u32 written; u32 written;
char *error_str; char *error_str;
/* disable gdb output while programming */
gdb_connection->output_disable = 1;
/* process the flashing buffer */ /* process the flashing buffer */
if ((result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, &error_str, NULL, 0)) != ERROR_OK) 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); image_close(gdb_connection->vflash_image);
free(gdb_connection->vflash_image); free(gdb_connection->vflash_image);
gdb_connection->vflash_image = NULL; gdb_connection->vflash_image = NULL;
/* reenable gdb output */
gdb_connection->output_disable = 0;
return ERROR_OK; return ERROR_OK;
} }
@ -1580,12 +1843,55 @@ int handle_gdb_detach_command(struct command_context_s *cmd_ctx, char *cmd, char
return ERROR_OK; 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) int gdb_register_commands(command_context_t *command_context)
{ {
register_command(command_context, NULL, "gdb_port", handle_gdb_port_command, register_command(command_context, NULL, "gdb_port", handle_gdb_port_command,
COMMAND_CONFIG, ""); COMMAND_CONFIG, "");
register_command(command_context, NULL, "gdb_detach", handle_gdb_detach_command, register_command(command_context, NULL, "gdb_detach", handle_gdb_detach_command,
COMMAND_CONFIG, ""); 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; return ERROR_OK;
} }

View File

@ -34,6 +34,7 @@ typedef struct gdb_connection_s
int ctrl_c; int ctrl_c;
enum target_state frontend_state; enum target_state frontend_state;
image_t *vflash_image; image_t *vflash_image;
int output_disable;
} gdb_connection_t; } gdb_connection_t;
typedef struct gdb_service_s typedef struct gdb_service_s

View File

@ -360,12 +360,12 @@ int image_elf_read_headers(image_t *image)
return ERROR_FILEIO_OPERATION_FAILED; 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"); ERROR("invalid ELF file, bad magic number");
return ERROR_IMAGE_FORMAT_ERROR; 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"); ERROR("invalid ELF file, only 32bits files are supported");
return ERROR_IMAGE_FORMAT_ERROR; 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]; elf->endianness = elf->header->e_ident[EI_DATA];
if ((elf->endianness!=ELFDATA2LSB) if ((elf->endianness != ELFDATA2LSB)
&&(elf->endianness!=ELFDATA2MSB)) &&(elf->endianness != ELFDATA2MSB))
{ {
ERROR("invalid ELF file, unknown endianess setting"); ERROR("invalid ELF file, unknown endianess setting");
return ERROR_IMAGE_FORMAT_ERROR; return ERROR_IMAGE_FORMAT_ERROR;
} }
elf->segment_count = field16(elf,elf->header->e_phnum); elf->segment_count = field16(elf, elf->header->e_phnum);
if (elf->segment_count==0) if (elf->segment_count == 0)
{ {
ERROR("invalid ELF file, no program headers"); ERROR("invalid ELF file, no program headers");
return ERROR_IMAGE_FORMAT_ERROR; 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"); ERROR("cannot read ELF segment headers, read failed");
return retval; 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"); ERROR("cannot read ELF segment headers, only partially read");
return ERROR_FILEIO_OPERATION_FAILED; 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)) 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].size = field32(elf, elf->segments[i].p_memsz);
image->sections[j].base_address = field32(elf,elf->segments[i].p_paddr); image->sections[j].base_address = field32(elf, elf->segments[i].p_paddr);
image->sections[j].private = &elf->segments[i]; 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++; j++;
} }
} }
image->start_address_set = 1; 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; 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 */ /* maximal size present in file for the current segment */
read_size = MIN(size, field32(elf, segment->p_filesz) - offset); read_size = MIN(size, field32(elf, segment->p_filesz) - offset);
DEBUG("read elf: size = 0x%x at 0x%x", read_size, 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 */ /* 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"); ERROR("cannot find ELF segment content, seek failed");
return retval; return retval;
@ -462,16 +462,7 @@ int image_elf_read_section(image_t *image, int section, u32 offset, u32 size, u8
if (!size) if (!size)
return ERROR_OK; 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; return ERROR_OK;
} }

View File

@ -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)->reset_script = NULL;
(*last_target_p)->post_halt_script = NULL; (*last_target_p)->post_halt_script = NULL;
(*last_target_p)->pre_resume_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 = 0x0;
(*last_target_p)->working_area_size = 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); free(target->pre_resume_script);
target->pre_resume_script = strdup(args[2]); 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 else
{ {
ERROR("unknown event type: '%s", args[1]); ERROR("unknown event type: '%s", args[1]);

View File

@ -157,6 +157,7 @@ typedef struct target_s
char *reset_script; /* script file to initialize the target after a reset */ 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 *post_halt_script; /* script file to execute after the target halted */
char *pre_resume_script; /* script file to execute before the target resumed */ 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; /* working area (initialized RAM) */
u32 working_area_size; /* size in bytes */ u32 working_area_size; /* size in bytes */
u32 backup_working_area; /* whether the content of the working area has to be preserved */ 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_RESET, /* target entered reset */
TARGET_EVENT_DEBUG_HALTED, /* target entered debug state, but was executing on behalf of the debugger */ 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_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 typedef struct target_event_callback_s