diff options
author | ntfreak <ntfreak@b42882b7-edfa-0310-969c-e2dbd0fdcd60> | 2007-12-29 13:51:48 +0000 |
---|---|---|
committer | ntfreak <ntfreak@b42882b7-edfa-0310-969c-e2dbd0fdcd60> | 2007-12-29 13:51:48 +0000 |
commit | 6c9b804d6187edda4f46f8458deec0b17ec76bb9 (patch) | |
tree | bb557b729b05e00b4839b199e58e066cdfa4c4b5 | |
parent | 2ec5bd2864e55654258070381ce58c126e9fbe7b (diff) | |
download | openocd+libswd-6c9b804d6187edda4f46f8458deec0b17ec76bb9.tar.gz openocd+libswd-6c9b804d6187edda4f46f8458deec0b17ec76bb9.tar.bz2 openocd+libswd-6c9b804d6187edda4f46f8458deec0b17ec76bb9.tar.xz openocd+libswd-6c9b804d6187edda4f46f8458deec0b17ec76bb9.zip |
- 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
-rw-r--r-- | configure.in | 1 | ||||
-rw-r--r-- | doc/openocd.texi | 103 | ||||
-rw-r--r-- | src/flash/flash.c | 28 | ||||
-rw-r--r-- | src/flash/flash.h | 1 | ||||
-rw-r--r-- | src/helper/command.c | 50 | ||||
-rw-r--r-- | src/jtag/usbprog.c | 598 | ||||
-rw-r--r-- | src/server/Makefile.am | 2 | ||||
-rw-r--r-- | src/server/gdb_server.c | 330 | ||||
-rw-r--r-- | src/server/gdb_server.h | 1 | ||||
-rw-r--r-- | src/target/image.c | 41 | ||||
-rw-r--r-- | src/target/target.c | 7 | ||||
-rw-r--r-- | src/target/target.h | 2 |
12 files changed, 791 insertions, 373 deletions
diff --git a/configure.in b/configure.in index 3802f60a..fd2584bb 100644 --- a/configure.in +++ b/configure.in @@ -1,3 +1,4 @@ +AC_PREREQ(2.59) AC_INIT(configure.in) AC_SEARCH_LIBS([ioperm], [ioperm]) diff --git a/doc/openocd.texi b/doc/openocd.texi index bb2c9435..786af94b 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -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 diff --git a/src/flash/flash.c b/src/flash/flash.c index efd16c34..de42fcde 100644 --- a/src/flash/flash.c +++ b/src/flash/flash.c @@ -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 */ diff --git a/src/flash/flash.h b/src/flash/flash.h index e8f91500..0f616a9a 100644 --- a/src/flash/flash.h +++ b/src/flash/flash.h @@ -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); diff --git a/src/helper/command.c b/src/helper/command.c index 44ead7cb..adaad109 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -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; diff --git a/src/jtag/usbprog.c b/src/jtag/usbprog.c index 94be8777..661b3b34 100644 --- a/src/jtag/usbprog.c +++ b/src/jtag/usbprog.c @@ -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; } } - diff --git a/src/server/Makefile.am b/src/server/Makefile.am index a41e9320..77256093 100644 --- a/src/server/Makefile.am +++ b/src/server/Makefile.am @@ -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 diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index ba5d2188..0ec1af73 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -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; } diff --git a/src/server/gdb_server.h b/src/server/gdb_server.h index cd00ce29..c02ad50e 100644 --- a/src/server/gdb_server.h +++ b/src/server/gdb_server.h @@ -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 diff --git a/src/target/image.c b/src/target/image.c index bdd89b1c..173fca56 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -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; } diff --git a/src/target/target.c b/src/target/target.c index 53022dff..01084512 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -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]); diff --git a/src/target/target.h b/src/target/target.h index 1900351e..e15a2c8e 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -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 |