2008-02-25 11:48:04 -06:00
|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2005 by Dominic Rath *
|
|
|
|
* Dominic.Rath@gmx.de *
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
* This program is distributed in the hope that it will be useful, *
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
* GNU General Public License for more details. *
|
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
* along with this program; if not, write to the *
|
|
|
|
* Free Software Foundation, Inc., *
|
|
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#define OPENOCD_VERSION "Open On-Chip Debugger " VERSION " (" PKGBLDDATE ") svn:" PKGBLDREV
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "log.h"
|
|
|
|
#include "types.h"
|
|
|
|
#include "jtag.h"
|
|
|
|
#include "configuration.h"
|
|
|
|
#include "interpreter.h"
|
|
|
|
#include "xsvf.h"
|
|
|
|
#include "target.h"
|
|
|
|
#include "flash.h"
|
|
|
|
#include "nand.h"
|
|
|
|
#include "pld.h"
|
|
|
|
|
|
|
|
#include "command.h"
|
|
|
|
#include "server.h"
|
|
|
|
#include "telnet_server.h"
|
|
|
|
#include "gdb_server.h"
|
2008-07-06 17:03:07 -05:00
|
|
|
#include "tcl_server.h"
|
2008-02-25 11:48:04 -06:00
|
|
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <strings.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
2008-07-06 18:22:17 -05:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include <malloc.h>
|
|
|
|
#else
|
|
|
|
#include <alloca.h>
|
|
|
|
#endif
|
|
|
|
|
2008-07-06 17:03:07 -05:00
|
|
|
#ifdef __ECOS
|
|
|
|
/* Jim is provied by eCos */
|
|
|
|
#include <cyg/jimtcl/jim.h>
|
|
|
|
#else
|
2008-07-04 01:31:43 -05:00
|
|
|
#define JIM_EMBEDDED
|
|
|
|
#include "jim.h"
|
2008-07-06 17:03:07 -05:00
|
|
|
#endif
|
|
|
|
|
2008-07-06 18:22:17 -05:00
|
|
|
#include "replacements.h"
|
2008-07-06 17:03:07 -05:00
|
|
|
|
|
|
|
int launchTarget(struct command_context_s *cmd_ctx)
|
|
|
|
{
|
|
|
|
int retval;
|
|
|
|
/* Try to examine & validate jtag chain, though this may require a reset first
|
|
|
|
* in which case we continue setup */
|
|
|
|
jtag_init(cmd_ctx);
|
|
|
|
|
|
|
|
/* try to examine target at this point. If it fails, perhaps a reset will
|
|
|
|
* bring it up later on via a telnet/gdb session */
|
|
|
|
target_examine(cmd_ctx);
|
2008-07-04 01:31:43 -05:00
|
|
|
|
2008-07-06 17:03:07 -05:00
|
|
|
retval=flash_init_drivers(cmd_ctx);
|
|
|
|
if (retval!=ERROR_OK)
|
|
|
|
return retval;
|
|
|
|
LOG_DEBUG("flash init complete");
|
|
|
|
|
|
|
|
retval=nand_init(cmd_ctx);
|
|
|
|
if (retval!=ERROR_OK)
|
|
|
|
return retval;
|
|
|
|
LOG_DEBUG("NAND init complete");
|
|
|
|
|
|
|
|
retval=pld_init(cmd_ctx);
|
|
|
|
if (retval!=ERROR_OK)
|
|
|
|
return retval;
|
|
|
|
LOG_DEBUG("pld init complete");
|
|
|
|
return retval;
|
|
|
|
}
|
2008-07-04 01:31:43 -05:00
|
|
|
|
2008-02-25 11:48:04 -06:00
|
|
|
/* Give TELNET a way to find out what version this is */
|
|
|
|
int handle_version_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
|
|
|
{
|
|
|
|
command_print(cmd_ctx, OPENOCD_VERSION);
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2008-04-09 00:50:34 -05:00
|
|
|
static int daemon_startup = 0;
|
|
|
|
|
|
|
|
int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
|
|
|
{
|
|
|
|
if (argc==0)
|
|
|
|
return ERROR_OK;
|
|
|
|
if (argc > 1 )
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
|
|
|
daemon_startup = strcmp("reset", args[0])==0;
|
|
|
|
|
|
|
|
command_print(cmd_ctx, OPENOCD_VERSION);
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2008-02-25 11:48:04 -06:00
|
|
|
void exit_handler(void)
|
|
|
|
{
|
|
|
|
/* close JTAG interface */
|
|
|
|
if (jtag && jtag->quit)
|
|
|
|
jtag->quit();
|
|
|
|
}
|
|
|
|
|
2008-04-09 00:50:34 -05:00
|
|
|
/* OpenOCD can't really handle failure of this command. Patches welcome! :-) */
|
|
|
|
int handle_init_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
|
|
|
{
|
2008-04-13 06:42:49 -05:00
|
|
|
int retval;
|
2008-04-09 00:50:34 -05:00
|
|
|
static int initialized=0;
|
|
|
|
if (initialized)
|
|
|
|
return ERROR_OK;
|
|
|
|
|
|
|
|
initialized=1;
|
|
|
|
|
|
|
|
command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);
|
|
|
|
|
|
|
|
atexit(exit_handler);
|
2008-04-13 06:42:49 -05:00
|
|
|
|
2008-04-09 00:50:34 -05:00
|
|
|
if (target_init(cmd_ctx) != ERROR_OK)
|
|
|
|
return ERROR_FAIL;
|
|
|
|
LOG_DEBUG("target init complete");
|
|
|
|
|
2008-04-13 06:42:49 -05:00
|
|
|
if ((retval=jtag_interface_init(cmd_ctx)) != ERROR_OK)
|
|
|
|
{
|
|
|
|
/* we must be able to set up the jtag interface */
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
LOG_DEBUG("jtag interface init complete");
|
|
|
|
|
|
|
|
/* Try to initialize & examine the JTAG chain at this point, but
|
2008-07-08 03:55:53 -05:00
|
|
|
* continue startup regardless */
|
2008-04-13 06:42:49 -05:00
|
|
|
if (jtag_init(cmd_ctx) == ERROR_OK)
|
|
|
|
{
|
|
|
|
LOG_DEBUG("jtag init complete");
|
|
|
|
if (target_examine(cmd_ctx) == ERROR_OK)
|
|
|
|
{
|
|
|
|
LOG_DEBUG("jtag examine complete");
|
|
|
|
}
|
|
|
|
}
|
2008-04-11 01:52:52 -05:00
|
|
|
|
2008-04-09 00:50:34 -05:00
|
|
|
if (flash_init_drivers(cmd_ctx) != ERROR_OK)
|
|
|
|
return ERROR_FAIL;
|
|
|
|
LOG_DEBUG("flash init complete");
|
|
|
|
|
|
|
|
if (nand_init(cmd_ctx) != ERROR_OK)
|
|
|
|
return ERROR_FAIL;
|
|
|
|
LOG_DEBUG("NAND init complete");
|
|
|
|
|
|
|
|
if (pld_init(cmd_ctx) != ERROR_OK)
|
|
|
|
return ERROR_FAIL;
|
|
|
|
LOG_DEBUG("pld init complete");
|
|
|
|
|
|
|
|
/* initialize tcp server */
|
|
|
|
server_init();
|
|
|
|
|
|
|
|
/* initialize telnet subsystem */
|
|
|
|
telnet_init("Open On-Chip Debugger");
|
|
|
|
gdb_init();
|
2008-07-06 14:33:05 -05:00
|
|
|
tcl_init(); /* allows tcl to just connect without going thru telnet */
|
2008-04-09 00:50:34 -05:00
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2008-07-04 01:31:43 -05:00
|
|
|
Jim_Interp *interp;
|
|
|
|
command_context_t *active_cmd_ctx;
|
|
|
|
|
2008-07-06 18:22:17 -05:00
|
|
|
static int new_int_array_element(Jim_Interp * interp, const char *varname, int idx, u32 val)
|
2008-07-06 14:17:43 -05:00
|
|
|
{
|
|
|
|
char *namebuf;
|
|
|
|
Jim_Obj *nameObjPtr, *valObjPtr;
|
|
|
|
int result;
|
|
|
|
|
2008-07-08 03:55:53 -05:00
|
|
|
namebuf = alloc_printf("%s(%d)", varname, idx);
|
|
|
|
|
|
|
|
nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
|
|
|
|
valObjPtr = Jim_NewIntObj(interp, val);
|
|
|
|
Jim_IncrRefCount(nameObjPtr);
|
|
|
|
Jim_IncrRefCount(valObjPtr);
|
|
|
|
result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
|
|
|
|
Jim_DecrRefCount(interp, nameObjPtr);
|
|
|
|
Jim_DecrRefCount(interp, valObjPtr);
|
|
|
|
free(namebuf);
|
|
|
|
/* printf( "%s = 0%08x\n", namebuf, val ); */
|
|
|
|
return result;
|
2008-07-06 14:17:43 -05:00
|
|
|
}
|
|
|
|
|
2008-07-06 18:22:17 -05:00
|
|
|
static int Jim_Command_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
2008-07-06 14:17:43 -05:00
|
|
|
{
|
|
|
|
target_t *target;
|
|
|
|
long l;
|
|
|
|
u32 width;
|
|
|
|
u32 len;
|
|
|
|
u32 addr;
|
|
|
|
u32 count;
|
|
|
|
u32 v;
|
|
|
|
const char *varname;
|
|
|
|
u8 buffer[4096];
|
2008-07-08 03:55:53 -05:00
|
|
|
int i, n, e, retval;
|
2008-07-06 14:17:43 -05:00
|
|
|
|
|
|
|
/* argv[1] = name of array to receive the data
|
|
|
|
* argv[2] = desired width
|
|
|
|
* argv[3] = memory address
|
|
|
|
* argv[4] = length in bytes to read
|
|
|
|
*/
|
2008-07-08 03:55:53 -05:00
|
|
|
if (argc != 5) {
|
|
|
|
Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems");
|
2008-07-06 14:17:43 -05:00
|
|
|
return JIM_ERR;
|
|
|
|
}
|
2008-07-08 03:55:53 -05:00
|
|
|
varname = Jim_GetString(argv[1], &len);
|
2008-07-06 14:17:43 -05:00
|
|
|
/* given "foo" get space for worse case "foo(%d)" .. add 20 */
|
|
|
|
|
2008-07-08 03:55:53 -05:00
|
|
|
e = Jim_GetLong(interp, argv[2], &l);
|
2008-07-06 14:17:43 -05:00
|
|
|
width = l;
|
2008-07-08 03:55:53 -05:00
|
|
|
if (e != JIM_OK) {
|
2008-07-06 14:17:43 -05:00
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
2008-07-08 03:55:53 -05:00
|
|
|
e = Jim_GetLong(interp, argv[3], &l);
|
2008-07-06 14:17:43 -05:00
|
|
|
addr = l;
|
2008-07-08 03:55:53 -05:00
|
|
|
if (e != JIM_OK) {
|
2008-07-06 14:17:43 -05:00
|
|
|
return e;
|
|
|
|
}
|
2008-07-08 03:55:53 -05:00
|
|
|
e = Jim_GetLong(interp, argv[4], &l);
|
2008-07-06 14:17:43 -05:00
|
|
|
len = l;
|
2008-07-08 03:55:53 -05:00
|
|
|
if (e != JIM_OK) {
|
2008-07-06 14:17:43 -05:00
|
|
|
return e;
|
|
|
|
}
|
2008-07-08 03:55:53 -05:00
|
|
|
switch (width) {
|
|
|
|
case 8:
|
|
|
|
width = 1;
|
|
|
|
break;
|
|
|
|
case 16:
|
|
|
|
width = 2;
|
|
|
|
break;
|
|
|
|
case 32:
|
|
|
|
width = 4;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
|
|
|
|
Jim_AppendStrings( interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL );
|
|
|
|
return JIM_ERR;
|
2008-07-06 14:17:43 -05:00
|
|
|
}
|
2008-07-08 03:55:53 -05:00
|
|
|
if (len == 0) {
|
|
|
|
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
|
|
|
|
Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: zero width read?", NULL);
|
2008-07-06 14:17:43 -05:00
|
|
|
return JIM_ERR;
|
|
|
|
}
|
2008-07-08 03:55:53 -05:00
|
|
|
if ((addr + (len * width)) < addr) {
|
|
|
|
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
|
|
|
|
Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: addr + len - wraps to zero?", NULL);
|
2008-07-06 14:17:43 -05:00
|
|
|
return JIM_ERR;
|
|
|
|
}
|
|
|
|
/* absurd transfer size? */
|
2008-07-08 03:55:53 -05:00
|
|
|
if (len > 65536) {
|
|
|
|
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
|
|
|
|
Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: absurd > 64K item request", NULL);
|
2008-07-06 14:17:43 -05:00
|
|
|
return JIM_ERR;
|
|
|
|
}
|
|
|
|
|
2008-07-08 03:55:53 -05:00
|
|
|
if ((width == 1) ||
|
2008-07-06 14:17:43 -05:00
|
|
|
((width == 2) && ((addr & 1) == 0)) ||
|
2008-07-08 03:55:53 -05:00
|
|
|
((width == 4) && ((addr & 3) == 0))) {
|
2008-07-06 14:17:43 -05:00
|
|
|
/* all is well */
|
|
|
|
} else {
|
|
|
|
char buf[100];
|
2008-07-08 03:55:53 -05:00
|
|
|
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
|
|
|
|
sprintf(buf, "mem2array address: 0x%08x is not aligned for %d byte reads", addr, width);
|
|
|
|
Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL);
|
2008-07-06 14:17:43 -05:00
|
|
|
return JIM_ERR;
|
|
|
|
}
|
|
|
|
|
2008-07-08 03:55:53 -05:00
|
|
|
target = get_current_target(active_cmd_ctx);
|
2008-07-06 14:17:43 -05:00
|
|
|
|
|
|
|
/* Transfer loop */
|
|
|
|
|
|
|
|
/* index counter */
|
|
|
|
n = 0;
|
|
|
|
/* assume ok */
|
|
|
|
e = JIM_OK;
|
2008-07-08 03:55:53 -05:00
|
|
|
while (len) {
|
2008-07-06 14:17:43 -05:00
|
|
|
/* Slurp... in buffer size chunks */
|
|
|
|
|
|
|
|
count = len; /* in objects.. */
|
2008-07-08 03:55:53 -05:00
|
|
|
if (count > (sizeof(buffer)/width)) {
|
2008-07-06 14:17:43 -05:00
|
|
|
count = (sizeof(buffer)/width);
|
|
|
|
}
|
|
|
|
|
2008-07-08 03:55:53 -05:00
|
|
|
retval = target->type->read_memory( target, addr, width, count, buffer );
|
2008-07-06 14:17:43 -05:00
|
|
|
|
2008-07-08 03:55:53 -05:00
|
|
|
if (retval != ERROR_OK) {
|
2008-07-06 14:17:43 -05:00
|
|
|
/* BOO !*/
|
2008-07-08 03:55:53 -05:00
|
|
|
LOG_ERROR("mem2array: Read @ 0x%08x, w=%d, cnt=%d, failed", addr, width, count);
|
|
|
|
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
|
|
|
|
Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL);
|
2008-07-06 14:17:43 -05:00
|
|
|
e = JIM_ERR;
|
|
|
|
len = 0;
|
|
|
|
} else {
|
|
|
|
v = 0; /* shut up gcc */
|
2008-07-08 03:55:53 -05:00
|
|
|
for (i = 0 ;i < count ;i++, n++) {
|
|
|
|
switch (width) {
|
|
|
|
case 4:
|
|
|
|
v = target_buffer_get_u32(target, &buffer[i*width]);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
v = target_buffer_get_u16(target, &buffer[i*width]);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
v = buffer[i] & 0x0ff;
|
|
|
|
break;
|
2008-07-06 14:17:43 -05:00
|
|
|
}
|
2008-07-08 03:55:53 -05:00
|
|
|
new_int_array_element(interp, varname, n, v);
|
2008-07-06 14:17:43 -05:00
|
|
|
}
|
|
|
|
len -= count;
|
|
|
|
}
|
|
|
|
}
|
2008-07-08 03:55:53 -05:00
|
|
|
|
|
|
|
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
|
2008-07-06 14:17:43 -05:00
|
|
|
|
|
|
|
return JIM_OK;
|
|
|
|
}
|
|
|
|
|
2008-07-06 18:22:17 -05:00
|
|
|
static void tcl_output(void *privData, const char *file, int line, const char *function, const char *string)
|
2008-07-04 01:31:43 -05:00
|
|
|
{
|
|
|
|
Jim_Obj *tclOutput=(Jim_Obj *)privData;
|
|
|
|
|
|
|
|
Jim_AppendString(interp, tclOutput, string, strlen(string));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* try to execute as Jim command, otherwise fall back to standard command.
|
2008-07-08 03:55:53 -05:00
|
|
|
* Note that even if the Jim command caused an error, then we succeeded
|
|
|
|
* to execute it, hence this fn pretty much always returns ERROR_OK. */
|
2008-06-27 01:58:45 -05:00
|
|
|
int jim_command(command_context_t *context, char *line)
|
|
|
|
{
|
2008-07-04 01:31:43 -05:00
|
|
|
int retval=ERROR_OK;
|
|
|
|
int retcode=Jim_Eval(interp, line);
|
|
|
|
|
|
|
|
const char *result;
|
|
|
|
int reslen;
|
2008-07-08 03:55:53 -05:00
|
|
|
result = Jim_GetString(Jim_GetResult(interp), &reslen);
|
|
|
|
if (retcode == JIM_ERR) {
|
|
|
|
int len, i;
|
|
|
|
|
|
|
|
LOG_USER_N("Runtime error, file \"%s\", line %d:" JIM_NL, interp->errorFileName, interp->errorLine);
|
|
|
|
LOG_USER_N(" %s" JIM_NL,
|
|
|
|
Jim_GetString(interp->result, NULL));
|
|
|
|
Jim_ListLength(interp, interp->stackTrace, &len);
|
|
|
|
for (i = 0; i < len; i += 3) {
|
|
|
|
Jim_Obj *objPtr;
|
|
|
|
const char *proc, *file, *line;
|
|
|
|
|
|
|
|
Jim_ListIndex(interp, interp->stackTrace, i, &objPtr, JIM_NONE);
|
|
|
|
proc = Jim_GetString(objPtr, NULL);
|
|
|
|
Jim_ListIndex(interp, interp->stackTrace, i+1, &objPtr, JIM_NONE);
|
|
|
|
file = Jim_GetString(objPtr, NULL);
|
|
|
|
Jim_ListIndex(interp, interp->stackTrace, i+2, &objPtr, JIM_NONE);
|
|
|
|
line = Jim_GetString(objPtr, NULL);
|
|
|
|
LOG_USER_N("In procedure '%s' called at file \"%s\", line %s" JIM_NL, proc, file, line);
|
2008-07-04 01:31:43 -05:00
|
|
|
}
|
2008-07-09 10:22:05 -05:00
|
|
|
long t;
|
|
|
|
if (Jim_GetLong(interp, Jim_GetVariableStr(interp, "openocd_result", JIM_ERRMSG), &t)==JIM_OK)
|
|
|
|
{
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
return ERROR_FAIL;
|
2008-07-08 03:55:53 -05:00
|
|
|
} else if (retcode == JIM_EXIT) {
|
|
|
|
/* ignore. */
|
|
|
|
/* exit(Jim_GetExitCode(interp)); */
|
|
|
|
} else {
|
|
|
|
if (reslen) {
|
|
|
|
int i;
|
|
|
|
char buff[256+1];
|
|
|
|
for (i = 0; i < reslen; i += 256)
|
|
|
|
{
|
|
|
|
int chunk;
|
|
|
|
chunk = reslen - i;
|
|
|
|
if (chunk > 256)
|
|
|
|
chunk = 256;
|
2008-07-08 11:05:59 -05:00
|
|
|
strncpy(buff, result+i, chunk);
|
2008-07-08 03:55:53 -05:00
|
|
|
buff[chunk] = 0;
|
|
|
|
LOG_USER_N("%s", buff);
|
|
|
|
}
|
|
|
|
LOG_USER_N("%s", "\n");
|
|
|
|
}
|
|
|
|
}
|
2008-07-04 01:31:43 -05:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2008-07-08 03:55:53 -05:00
|
|
|
int startLoop = 0;
|
2008-07-04 01:31:43 -05:00
|
|
|
|
2008-07-06 18:22:17 -05:00
|
|
|
static int Jim_Command_openocd_ignore(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int ignore)
|
2008-07-04 01:31:43 -05:00
|
|
|
{
|
|
|
|
int retval;
|
2008-07-08 03:55:53 -05:00
|
|
|
char *cmd = (char*)Jim_GetString(argv[1], NULL);
|
|
|
|
|
|
|
|
Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
|
|
|
|
|
|
|
|
if (startLoop)
|
|
|
|
{
|
|
|
|
/* We don't know whether or not the telnet/gdb server is running... */
|
|
|
|
target_call_timer_callbacks_now();
|
|
|
|
}
|
2008-07-04 01:31:43 -05:00
|
|
|
|
|
|
|
log_add_callback(tcl_output, tclOutput);
|
2008-07-08 03:55:53 -05:00
|
|
|
retval=command_run_line_internal(active_cmd_ctx, cmd);
|
2008-07-09 10:22:05 -05:00
|
|
|
|
|
|
|
/* we need to be able to get at the retval, so we store in a variable
|
|
|
|
*/
|
|
|
|
Jim_Obj *resultvar=Jim_NewIntObj(interp, retval);
|
|
|
|
Jim_IncrRefCount(resultvar);
|
|
|
|
Jim_SetGlobalVariableStr(interp, "openocd_result", resultvar);
|
|
|
|
Jim_DecrRefCount(interp, resultvar);
|
2008-07-08 03:55:53 -05:00
|
|
|
|
|
|
|
if (startLoop)
|
|
|
|
{
|
|
|
|
target_call_timer_callbacks_now();
|
|
|
|
}
|
2008-07-04 01:31:43 -05:00
|
|
|
log_remove_callback(tcl_output, tclOutput);
|
2008-07-08 03:55:53 -05:00
|
|
|
|
2008-07-04 01:31:43 -05:00
|
|
|
Jim_SetResult(interp, tclOutput);
|
2008-07-08 03:55:53 -05:00
|
|
|
|
|
|
|
return (ignore||(retval==ERROR_OK))?JIM_OK:JIM_ERR;
|
2008-07-04 01:31:43 -05:00
|
|
|
}
|
|
|
|
|
2008-07-06 18:22:17 -05:00
|
|
|
static int Jim_Command_openocd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
2008-07-04 01:31:43 -05:00
|
|
|
{
|
|
|
|
return Jim_Command_openocd_ignore(interp, argc, argv, 1);
|
|
|
|
}
|
|
|
|
|
2008-07-06 18:22:17 -05:00
|
|
|
static int Jim_Command_openocd_throw(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
2008-07-04 01:31:43 -05:00
|
|
|
{
|
|
|
|
return Jim_Command_openocd_ignore(interp, argc, argv, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find full path to file */
|
2008-07-06 18:22:17 -05:00
|
|
|
static int Jim_Command_find(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
2008-07-04 01:31:43 -05:00
|
|
|
{
|
2008-07-08 03:55:53 -05:00
|
|
|
if (argc != 2)
|
2008-07-04 01:31:43 -05:00
|
|
|
return JIM_ERR;
|
|
|
|
char *file = (char*)Jim_GetString(argv[1], NULL);
|
2008-07-08 03:55:53 -05:00
|
|
|
char *full_path = find_file(file);
|
|
|
|
if (full_path == NULL)
|
2008-07-04 01:31:43 -05:00
|
|
|
return JIM_ERR;
|
2008-07-08 03:55:53 -05:00
|
|
|
Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path));
|
|
|
|
free(full_path);
|
|
|
|
|
2008-07-04 01:31:43 -05:00
|
|
|
Jim_SetResult(interp, result);
|
|
|
|
return JIM_OK;
|
|
|
|
}
|
|
|
|
|
2008-07-06 18:22:17 -05:00
|
|
|
static int Jim_Command_echo(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
2008-07-04 08:37:34 -05:00
|
|
|
{
|
2008-07-08 03:55:53 -05:00
|
|
|
if (argc != 2)
|
2008-07-04 08:37:34 -05:00
|
|
|
return JIM_ERR;
|
|
|
|
char *str = (char*)Jim_GetString(argv[1], NULL);
|
|
|
|
LOG_USER("%s", str);
|
|
|
|
return JIM_OK;
|
|
|
|
}
|
2008-07-04 01:31:43 -05:00
|
|
|
|
2008-07-06 18:22:17 -05:00
|
|
|
static size_t openocd_jim_fwrite(const void *_ptr, size_t size, size_t n, void *cookie)
|
2008-07-06 14:17:43 -05:00
|
|
|
{
|
|
|
|
size_t nbytes;
|
|
|
|
const char *ptr;
|
|
|
|
|
|
|
|
/* make it a char easier to read code */
|
|
|
|
ptr = _ptr;
|
|
|
|
|
|
|
|
nbytes = size * n;
|
2008-07-08 03:55:53 -05:00
|
|
|
if (nbytes == 0) {
|
2008-07-06 14:17:43 -05:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-07-08 03:55:53 -05:00
|
|
|
if (!active_cmd_ctx) {
|
|
|
|
/* TODO: Where should this go? */
|
2008-07-06 14:17:43 -05:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* do we have to chunk it? */
|
2008-07-08 03:55:53 -05:00
|
|
|
if (ptr[nbytes] == 0) {
|
2008-07-06 14:17:43 -05:00
|
|
|
/* no it is a C style string */
|
2008-07-08 03:55:53 -05:00
|
|
|
command_output_text(active_cmd_ctx, ptr);
|
2008-07-06 17:03:07 -05:00
|
|
|
return strlen(ptr);
|
2008-07-06 14:17:43 -05:00
|
|
|
}
|
|
|
|
/* GRR we must chunk - not null terminated */
|
2008-07-08 03:55:53 -05:00
|
|
|
while (nbytes) {
|
2008-07-06 14:17:43 -05:00
|
|
|
char chunk[128+1];
|
|
|
|
int x;
|
|
|
|
|
|
|
|
x = nbytes;
|
2008-07-08 03:55:53 -05:00
|
|
|
if (x > 128) {
|
2008-07-06 14:17:43 -05:00
|
|
|
x = 128;
|
|
|
|
}
|
|
|
|
/* copy it */
|
2008-07-08 03:55:53 -05:00
|
|
|
memcpy(chunk, ptr, x);
|
2008-07-06 14:17:43 -05:00
|
|
|
/* terminate it */
|
|
|
|
chunk[n] = 0;
|
|
|
|
/* output it */
|
2008-07-08 03:55:53 -05:00
|
|
|
command_output_text(active_cmd_ctx, chunk);
|
2008-07-06 14:17:43 -05:00
|
|
|
ptr += x;
|
|
|
|
nbytes -= x;
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2008-07-06 18:22:17 -05:00
|
|
|
static size_t openocd_jim_fread(void *ptr, size_t size, size_t n, void *cookie )
|
2008-07-06 14:17:43 -05:00
|
|
|
{
|
|
|
|
/* TCL wants to read... tell him no */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-07-06 18:22:17 -05:00
|
|
|
static int openocd_jim_vfprintf(void *cookie, const char *fmt, va_list ap)
|
2008-07-06 14:17:43 -05:00
|
|
|
{
|
|
|
|
char *cp;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
n = -1;
|
2008-07-08 03:55:53 -05:00
|
|
|
if (active_cmd_ctx) {
|
|
|
|
cp = alloc_vprintf(fmt, ap);
|
|
|
|
if (cp) {
|
|
|
|
command_output_text(active_cmd_ctx, cp);
|
2008-07-06 14:17:43 -05:00
|
|
|
n = strlen(cp);
|
|
|
|
free(cp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2008-07-06 18:22:17 -05:00
|
|
|
static int openocd_jim_fflush(void *cookie)
|
2008-07-06 14:17:43 -05:00
|
|
|
{
|
|
|
|
/* nothing to flush */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-07-06 18:22:17 -05:00
|
|
|
static char* openocd_jim_fgets(char *s, int size, void *cookie)
|
2008-07-06 14:17:43 -05:00
|
|
|
{
|
|
|
|
/* not supported */
|
|
|
|
errno = ENOTSUP;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-07-04 01:31:43 -05:00
|
|
|
void initJim(void)
|
|
|
|
{
|
2008-07-08 03:55:53 -05:00
|
|
|
Jim_CreateCommand(interp, "openocd", Jim_Command_openocd, NULL, NULL);
|
|
|
|
Jim_CreateCommand(interp, "openocd_throw", Jim_Command_openocd_throw, NULL, NULL);
|
|
|
|
Jim_CreateCommand(interp, "find", Jim_Command_find, NULL, NULL);
|
|
|
|
Jim_CreateCommand(interp, "echo", Jim_Command_echo, NULL, NULL);
|
|
|
|
Jim_CreateCommand(interp, "mem2array", Jim_Command_mem2array, NULL, NULL );
|
|
|
|
|
2008-07-06 14:17:43 -05:00
|
|
|
/* Set Jim's STDIO */
|
2008-07-08 03:55:53 -05:00
|
|
|
interp->cookie_stdin = NULL;
|
2008-07-06 14:17:43 -05:00
|
|
|
interp->cookie_stdout = NULL;
|
|
|
|
interp->cookie_stderr = NULL;
|
2008-07-08 03:55:53 -05:00
|
|
|
interp->cb_fwrite = openocd_jim_fwrite;
|
|
|
|
interp->cb_fread = openocd_jim_fread ;
|
|
|
|
interp->cb_vfprintf = openocd_jim_vfprintf;
|
|
|
|
interp->cb_fflush = openocd_jim_fflush;
|
|
|
|
interp->cb_fgets = openocd_jim_fgets;
|
2008-06-27 01:58:45 -05:00
|
|
|
}
|
2008-03-26 08:18:23 -05:00
|
|
|
|
2008-07-06 17:03:07 -05:00
|
|
|
/* after command line parsing */
|
|
|
|
void initJim2(void)
|
2008-02-25 11:48:04 -06:00
|
|
|
{
|
2008-07-06 17:03:07 -05:00
|
|
|
Jim_Eval(interp, "source [find tcl/commands.tcl]");
|
|
|
|
}
|
|
|
|
|
2008-07-08 03:55:53 -05:00
|
|
|
command_context_t *setup_command_handler(void)
|
2008-07-06 17:03:07 -05:00
|
|
|
{
|
|
|
|
command_context_t *cmd_ctx;
|
2008-07-04 01:31:43 -05:00
|
|
|
|
2008-02-25 11:48:04 -06:00
|
|
|
cmd_ctx = command_init();
|
|
|
|
|
|
|
|
register_command(cmd_ctx, NULL, "version", handle_version_command,
|
|
|
|
COMMAND_EXEC, "show OpenOCD version");
|
2008-04-09 00:50:34 -05:00
|
|
|
register_command(cmd_ctx, NULL, "daemon_startup", handle_daemon_startup_command, COMMAND_CONFIG,
|
|
|
|
"deprecated - use \"init\" and \"reset\" at end of startup script instead");
|
|
|
|
|
2008-02-25 11:48:04 -06:00
|
|
|
/* register subsystem commands */
|
|
|
|
server_register_commands(cmd_ctx);
|
|
|
|
telnet_register_commands(cmd_ctx);
|
|
|
|
gdb_register_commands(cmd_ctx);
|
2008-07-06 14:33:05 -05:00
|
|
|
tcl_register_commands(cmd_ctx); /* tcl server commands */
|
2008-02-25 11:48:04 -06:00
|
|
|
log_register_commands(cmd_ctx);
|
|
|
|
jtag_register_commands(cmd_ctx);
|
|
|
|
interpreter_register_commands(cmd_ctx);
|
|
|
|
xsvf_register_commands(cmd_ctx);
|
|
|
|
target_register_commands(cmd_ctx);
|
|
|
|
flash_register_commands(cmd_ctx);
|
|
|
|
nand_register_commands(cmd_ctx);
|
|
|
|
pld_register_commands(cmd_ctx);
|
|
|
|
|
|
|
|
if (log_init(cmd_ctx) != ERROR_OK)
|
2008-07-06 17:03:07 -05:00
|
|
|
{
|
|
|
|
exit(-1);
|
|
|
|
}
|
2008-03-25 10:45:17 -05:00
|
|
|
LOG_DEBUG("log init complete");
|
2008-07-04 01:31:43 -05:00
|
|
|
|
2008-03-25 10:45:17 -05:00
|
|
|
LOG_OUTPUT( OPENOCD_VERSION "\n" );
|
2008-04-06 14:59:32 -05:00
|
|
|
|
|
|
|
|
2008-04-09 00:50:34 -05:00
|
|
|
register_command(cmd_ctx, NULL, "init", handle_init_command,
|
|
|
|
COMMAND_ANY, "initializes target and servers - nop on subsequent invocations");
|
|
|
|
|
2008-07-06 17:03:07 -05:00
|
|
|
return cmd_ctx;
|
|
|
|
}
|
|
|
|
|
2008-07-08 03:55:53 -05:00
|
|
|
/* normally this is the main() function entry, but if OpenOCD is linked
|
|
|
|
* into application, then this fn will not be invoked, but rather that
|
|
|
|
* application will have it's own implementation of main(). */
|
2008-07-06 17:03:07 -05:00
|
|
|
int openocd_main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
#ifdef JIM_EMBEDDED
|
|
|
|
Jim_InitEmbedded();
|
2008-07-08 03:55:53 -05:00
|
|
|
/* Create an interpreter */
|
|
|
|
interp = Jim_CreateInterp();
|
|
|
|
/* Add all the Jim core commands */
|
|
|
|
Jim_RegisterCoreCommands(interp);
|
2008-07-06 17:03:07 -05:00
|
|
|
#endif
|
2008-07-08 03:55:53 -05:00
|
|
|
|
2008-07-06 17:03:07 -05:00
|
|
|
initJim();
|
|
|
|
|
|
|
|
/* initialize commandline interface */
|
|
|
|
command_context_t *cmd_ctx;
|
|
|
|
cmd_ctx=setup_command_handler();
|
|
|
|
|
2008-07-08 11:05:59 -05:00
|
|
|
/* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
|
|
|
|
/* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
|
|
|
|
/* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
|
|
|
|
/* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
|
|
|
|
/* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
|
|
|
|
LOG_OUTPUT( "$URL$\n");
|
|
|
|
/* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
|
|
|
|
/* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
|
|
|
|
/* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
|
|
|
|
/* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
|
|
|
|
/* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
|
|
|
|
|
2008-07-06 17:03:07 -05:00
|
|
|
command_context_t *cfg_cmd_ctx;
|
2008-02-25 11:48:04 -06:00
|
|
|
cfg_cmd_ctx = copy_command_context(cmd_ctx);
|
|
|
|
cfg_cmd_ctx->mode = COMMAND_CONFIG;
|
|
|
|
command_set_output_handler(cfg_cmd_ctx, configuration_output_handler, NULL);
|
|
|
|
|
2008-07-07 15:02:51 -05:00
|
|
|
active_cmd_ctx=cfg_cmd_ctx;
|
|
|
|
|
2008-02-25 11:48:04 -06:00
|
|
|
if (parse_cmdline_args(cfg_cmd_ctx, argc, argv) != ERROR_OK)
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
2008-07-06 17:03:07 -05:00
|
|
|
initJim2();
|
2008-07-04 01:31:43 -05:00
|
|
|
|
2008-02-25 11:48:04 -06:00
|
|
|
if (parse_config_file(cfg_cmd_ctx) != ERROR_OK)
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
2008-07-07 15:02:51 -05:00
|
|
|
active_cmd_ctx=cmd_ctx;
|
|
|
|
|
2008-02-25 11:48:04 -06:00
|
|
|
command_done(cfg_cmd_ctx);
|
|
|
|
|
2008-04-09 00:50:34 -05:00
|
|
|
if (command_run_line(cmd_ctx, "init")!=ERROR_OK)
|
2008-02-25 11:48:04 -06:00
|
|
|
return EXIT_FAILURE;
|
2008-04-09 00:50:34 -05:00
|
|
|
|
|
|
|
if (daemon_startup)
|
|
|
|
command_run_line(cmd_ctx, "reset");
|
2008-07-06 18:22:17 -05:00
|
|
|
|
2008-07-04 01:31:43 -05:00
|
|
|
startLoop=1;
|
|
|
|
|
2008-02-25 11:48:04 -06:00
|
|
|
/* handle network connections */
|
|
|
|
server_loop(cmd_ctx);
|
|
|
|
|
|
|
|
/* shut server down */
|
|
|
|
server_quit();
|
|
|
|
|
2008-05-07 07:15:19 -05:00
|
|
|
unregister_all_commands(cmd_ctx);
|
|
|
|
|
2008-02-25 11:48:04 -06:00
|
|
|
/* free commandline interface */
|
|
|
|
command_done(cmd_ctx);
|
|
|
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|