Compare commits

...

12 Commits
jim ... rtt

Author SHA1 Message Date
  Jim Paris e8d8d9c53b rtt: Fix writing to down channels 4 years ago
  Marc Schink cdd93e3cff Add initial RTT support (WIP+RFC) 4 years ago
  Marc Schink 0326788077 server/server: Add ability to remove services 4 years ago
  Marc Schink afce40dd48 server/server: Remove all connections on shutdown 4 years ago
  Marc Schink 072d6bac02 helper/command.h: Add missing #include for target_addr_t 4 years ago
  Marc Schink eda66b053a server/server.h: Add missing #include 4 years ago
  Marc Schink 7e8a88a304 helper/types.h: Add missing #includes 4 years ago
  Marc Schink 032447a1f1 helper/command.h: Add missing #includes 4 years ago
  Marc Schink 20c7212cf1 helper/replacements.h: Add missing #include 4 years ago
  Marc Schink 4494c645b0 target: Fix memory leak 4 years ago
  Marc Schink ba52458dfc server/server: Remove all exit() calls 5 years ago
  Marc Schink e8f065c616 Fix Jim interpreter memory leak 6 years ago
24 changed files with 1564 additions and 57 deletions
Split View
  1. +3
    -1
      src/Makefile.am
  2. +6
    -2
      src/flash/nor/stellaris.c
  3. +41
    -8
      src/helper/command.c
  4. +21
    -1
      src/helper/command.h
  5. +2
    -0
      src/helper/replacements.h
  6. +5
    -0
      src/helper/types.h
  7. +4
    -1
      src/jtag/core.c
  8. +16
    -2
      src/openocd.c
  9. +2
    -0
      src/rtt/Makefile.am
  10. +516
    -0
      src/rtt/rtt.c
  11. +119
    -0
      src/rtt/rtt.h
  12. +3
    -1
      src/server/Makefile.am
  13. +182
    -0
      src/server/rtt_server.c
  14. +26
    -0
      src/server/rtt_server.h
  15. +110
    -20
      src/server/server.c
  16. +5
    -0
      src/server/server.h
  17. +3
    -1
      src/server/tcl_server.c
  18. +12
    -8
      src/server/telnet_server.c
  19. +4
    -2
      src/target/Makefile.am
  20. +1
    -1
      src/target/dsp563xx.c
  21. +412
    -0
      src/target/rtt.c
  22. +46
    -0
      src/target/rtt.h
  23. +24
    -8
      src/target/target.c
  24. +1
    -1
      src/target/target.h

+ 3
- 1
src/Makefile.am View File

@@ -53,7 +53,8 @@ endif
%D%/target/libtarget.la \
%D%/server/libserver.la \
%D%/rtos/librtos.la \
%D%/helper/libhelper.la
%D%/helper/libhelper.la \
%D%/rtt/librtt.la

BIN2C = $(srcdir)/%D%/helper/bin2char.sh

@@ -83,3 +84,4 @@ include %D%/rtos/Makefile.am
include %D%/server/Makefile.am
include %D%/flash/Makefile.am
include %D%/pld/Makefile.am
include %D%/rtt/Makefile.am

+ 6
- 2
src/flash/nor/stellaris.c View File

@@ -1356,6 +1356,7 @@ COMMAND_HANDLER(stellaris_handle_recover_command)
{
struct flash_bank *bank;
int retval;
const char *tmp;

if (CMD_ARGC != 0)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -1370,8 +1371,11 @@ COMMAND_HANDLER(stellaris_handle_recover_command)
* cycle to recover.
*/

Jim_Eval_Named(CMD_CTX->interp, "catch { hla_command \"debug unlock\" }", 0, 0);
if (!strcmp(Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL), "0")) {
Jim_Eval_Named(CMD_CTX->interp->interp,
"catch { hla_command \"debug unlock\" }", 0, 0);
tmp = Jim_GetString(Jim_GetResult(CMD_CTX->interp->interp), NULL);

if (!strcmp(tmp, "0")) {
retval = ERROR_OK;
goto user_action;
}


+ 41
- 8
src/helper/command.c View File

@@ -356,7 +356,7 @@ static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
static int register_command_handler(struct command_context *cmd_ctx,
struct command *c)
{
Jim_Interp *interp = cmd_ctx->interp;
Jim_Interp *interp = cmd_ctx->interp->interp;
char *ocd_name = alloc_printf("ocd_%s", c->name);
if (NULL == ocd_name)
return JIM_ERR;
@@ -406,7 +406,7 @@ struct command *register_command(struct command_context *context,

int retval = ERROR_OK;
if (NULL != cr->jim_handler && NULL == parent) {
retval = Jim_CreateCommand(context->interp, cr->name,
retval = Jim_CreateCommand(context->interp->interp, cr->name,
cr->jim_handler, cr->jim_handler_data, NULL);
} else if (NULL != cr->handler || NULL != parent)
retval = register_command_handler(context, command_root(c));
@@ -643,7 +643,7 @@ int command_run_line(struct command_context *context, char *line)
* happen when the Jim Tcl interpreter is provided by eCos for
* instance.
*/
Jim_Interp *interp = context->interp;
Jim_Interp *interp = context->interp->interp;
Jim_DeleteAssocData(interp, "context");
retcode = Jim_SetAssocData(interp, "context", NULL, context);
if (retcode == JIM_OK) {
@@ -720,8 +720,14 @@ void command_set_output_handler(struct command_context *context,

struct command_context *copy_command_context(struct command_context *context)
{
struct command_context *copy_context = malloc(sizeof(struct command_context));
struct command_context *copy_context;

copy_context = malloc(sizeof(struct command_context));

if (!copy_context)
return NULL;

context->interp->refcnt++;
*copy_context = *context;

return copy_context;
@@ -729,9 +735,18 @@ struct command_context *copy_command_context(struct command_context *context)

void command_done(struct command_context *cmd_ctx)
{
if (NULL == cmd_ctx)
if (cmd_ctx == NULL)
return;

cmd_ctx->interp->refcnt--;

if (!cmd_ctx->interp->refcnt) {
if (cmd_ctx->interp->free)
Jim_FreeInterp(cmd_ctx->interp->interp);

free(cmd_ctx->interp);
}

free(cmd_ctx);
}

@@ -1269,14 +1284,28 @@ static const struct command_registration command_builtin_handlers[] = {

struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp)
{
struct command_context *context = malloc(sizeof(struct command_context));
struct command_context *context;
const char *HostOs;

context = malloc(sizeof(struct command_context));

if (!context) {
LOG_ERROR("Failed to allocate command context.");
return NULL;
}

context->mode = COMMAND_EXEC;
context->commands = NULL;
context->current_target = 0;
context->output_handler = NULL;
context->output_handler_priv = NULL;
context->interp = malloc(sizeof(struct command_interpreter));

if (!context->interp) {
LOG_ERROR("Failed to allocate command interpreter.");
free(context);
return NULL;
}

/* Create a jim interpreter if we were not handed one */
if (interp == NULL) {
@@ -1285,9 +1314,13 @@ struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp
/* Add all the Jim core commands */
Jim_RegisterCoreCommands(interp);
Jim_InitStaticExtensions(interp);
context->interp->free = true;
} else {
context->interp->free = false;
}

context->interp = interp;
context->interp->interp = interp;
context->interp->refcnt = 1;

/* Stick to lowercase for HostOS strings. */
#if defined(_MSC_VER)
@@ -1355,7 +1388,7 @@ void process_jim_events(struct command_context *cmd_ctx)
return;

recursion++;
Jim_ProcessEvents(cmd_ctx->interp, JIM_ALL_EVENTS | JIM_DONT_WAIT);
Jim_ProcessEvents(cmd_ctx->interp->interp, JIM_ALL_EVENTS | JIM_DONT_WAIT);
recursion--;
}



+ 21
- 1
src/helper/command.h View File

@@ -22,8 +22,12 @@
#ifndef OPENOCD_HELPER_COMMAND_H
#define OPENOCD_HELPER_COMMAND_H

#include <stdint.h>
#include <stdbool.h>
#include <jim-nvp.h>

#include <helper/types.h>

/* To achieve C99 printf compatibility in MinGW, gnu_printf should be
* used for __attribute__((format( ... ))), with GCC v4.4 or later
*/
@@ -39,6 +43,22 @@ enum command_mode {
COMMAND_ANY,
};

/**
* Helper struct to share a common Jim interpreter among multiple command
* contexts.
*/
struct command_interpreter {
/** Jim interpreter. */
Jim_Interp *interp;
/** Number of references held on this interpreter. */
unsigned int refcnt;
/**
* Determines whether the Jim interpreter should be free'd when the last
* reference is released.
*/
bool free;
};

struct command_context;

/** The type signature for command context's output handler. */
@@ -46,7 +66,7 @@ typedef int (*command_output_handler_t)(struct command_context *context,
const char *line);

struct command_context {
Jim_Interp *interp;
struct command_interpreter *interp;
enum command_mode mode;
struct command *commands;
int current_target;


+ 2
- 0
src/helper/replacements.h View File

@@ -25,6 +25,8 @@
#ifndef OPENOCD_HELPER_REPLACEMENTS_H
#define OPENOCD_HELPER_REPLACEMENTS_H

#include <stdint.h>

/* MIN,MAX macros */
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))


+ 5
- 0
src/helper/types.h View File

@@ -22,7 +22,12 @@
#ifndef OPENOCD_HELPER_TYPES_H
#define OPENOCD_HELPER_TYPES_H

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stddef.h>
#include <assert.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif


+ 4
- 1
src/jtag/core.c View File

@@ -1582,7 +1582,10 @@ int jtag_init(struct command_context *cmd_ctx)
if (retval != ERROR_OK)
return retval;

if (Jim_Eval_Named(cmd_ctx->interp, "jtag_init", __FILE__, __LINE__) != JIM_OK)
retval = Jim_Eval_Named(cmd_ctx->interp->interp, "jtag_init", __FILE__,
__LINE__);

if (retval != JIM_OK)
return ERROR_FAIL;

return ERROR_OK;


+ 16
- 2
src/openocd.c View File

@@ -37,9 +37,11 @@
#include <flash/nand/core.h>
#include <pld/pld.h>
#include <flash/mflash.h>
#include <rtt/rtt.h>

#include <server/server.h>
#include <server/gdb_server.h>
#include <server/rtt_server.h>

#ifdef HAVE_STRINGS_H
#include <strings.h>
@@ -170,7 +172,10 @@ COMMAND_HANDLER(handle_init_command)
command_context_mode(CMD_CTX, COMMAND_EXEC);

/* initialize telnet subsystem */
gdb_target_add_all(all_targets);
retval = gdb_target_add_all(all_targets);

if (retval != ERROR_OK)
return retval;

target_register_event_callback(log_target_callback_event_handler, CMD_CTX);

@@ -245,6 +250,8 @@ struct command_context *setup_command_handler(Jim_Interp *interp)
&server_register_commands,
&gdb_register_commands,
&log_register_commands,
&rtt_register_commands,
&rtt_server_register_commands,
&transport_register_commands,
&interface_register_commands,
&target_register_commands,
@@ -297,8 +304,10 @@ static int openocd_thread(int argc, char *argv[], struct command_context *cmd_ct

if (init_at_startup) {
ret = command_run_line(cmd_ctx, "init");
if (ERROR_OK != ret)
if (ERROR_OK != ret) {
server_quit();
return ERROR_FAIL;
}
}

ret = server_loop(cmd_ctx);
@@ -330,6 +339,9 @@ int openocd_main(int argc, char *argv[])
if (ioutil_init(cmd_ctx) != ERROR_OK)
return EXIT_FAILURE;

if (rtt_init() != ERROR_OK)
return EXIT_FAILURE;

LOG_OUTPUT("For bug reports, read\n\t"
"http://openocd.org/doc/doxygen/bugs.html"
"\n");
@@ -347,6 +359,8 @@ int openocd_main(int argc, char *argv[])

adapter_quit();

rtt_exit();

if (ERROR_FAIL == ret)
return EXIT_FAILURE;
else if (ERROR_OK != ret)


+ 2
- 0
src/rtt/Makefile.am View File

@@ -0,0 +1,2 @@
noinst_LTLIBRARIES += %D%/librtt.la
%C%_librtt_la_SOURCES = %D%/rtt.c %D%/rtt.h

+ 516
- 0
src/rtt/rtt.c View File

@@ -0,0 +1,516 @@
/*
* Copyright (C) 2016-2017 by Marc Schink
* openocd-dev@marcschink.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#include <helper/log.h>
#include <helper/list.h>
#include <target/target.h>
#include <target/rtt.h>

#include "rtt.h"

static struct rtt_source global_source;
static struct rtt_control global_ctrl;
static struct target *global_target;
static target_addr_t global_addr;
static uint32_t global_length;
static char global_id[RTT_MAX_CB_ID_LENGTH];
static size_t global_id_length;
static bool global_configured;
static bool global_started;
static bool global_changed;
static bool global_found_cb;

static struct rtt_sink_list **global_sink_list;
static size_t global_sink_list_length;

int rtt_init(void)
{
global_sink_list_length = 1;
global_sink_list = calloc(global_sink_list_length,
sizeof(struct rtt_sink_list *));

if (!global_sink_list)
return ERROR_FAIL;

global_sink_list[0] = NULL;
global_started = false;

return ERROR_OK;
}

int rtt_exit(void)
{
free(global_sink_list);

return ERROR_OK;
}

static int read_channel_callback(void *user_data)
{
int ret;

ret = global_source.read(&global_ctrl, global_sink_list,
global_sink_list_length, global_target, NULL);

if (ret != ERROR_OK) {
target_unregister_timer_callback(&read_channel_callback, NULL);
global_source.stop(global_target, NULL);
return ret;
}

return ERROR_OK;
}

int rtt_register_source(const struct rtt_source source, struct target *target)
{
global_source = source;
global_target = target;

return ERROR_OK;
}

int rtt_start(void)
{
int ret;
target_addr_t addr = global_addr;

if (global_started) {
LOG_INFO("RTT already started");
return ERROR_OK;
}

if (!global_found_cb || global_changed) {
global_source.find_cb(&addr, global_length, global_id,
global_id_length, &global_found_cb, global_target, NULL);

global_changed = false;

if (global_found_cb) {
LOG_INFO("RTT control block found at 0x%" TARGET_PRIxADDR, addr);
global_ctrl.address = addr;
} else {
LOG_INFO("No RTT control block found");
return ERROR_OK;
}
}

ret = global_source.read_cb(global_ctrl.address, &global_ctrl,
global_target, NULL);

if (ret != ERROR_OK)
return ret;

ret = global_source.start(&global_ctrl, global_target, NULL);

if (ret != ERROR_OK)
return ret;

target_register_timer_callback(&read_channel_callback, 100, 1, NULL);
global_started = true;

return ERROR_OK;
}

int rtt_stop(void)
{
int ret;

target_unregister_timer_callback(&read_channel_callback, NULL);
global_started = false;

ret = global_source.stop(global_target, NULL);

if (ret != ERROR_OK)
return ret;

return ERROR_OK;
}

static int adjust_sink_list(size_t length)
{
size_t i;
struct rtt_sink_list **tmp;

if (length <= global_sink_list_length)
return ERROR_OK;

tmp = realloc(global_sink_list, sizeof(struct rtt_sink_list *) * length);

if (!tmp)
return ERROR_FAIL;

for (i = global_sink_list_length; i < length; i++)
tmp[i] = NULL;

global_sink_list = tmp;
global_sink_list_length = length;

return ERROR_OK;
}

int rtt_register_sink(unsigned int channel, rtt_sink_read read,
void *user_data)
{
struct rtt_sink_list *tmp;

if (channel >= global_sink_list_length) {
if (adjust_sink_list(channel + 1) != ERROR_OK)
return ERROR_FAIL;
}

LOG_DEBUG("Registering sink for RTT channel %u", channel);

tmp = malloc(sizeof(struct rtt_sink_list));

if (!tmp)
return ERROR_FAIL;

tmp->read = read;
tmp->user_data = user_data;
tmp->next = global_sink_list[channel];

global_sink_list[channel] = tmp;

return ERROR_OK;
}

int rtt_unregister_sink(unsigned int channel, rtt_sink_read read,
void *user_data)
{
struct rtt_sink_list *sink;
struct rtt_sink_list *prev_sink;

LOG_DEBUG("Unregistering sink for RTT channel %u", channel);

if (channel >= global_sink_list_length)
return ERROR_FAIL;

prev_sink = global_sink_list[channel];

for (sink = global_sink_list[channel]; sink; prev_sink = sink,
sink = sink->next) {
if (sink->read == read && sink->user_data == user_data) {

if (sink == global_sink_list[channel])
global_sink_list[channel] = sink->next;
else
prev_sink->next = sink->next;

free(sink);

return ERROR_OK;
}
}

return ERROR_OK;
}

int rtt_write_channel(unsigned int channel, const uint8_t *buffer,
size_t *length)
{
if (!global_source.write)
return ERROR_FAIL;

if (channel >= global_ctrl.num_up_buffers) {
LOG_WARNING("Down-channel %u is not available", channel);
return ERROR_OK;
}

return global_source.write(&global_ctrl, channel, buffer, length,
global_target, NULL);
}

COMMAND_HANDLER(handle_rtt_setup_command)
{
target_addr_t addr;
uint32_t length;
struct rtt_source source;

if (CMD_ARGC != 3)
return ERROR_COMMAND_SYNTAX_ERROR;

COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[0], addr);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length);

global_id_length = strlen(CMD_ARGV[2]);

if (!global_id_length || global_id_length > RTT_MAX_CB_ID_LENGTH) {
LOG_ERROR("Invalid RTT control block ID");
return ERROR_COMMAND_ARGUMENT_INVALID;
}

source.find_cb = &target_rtt_find_control_block;
source.read_cb = &target_rtt_read_control_block;
source.start = &target_rtt_start;
source.stop = &target_rtt_stop;
source.read = &target_rtt_read_callback;
source.write = &target_rtt_write_callback;
source.read_buffer_info = &target_rtt_read_buffer_info;

rtt_register_source(source, get_current_target(CMD_CTX));

global_addr = addr;
global_length = length;
memcpy(global_id, CMD_ARGV[2], global_id_length);
global_changed = true;
global_configured = true;

return ERROR_OK;
}

COMMAND_HANDLER(handle_rtt_start_command)
{
int ret;

if (CMD_ARGC > 0)
return ERROR_COMMAND_SYNTAX_ERROR;

if (global_started) {
LOG_INFO("RTT already started");
return ERROR_OK;
}

if (!global_configured) {
LOG_ERROR("RTT is not configured");
return ERROR_FAIL;
}

ret = rtt_start();

if (ret != ERROR_OK)
return ret;

return ERROR_OK;
}

COMMAND_HANDLER(handle_rtt_stop_command)
{
int ret;

if (CMD_ARGC > 0)
return ERROR_COMMAND_SYNTAX_ERROR;

ret = rtt_stop();

if (ret != ERROR_OK)
return ret;

return ERROR_OK;
}

COMMAND_HANDLER(handle_rtt_channels_command)
{
int ret;
size_t i;
char channel_name[32];
struct rtt_buffer_info info;

if (!global_found_cb) {
LOG_ERROR("RTT control block not available");
return ERROR_FAIL;
}

command_print(CMD_CTX, "Channels: up=%u, down=%u",
global_ctrl.num_up_buffers, global_ctrl.num_down_buffers);

LOG_INFO("Up-channels:");

info.name = channel_name;
info.name_length = sizeof(channel_name);

for (i = 0; i < global_ctrl.num_up_buffers; i++) {
ret = global_source.read_buffer_info(&global_ctrl, i, true, &info,
global_target, NULL);

if (ret != ERROR_OK)
return ret;

if (!info.size)
continue;

LOG_INFO("%zu: %s %u %u", i, info.name, info.size, info.flags);
}

LOG_INFO("Down-channels:");

for (i = 0; i < global_ctrl.num_down_buffers; i++) {
ret = global_source.read_buffer_info(&global_ctrl, i, false, &info,
global_target, NULL);

if (ret != ERROR_OK)
return ret;

if (!info.size)
continue;

LOG_INFO("%zu: %s %u %u", i, info.name, info.size, info.flags);
}

return ERROR_OK;
}

static int jim_channel_list(Jim_Interp *interp, int argc,
Jim_Obj * const *argv)
{
int ret;
size_t i;
Jim_Obj *list;
Jim_Obj *channel_list;
char channel_name[128];
struct rtt_buffer_info info;

if (!global_found_cb) {
LOG_ERROR("RTT control block not available");
return ERROR_FAIL;
}

info.name = channel_name;
info.name_length = sizeof(channel_name);

list = Jim_NewListObj(interp, NULL, 0);

channel_list = Jim_NewListObj(interp, NULL, 0);

for (i = 0; i < global_ctrl.num_up_buffers; i++) {
ret = global_source.read_buffer_info(&global_ctrl, i, true, &info,
global_target, NULL);

if (ret != ERROR_OK)
return ret;

if (!info.size)
continue;

Jim_Obj *tmp = Jim_NewListObj(interp, NULL, 0);

Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
"name", -1));
Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
info.name, -1));

Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
"size", -1));
Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
info.size));

Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
"flags", -1));
Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
info.flags));

Jim_ListAppendElement(interp, channel_list, tmp);
}

Jim_ListAppendElement(interp, list, channel_list);

channel_list = Jim_NewListObj(interp, NULL, 0);

for (i = 0; i < global_ctrl.num_down_buffers; i++) {
ret = global_source.read_buffer_info(&global_ctrl, i, false, &info,
global_target, NULL);

if (ret != ERROR_OK)
return ret;

if (!info.size)
continue;

Jim_Obj *tmp = Jim_NewListObj(interp, NULL, 0);

Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
"name", -1));
Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
info.name, -1));

Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
"size", -1));
Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
info.size));

Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
"flags", -1));
Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
info.flags));

Jim_ListAppendElement(interp, channel_list, tmp);
}

Jim_ListAppendElement(interp, list, channel_list);
Jim_SetResult(interp, list);

return JIM_OK;
}

static const struct command_registration rtt_subcommand_handlers[] = {
{
.name = "setup",
.handler = handle_rtt_setup_command,
.mode = COMMAND_ANY,
.help = "setup RTT",
.usage = "<address> <length> <ID>"
},
{
.name = "start",
.handler = handle_rtt_start_command,
.mode = COMMAND_EXEC,
.help = "start RTT",
.usage = ""
},
{
.name = "stop",
.handler = handle_rtt_stop_command,
.mode = COMMAND_EXEC,
.help = "stop RTT",
.usage = ""
},
{
.name = "channels",
.handler = handle_rtt_channels_command,
.mode = COMMAND_EXEC,
.help = "list available channels",
.usage = ""
},
{
.name = "channellist",
.jim_handler = jim_channel_list,
.mode = COMMAND_EXEC,
.help = "list available channels",
.usage = ""
},
COMMAND_REGISTRATION_DONE
};

static const struct command_registration rtt_command_handlers[] = {
{
.name = "rtt",
.mode = COMMAND_EXEC,
.help = "RTT commands",
.usage = "",
.chain = rtt_subcommand_handlers
},
COMMAND_REGISTRATION_DONE
};

int rtt_register_commands(struct command_context *ctx)
{
return register_commands(ctx, NULL, rtt_command_handlers);
}

+ 119
- 0
src/rtt/rtt.h View File

@@ -0,0 +1,119 @@
/*
* Copyright (C) 2016-2017 by Marc Schink
* openocd-dev@marcschink.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef OPENOCD_RTT_RTT_H
#define OPENOCD_RTT_RTT_H

#include <stdint.h>
#include <stdbool.h>

#include <helper/command.h>
#include <target/target.h>

#define RTT_MAX_CB_ID_LENGTH 16
#define RTT_MIN_BUFFER_SIZE 2
#define RTT_CB_LENGTH (RTT_MAX_CB_ID_LENGTH + 4 + 4)
#define RTT_BUFFER_LENGTH 24

struct rtt_control {
target_addr_t address;
char id[RTT_MAX_CB_ID_LENGTH + 1];
uint32_t num_up_buffers;
uint32_t num_down_buffers;
};

struct rtt_buffer {
target_addr_t address;
target_addr_t name_addr;
target_addr_t buffer_addr;
uint32_t size;
uint32_t write_offset;
uint32_t read_offset;
uint32_t flags;
};

struct rtt_buffer_info {
char *name;
size_t name_length;
uint32_t size;
uint32_t flags;
};

typedef int (*rtt_sink_read)(unsigned int channel, const uint8_t *buffer,
size_t length, void *user_data);

struct rtt_sink_list {
rtt_sink_read read;
void *user_data;

struct rtt_sink_list *next;
};

enum rtt_channel_type {
RTT_CHANNEL_TYPE_UP,
RTT_CHANNEL_TYPE_DOWN
};

typedef int (*rtt_source_find_ctrl_block)(target_addr_t *address,
size_t length, const char *id, size_t id_length, bool *found,
struct target *target, void *user_data);
typedef int (*rtt_source_read_ctrl_block)(target_addr_t address,
struct rtt_control *ctrl_block, struct target *target,
void *user_data);
typedef int (*rtt_source_read_buffer_info)(const struct rtt_control *ctrl,
unsigned int channel, enum rtt_channel_type type,
struct rtt_buffer_info *info, struct target *target, void *user_data);
typedef int (*rtt_source_start)(const struct rtt_control *ctrl,
struct target *target, void *user_data);
typedef int (*rtt_source_stop)(struct target *target, void *user_data);
typedef int (*rtt_source_read)(const struct rtt_control *ctrl,
struct rtt_sink_list **sinks, size_t num_channels,
struct target *target, void *user_data);
typedef int (*rtt_source_write)(struct rtt_control *ctrl,
unsigned int channel, const uint8_t *buffer, size_t *length,
struct target *target, void *user_data);

struct rtt_source {
rtt_source_find_ctrl_block find_cb;
rtt_source_read_ctrl_block read_cb;
rtt_source_read_buffer_info read_buffer_info;
rtt_source_start start;
rtt_source_stop stop;
rtt_source_read read;
rtt_source_write write;
};

int rtt_init(void);
int rtt_exit(void);

int rtt_register_source(const struct rtt_source source, struct target *target);

int rtt_start(void);
int rtt_stop(void);

int rtt_register_sink(unsigned int channel, rtt_sink_read read,
void *user_data);
int rtt_unregister_sink(unsigned int channel, rtt_sink_read read,
void *user_data);

int rtt_write_channel(unsigned int channel, const uint8_t *buffer,
size_t *length);

int rtt_register_commands(struct command_context *ctx);

#endif /* OPENOCD_RTT_RTT_H */

+ 3
- 1
src/server/Makefile.am View File

@@ -8,7 +8,9 @@ noinst_LTLIBRARIES += %D%/libserver.la
%D%/gdb_server.h \
%D%/server_stubs.c \
%D%/tcl_server.c \
%D%/tcl_server.h
%D%/tcl_server.h \
%D%/rtt_server.c \
%D%/rtt_server.h

%C%_libserver_la_CFLAGS = $(AM_CFLAGS)
if IS_MINGW


+ 182
- 0
src/server/rtt_server.c View File

@@ -0,0 +1,182 @@
/*
* Copyright (C) 2016-2017 by Marc Schink
* openocd-dev@marcschink.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdint.h>
#include <rtt/rtt.h>

#include "server.h"
#include "rtt_server.h"

/**
* @file
*
* RTT server.
*
* This server allows access to Real Time Transfer (RTT) channels via TCP
* connections.
*/

struct rtt_service {
unsigned int channel;
};

static int read_callback(unsigned int channel, const uint8_t *buffer,
size_t length, void *user_data)
{
int ret;
struct connection *connection;
size_t offset;

connection = (struct connection *)user_data;
offset = 0;

while (offset < length) {
ret = connection_write(connection, buffer + offset, length - offset);

if (ret < 0) {
LOG_ERROR("Failed to write data to socket.");
return ERROR_FAIL;
}

offset += ret;
}

return ERROR_OK;
}

static int rtt_new_connection(struct connection *connection)
{
int ret;
struct rtt_service *service;

service = connection->service->priv;

LOG_DEBUG("New connection for RTT channel %u", service->channel);

ret = rtt_register_sink(service->channel, &read_callback, connection);

if (ret != ERROR_OK)
return ret;

return ERROR_OK;
}

static int rtt_connection_closed(struct connection *connection)
{
struct rtt_service *service;

service = (struct rtt_service *)connection->service->priv;
rtt_unregister_sink(service->channel, &read_callback, connection);

LOG_DEBUG("Connection for RTT channel %u closed", service->channel);

return ERROR_OK;
}

static int rtt_input(struct connection *connection)
{
int bytes_read;
unsigned char buffer[1024];
struct rtt_service *service;
size_t length;

service = (struct rtt_service *)connection->service->priv;
bytes_read = connection_read(connection, buffer, sizeof(buffer));

if (!bytes_read)
return ERROR_SERVER_REMOTE_CLOSED;
else if (bytes_read < 0) {
LOG_ERROR("error during read: %s", strerror(errno));
return ERROR_SERVER_REMOTE_CLOSED;
}

length = bytes_read;
rtt_write_channel(service->channel, buffer, &length);

return ERROR_OK;
}

COMMAND_HANDLER(handle_rtt_start_command)
{
int ret;
struct rtt_service *service;

if (CMD_ARGC != 2)
return ERROR_COMMAND_SYNTAX_ERROR;

service = malloc(sizeof(struct rtt_service));

if (!service)
return ERROR_FAIL;

COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], service->channel);

ret = add_service("RTT", CMD_ARGV[0], CONNECTION_LIMIT_UNLIMITED,
rtt_new_connection, rtt_input, rtt_connection_closed, service);

if (ret != ERROR_OK) {
free(service);
return ERROR_FAIL;
}

return ERROR_OK;
}

COMMAND_HANDLER(handle_rtt_stop_command)
{
if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;

remove_service("RTT", CMD_ARGV[0]);

return ERROR_OK;
}

static const struct command_registration rtt_subcommand_handlers[] = {
{
.name = "start",
.handler = handle_rtt_start_command,
.mode = COMMAND_ANY,
.help = "Start a RTT server",
.usage = "<port> <channel>"
},
{
.name = "stop",
.handler = handle_rtt_stop_command,
.mode = COMMAND_ANY,
.help = "Stop a RTT server",
.usage = "<port>"
},
COMMAND_REGISTRATION_DONE
};

static const struct command_registration rtt_command_handlers[] = {
{
.name = "rttserver",
.mode = COMMAND_ANY,
.help = "RTT server",
.usage = "",
.chain = rtt_subcommand_handlers
},
COMMAND_REGISTRATION_DONE
};

int rtt_server_register_commands(struct command_context *ctx)
{
return register_commands(ctx, NULL, rtt_command_handlers);
}

+ 26
- 0
src/server/rtt_server.h View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2016-2017 by Marc Schink
* openocd-dev@marcschink.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef OPENOCD_SERVER_RTT_SERVER_H
#define OPENOCD_SERVER_RTT_SERVER_H

#include <helper/command.h>

int rtt_server_register_commands(struct command_context *ctx);

#endif /* OPENOCD_SERVER_RTT_SERVER_H */

+ 110
- 20
src/server/server.c View File

@@ -67,10 +67,23 @@ static int add_connection(struct service *service, struct command_context *cmd_c
int flag = 1;

c = malloc(sizeof(struct connection));

if (!c) {
LOG_ERROR("Failed to allocate connection.");
return ERROR_FAIL;
}

c->cmd_ctx = copy_command_context(cmd_ctx);

if (!c->cmd_ctx) {
LOG_ERROR("Failed to copy command context.");
free(c);
return ERROR_FAIL;
}

c->fd = -1;
c->fd_out = -1;
memset(&c->sin, 0, sizeof(c->sin));
c->cmd_ctx = copy_command_context(cmd_ctx);
c->service = service;
c->input_pending = 0;
c->priv = NULL;
@@ -132,7 +145,9 @@ static int add_connection(struct service *service, struct command_context *cmd_c
free(out_file);
if (c->fd_out == -1) {
LOG_ERROR("could not open %s", service->port);
exit(1);
command_done(c->cmd_ctx);
free(c);
return ERROR_FAIL;
}

LOG_INFO("accepting '%s' connection from pipe %s", service->name, service->port);
@@ -191,7 +206,13 @@ static int remove_connection(struct service *service, struct connection *connect
return ERROR_OK;
}

/* FIX! make service return error instead of invoking exit() */
static void free_service(struct service *c)
{
free(c->name);
free(c->port);
free(c);
}

int add_service(char *name,
const char *port,
int max_connections,
@@ -235,7 +256,8 @@ int add_service(char *name,
c->fd = socket(AF_INET, SOCK_STREAM, 0);
if (c->fd == -1) {
LOG_ERROR("error creating socket: %s", strerror(errno));
exit(-1);
free_service(c);
return ERROR_FAIL;
}

setsockopt(c->fd,
@@ -255,7 +277,9 @@ int add_service(char *name,
hp = gethostbyname(bindto_name);
if (hp == NULL) {
LOG_ERROR("couldn't resolve bindto address: %s", bindto_name);
exit(-1);
close_socket(c->fd);
free_service(c);
return ERROR_FAIL;
}
memcpy(&c->sin.sin_addr, hp->h_addr_list[0], hp->h_length);
}
@@ -263,7 +287,9 @@ int add_service(char *name,

if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) {
LOG_ERROR("couldn't bind %s to socket: %s", name, strerror(errno));
exit(-1);
close_socket(c->fd);
free_service(c);
return ERROR_FAIL;
}

#ifndef _WIN32
@@ -281,7 +307,9 @@ int add_service(char *name,

if (listen(c->fd, 1) == -1) {
LOG_ERROR("couldn't listen on socket: %s", strerror(errno));
exit(-1);
close_socket(c->fd);
free_service(c);
return ERROR_FAIL;
}
} else if (c->type == CONNECTION_STDINOUT) {
c->fd = fileno(stdin);
@@ -302,13 +330,15 @@ int add_service(char *name,
/* we currenty do not support named pipes under win32
* so exit openocd for now */
LOG_ERROR("Named pipes currently not supported under this os");
exit(1);
free_service(c);
return ERROR_FAIL;
#else
/* Pipe we're reading from */
c->fd = open(c->port, O_RDONLY | O_NONBLOCK);
if (c->fd == -1) {
LOG_ERROR("could not open %s", c->port);
exit(1);
free_service(c);
return ERROR_FAIL;
}
#endif
}
@@ -321,6 +351,50 @@ int add_service(char *name,
return ERROR_OK;
}

static void remove_connections(struct service *service)
{
struct connection *connection;

connection = service->connections;

while (connection) {
struct connection *tmp;

tmp = connection->next;
remove_connection(service, connection);
connection = tmp;
}
}

int remove_service(const char *name, const char *port)
{
struct service *tmp;
struct service *prev;

prev = services;

for (tmp = services; tmp; prev = tmp, tmp = tmp->next) {
if (!strcmp(tmp->name, name) && !strcmp(tmp->port, port)) {
remove_connections(tmp);

if (tmp == services)
services = tmp->next;
else
prev->next = tmp->next;

if (tmp->type != CONNECTION_STDINOUT)
close_socket(tmp->fd);

free(tmp->priv);
free_service(tmp);

return ERROR_OK;
}
}

return ERROR_OK;
}

static int remove_services(void)
{
struct service *c = services;
@@ -329,6 +403,8 @@ static int remove_services(void)
while (c) {
struct service *next = c->next;

remove_connections(c);

if (c->name)
free(c->name);

@@ -425,7 +501,7 @@ int server_loop(struct command_context *command_context)
FD_ZERO(&read_fds);
else {
LOG_ERROR("error during select: %s", strerror(errno));
exit(-1);
return ERROR_FAIL;
}
#else

@@ -433,7 +509,7 @@ int server_loop(struct command_context *command_context)
FD_ZERO(&read_fds);
else {
LOG_ERROR("error during select: %s", strerror(errno));
exit(-1);
return ERROR_FAIL;
}
#endif
}
@@ -463,11 +539,15 @@ int server_loop(struct command_context *command_context)

for (service = services; service; service = service->next) {
/* handle new connections on listeners */
if ((service->fd != -1)
&& (FD_ISSET(service->fd, &read_fds))) {
if (service->max_connections != 0)
add_connection(service, command_context);
else {
if ((service->fd != -1) && (FD_ISSET(service->fd, &read_fds))) {
if (service->max_connections != 0) {
retval = add_connection(service, command_context);

if (retval != ERROR_OK) {
LOG_ERROR("%i", retval);
return ERROR_FAIL;
}
} else {
if (service->type == CONNECTION_TCP) {
struct sockaddr_in sin;
socklen_t address_size = sizeof(sin);
@@ -552,7 +632,7 @@ int server_preinit(void)

if (WSAStartup(wVersionRequested, &wsaData) != 0) {
LOG_ERROR("Failed to Open Winsock");
exit(-1);
return ERROR_FAIL;
}

/* register ctrl-c handler */
@@ -569,11 +649,21 @@ int server_preinit(void)

int server_init(struct command_context *cmd_ctx)
{
int ret = tcl_init();
if (ERROR_OK != ret)
int ret;

ret = tcl_init();

if (ret != ERROR_OK)
return ret;

ret = telnet_init("Open On-Chip Debugger");

if (ret != ERROR_OK) {
remove_services();
return ret;
}

return telnet_init("Open On-Chip Debugger");
return ERROR_OK;
}

int server_quit(void)


+ 5
- 0
src/server/server.h View File

@@ -25,6 +25,10 @@
#ifndef OPENOCD_SERVER_SERVER_H
#define OPENOCD_SERVER_SERVER_H

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <helper/log.h>

#ifdef HAVE_NETINET_IN_H
@@ -74,6 +78,7 @@ int add_service(char *name, const char *port,
int max_connections, new_connection_handler_t new_connection_handler,
input_handler_t in_handler, connection_closed_handler_t close_handler,
void *priv);
int remove_service(const char *name, const char *port);

int server_preinit(void);
int server_init(struct command_context *cmd_ctx);


+ 3
- 1
src/server/tcl_server.c View File

@@ -173,7 +173,7 @@ static int tcl_new_connection(struct connection *connection)

static int tcl_input(struct connection *connection)
{
Jim_Interp *interp = (Jim_Interp *)connection->cmd_ctx->interp;
Jim_Interp *interp;
int retval;
int i;
ssize_t rlen;
@@ -184,6 +184,8 @@ static int tcl_input(struct connection *connection)
char *tc_line_new;
int tc_line_size_new;

interp = connection->cmd_ctx->interp->interp;

rlen = connection_read(connection, &in, sizeof(in));
if (rlen <= 0) {
if (rlen < 0)


+ 12
- 8
src/server/telnet_server.c View File

@@ -619,13 +619,14 @@ static int telnet_connection_closed(struct connection *connection)

int telnet_init(char *banner)
{
int ret;
struct telnet_service *telnet_service;

if (strcmp(telnet_port, "disabled") == 0) {
LOG_INFO("telnet server disabled");
return ERROR_OK;
}

struct telnet_service *telnet_service;

telnet_service = malloc(sizeof(struct telnet_service));

if (!telnet_service) {
@@ -635,13 +636,16 @@ int telnet_init(char *banner)

telnet_service->banner = banner;

return add_service("telnet",
telnet_port,
CONNECTION_LIMIT_UNLIMITED,
telnet_new_connection,
telnet_input,
telnet_connection_closed,
ret = add_service("telnet", telnet_port, CONNECTION_LIMIT_UNLIMITED,
telnet_new_connection, telnet_input, telnet_connection_closed,
telnet_service);

if (ret != ERROR_OK) {
free(telnet_service);
return ret;
}

return ERROR_OK;
}

/* daemon configuration command telnet_port */


+ 4
- 2
src/target/Makefile.am View File

@@ -38,7 +38,8 @@ TARGET_CORE_SRC = \
%D%/target.c \
%D%/target_request.c \
%D%/testee.c \
%D%/smp.c
%D%/smp.c \
%D%/rtt.c

ARMV4_5_SRC = \
%D%/armv4_5.c \
@@ -207,6 +208,7 @@ INTEL_IA32_SRC = \
%D%/nds32_aice.h \
%D%/lakemont.h \
%D%/x86_32_common.h \
%D%/arm_cti.h
%D%/arm_cti.h \
%D%/rtt.h

include %D%/openrisc/Makefile.am

+ 1
- 1
src/target/dsp563xx.c View File

@@ -1470,7 +1470,7 @@ static int dsp563xx_get_default_memory(void)
if (!global_cmd_ctx)
return MEM_P;

interp = global_cmd_ctx->interp;
interp = global_cmd_ctx->interp->interp;

if (!interp)
return MEM_P;


+ 412
- 0
src/target/rtt.c View File

@@ -0,0 +1,412 @@
/*
* Copyright (C) 2016-2017 by Marc Schink
* openocd-dev@marcschink.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <stddef.h>
#include <stdint.h>
#include <helper/log.h>
#include <helper/binarybuffer.h>
#include <helper/command.h>
#include <rtt/rtt.h>

#include "target.h"

static uint8_t rtt_buffer[1024];

static int read_rtt_buffer(struct target *target,
const struct rtt_control *ctrl, unsigned int channel,
enum rtt_channel_type type, struct rtt_buffer *buffer)
{
int ret;
uint8_t buf[RTT_BUFFER_LENGTH];
target_addr_t address;

address = ctrl->address + RTT_CB_LENGTH + (channel * RTT_BUFFER_LENGTH);

if (type == RTT_CHANNEL_TYPE_DOWN)
address += ctrl->num_up_buffers * RTT_BUFFER_LENGTH;

ret = target_read_buffer(target, address, RTT_BUFFER_LENGTH, buf);

if (ret != ERROR_OK)
return ret;

buffer->address = address;
buffer->name_addr = buf_get_u32(buf, 0, 32);
buffer->buffer_addr = buf_get_u32(buf + 4, 0, 32);
buffer->size = buf_get_u32(buf + 8, 0, 32);
buffer->write_offset = buf_get_u32(buf + 12, 0, 32);
buffer->read_offset = buf_get_u32(buf + 16, 0, 32);
buffer->flags = buf_get_u32(buf + 20, 0, 32);

return ERROR_OK;
}

int target_rtt_start(const struct rtt_control *ctrl, struct target *target,
void *user_data)
{
return ERROR_OK;
}

int target_rtt_stop(struct target *target, void *user_data)
{
return ERROR_OK;
}

static int read_buffer_name(struct target *target, target_addr_t address,
char *name, size_t length)
{
size_t offset;

offset = 0;

while (offset < length) {
int ret;
size_t tmp;

tmp = MIN(32, length - offset);
ret = target_read_buffer(target, address + offset, tmp,
(uint8_t *)name + offset);

if (ret != ERROR_OK)
return ret;

if (memchr(name + offset, '\0', tmp))
return ERROR_OK;

offset += tmp;
}

name[length - 1] = '\0';

return ERROR_OK;
}

static int write_to_channel(struct target *target,
const struct rtt_buffer *rttbuf, const uint8_t *buffer, size_t *length)
{
int ret;
uint32_t len;

if (!*length)
return ERROR_OK;

if (rttbuf->write_offset == rttbuf->read_offset) {
uint32_t first_length;

len = MIN(*length, rttbuf->size - 1);
first_length = MIN(len, rttbuf->size - rttbuf->write_offset);

ret = target_write_buffer(target,
rttbuf->buffer_addr + rttbuf->write_offset, first_length, buffer);

if (ret != ERROR_OK)
return ret;

ret = target_write_buffer(target, rttbuf->buffer_addr,
len - first_length, buffer + first_length);

if (ret != ERROR_OK)
return ret;
} else if (rttbuf->write_offset < rttbuf->read_offset) {
len = MIN(*length, rttbuf->read_offset - rttbuf->write_offset - 1);

if (!len) {
*length = 0;
return ERROR_OK;
}

ret = target_write_buffer(target,
rttbuf->buffer_addr + rttbuf->write_offset, len, buffer);

if (ret != ERROR_OK)
return ret;
} else {
uint32_t first_length;

len = MIN(*length,
rttbuf->size - rttbuf->write_offset + rttbuf->read_offset - 1);

if (!len) {
*length = 0;
return ERROR_OK;
}

first_length = MIN(len, rttbuf->size - rttbuf->write_offset);

ret = target_write_buffer(target,
rttbuf->buffer_addr + rttbuf->write_offset, first_length, buffer);

if (ret != ERROR_OK)
return ret;

buffer = buffer + first_length;

ret = target_write_buffer(target, rttbuf->buffer_addr,
len - first_length, buffer);

if (ret != ERROR_OK)
return ret;
}

ret = target_write_u32(target, rttbuf->address + 12,
(rttbuf->write_offset + len) % rttbuf->size);

if (ret != ERROR_OK)
return ret;

*length = len;

return ERROR_OK;
}

static bool buffer_is_active(const struct rtt_buffer *buf)
{
if (!buf)
return false;

if (!buf->size)
return false;

return true;
}

int target_rtt_write_callback(struct rtt_control *ctrl,
unsigned int channel, const uint8_t *buffer, size_t *length,
struct target *target, void *user_data)
{
int ret;
struct rtt_buffer rttbuf;

ret = read_rtt_buffer(target, ctrl, channel, RTT_CHANNEL_TYPE_DOWN, &rttbuf);

if (ret != ERROR_OK) {
LOG_ERROR("Failed to read RTT buffer of down-channel %u", channel);
return ret;
}

if (!buffer_is_active(&rttbuf)) {
LOG_WARNING("Down-channel %u is not active", channel);
return ERROR_OK;
}

if (rttbuf.size < RTT_MIN_BUFFER_SIZE) {
LOG_WARNING("Down-channel %u is not large enough", channel);
return ERROR_OK;
}

ret = write_to_channel(target, &rttbuf, buffer, length);

if (ret != ERROR_OK)
return ret;

LOG_DEBUG("Wrote %zu bytes into RTT down-channel %u", *length, channel);

return ERROR_OK;
}

int target_rtt_read_control_block(target_addr_t address,
struct rtt_control *ctrl, struct target *target, void *user_data)
{
int ret;
uint8_t buf[RTT_CB_LENGTH];

ret = target_read_buffer(target, address, RTT_CB_LENGTH, buf);

if (ret != ERROR_OK)
return ret;

memcpy(ctrl->id, buf, RTT_MAX_CB_ID_LENGTH);
ctrl->id[RTT_MAX_CB_ID_LENGTH] = '\0';
ctrl->num_up_buffers = buf_get_u32(buf + RTT_MAX_CB_ID_LENGTH, 0, 32);
ctrl->num_down_buffers = buf_get_u32(buf + RTT_MAX_CB_ID_LENGTH + 4, 0,
32);

return ERROR_OK;
}

int target_rtt_find_control_block(target_addr_t *address, size_t length,
const char *id, size_t id_length, bool *found, struct target *target,
void *user_data)
{
target_addr_t addr;
uint8_t buf[1024];
size_t j;
size_t start;

*found = false;

j = 0;
start = 0;

LOG_INFO("Searching for RTT control block '%s'", id);

for (addr = 0; addr < length; addr = addr + sizeof(buf)) {
int ret;
size_t i;

ret = target_read_buffer(target, *address + addr, sizeof(buf), buf);

if (ret != ERROR_OK)
return ret;

for (i = 0; i < sizeof(buf); i++) {
if (buf[i] == id[j]) {
j++;
} else {
j = 0;
start = addr + i + 1;
}

if (j == id_length) {
*address = *address + start;
*found = true;
return ERROR_OK;
}
}
}

return ERROR_OK;
}

int target_rtt_read_buffer_info(const struct rtt_control *ctrl,
unsigned int channel, enum rtt_channel_type type,
struct rtt_buffer_info *info, struct target *target, void *user_data)
{
int ret;
struct rtt_buffer rttbuf;

ret = read_rtt_buffer(target, ctrl, channel, type, &rttbuf);

if (ret != ERROR_OK) {
LOG_ERROR("Failed to read RTT buffer of channel %u", channel);
return ret;
}

ret = read_buffer_name(target, rttbuf.name_addr, info->name,
info->name_length);

if (ret != ERROR_OK)
return ret;

info->size = rttbuf.size;
info->flags = rttbuf.flags;

return ERROR_OK;
}

static int read_from_channel(struct target *target,
const struct rtt_buffer *rttbuf, uint8_t *buffer, size_t *length)
{
int ret;
uint32_t len;

if (!*length)
return ERROR_OK;

if (rttbuf->read_offset == rttbuf->write_offset) {
len = 0;
} else if (rttbuf->read_offset < rttbuf->write_offset) {
len = MIN(*length, rttbuf->write_offset - rttbuf->read_offset);

ret = target_read_buffer(target,
rttbuf->buffer_addr + rttbuf->read_offset, len, buffer);

if (ret != ERROR_OK)
return ret;
} else {
uint32_t first_length;

len = MIN(*length,
rttbuf->size - rttbuf->read_offset + rttbuf->write_offset);
first_length = MIN(len, rttbuf->size - rttbuf->read_offset);

ret = target_read_buffer(target,
rttbuf->buffer_addr + rttbuf->read_offset, first_length, buffer);

if (ret != ERROR_OK)
return ret;

ret = target_read_buffer(target, rttbuf->buffer_addr,
len - first_length, buffer + first_length);

if (ret != ERROR_OK)
return ret;
}

if (len > 0) {
ret = target_write_u32(target, rttbuf->address + 16,
(rttbuf->read_offset + len) % rttbuf->size);

if (ret != ERROR_OK)
return ret;
}

*length = len;

return ERROR_OK;
}

int target_rtt_read_callback(const struct rtt_control *ctrl,
struct rtt_sink_list **sinks, size_t num_channels,
struct target *target, void *user_data)
{
size_t channel;

num_channels = MIN(num_channels, ctrl->num_up_buffers);

for (channel = 0; channel < num_channels; channel++) {
int ret;
struct rtt_buffer rttbuf;
size_t length;
struct rtt_sink_list *tmp;

if (!sinks[channel])
continue;

ret = read_rtt_buffer(target, ctrl, channel, RTT_CHANNEL_TYPE_UP,
&rttbuf);

if (ret != ERROR_OK) {
LOG_ERROR("Failed to read RTT buffer of up-channel %zu", channel);
return ret;
}

if (!buffer_is_active(&rttbuf)) {
LOG_WARNING("Up-channel %zu is not active", channel);
continue;
}

if (rttbuf.size < RTT_MIN_BUFFER_SIZE) {
LOG_WARNING("Up-channel %zu is not large enough", channel);
continue;
}

length = sizeof(rtt_buffer);
ret = read_from_channel(target, &rttbuf, rtt_buffer, &length);

if (ret != ERROR_OK) {
LOG_ERROR("Failed to read from RTT up-channel %zu", channel);
return ret;
}

for (tmp = sinks[channel]; tmp; tmp = tmp->next)
tmp->read(channel, rtt_buffer, length, tmp->user_data);
}

return ERROR_OK;
}

+ 46
- 0
src/target/rtt.h View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2016-2017 by Marc Schink
* openocd-dev@marcschink.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef OPENOCD_TARGET_RTT_H
#define OPENOCD_TARGET_RTT_H

#include <stdint.h>
#include <stdbool.h>

#include <target/target.h>
#include <rtt/rtt.h>

int target_rtt_start(const struct rtt_control *ctrl, struct target *target,
void *user_data);
int target_rtt_stop(struct target *target, void *user_data);
int target_rtt_find_control_block(target_addr_t *address, size_t length,
const char *id, size_t id_length, bool *found, struct target *target,
void *uer_data);
int target_rtt_read_control_block(target_addr_t address,
struct rtt_control *ctrl, struct target *target, void *user_data);
int target_rtt_write_callback(struct rtt_control *ctrl,
unsigned int channel, const uint8_t *buffer, size_t *length,
struct target *target, void *user_data);
int target_rtt_read_callback(const struct rtt_control *ctrl,
struct rtt_sink_list **sinks, size_t length, struct target *target,
void *user_data);
int target_rtt_read_buffer_info(const struct rtt_control *ctrl,
unsigned int channel, enum rtt_channel_type type,
struct rtt_buffer_info *info, struct target *target, void *user_data);

#endif /* OPENOCD_TARGET_RTT_H */

+ 24
- 8
src/target/target.c View File

@@ -651,13 +651,14 @@ static int target_process_reset(struct command_context *cmd_ctx, enum target_res
jtag_poll_set_enabled(false);

sprintf(buf, "ocd_process_reset %s", n->name);
retval = Jim_Eval(cmd_ctx->interp, buf);
retval = Jim_Eval(cmd_ctx->interp->interp, buf);

jtag_poll_set_enabled(save_poll);

if (retval != JIM_OK) {
Jim_MakeErrorMessage(cmd_ctx->interp);
command_print(NULL, "%s\n", Jim_GetString(Jim_GetResult(cmd_ctx->interp), NULL));
Jim_MakeErrorMessage(cmd_ctx->interp->interp);
command_print(NULL, "%s\n",
Jim_GetString(Jim_GetResult(cmd_ctx->interp->interp), NULL));
return ERROR_FAIL;
}

@@ -1293,7 +1294,7 @@ static int target_init(struct command_context *cmd_ctx)
return retval;

retval = target_register_timer_callback(&handle_target,
polling_interval, 1, cmd_ctx->interp);
polling_interval, 1, cmd_ctx->interp->interp);
if (ERROR_OK != retval)
return retval;

@@ -1870,6 +1871,17 @@ int target_free_working_area(struct target *target, struct working_area *area)
return target_free_working_area_restore(target, area, 1);
}

static void target_destroy(struct target *target)
{
if (target->type->deinit_target)
target->type->deinit_target(target);

free(target->type);
free(target->trace_info);
free(target->cmd_name);
free(target);
}

void target_quit(void)
{
struct target_event_callback *pe = target_event_callbacks;