fix a few compilation problems.
[fw/openocd] / src / openocd.c
1 /***************************************************************************
2  *   Copyright (C) 2005 by Dominic Rath                                    *
3  *   Dominic.Rath@gmx.de                                                   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #define OPENOCD_VERSION "Open On-Chip Debugger " VERSION " (" PKGBLDDATE ") svn:" PKGBLDREV
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "log.h"
28 #include "types.h"
29 #include "jtag.h"
30 #include "configuration.h"
31 #include "interpreter.h"
32 #include "xsvf.h"
33 #include "target.h"
34 #include "flash.h"
35 #include "nand.h"
36 #include "pld.h"
37
38 #include "command.h"
39 #include "server.h"
40 #include "telnet_server.h"
41 #include "gdb_server.h"
42
43 #include <sys/time.h>
44 #include <sys/types.h>
45 #include <strings.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50 #include <errno.h>
51
52 #define JIM_EMBEDDED
53 #include "jim.h"
54
55
56 /* Give TELNET a way to find out what version this is */
57 int handle_version_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
58 {
59         command_print(cmd_ctx, OPENOCD_VERSION);
60
61         return ERROR_OK;
62 }
63
64 static int daemon_startup = 0;
65
66 int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
67 {
68         if (argc==0)
69                 return ERROR_OK;
70         if (argc > 1 )
71                 return ERROR_COMMAND_SYNTAX_ERROR;
72         
73         daemon_startup = strcmp("reset", args[0])==0;
74         
75         command_print(cmd_ctx, OPENOCD_VERSION);
76
77         return ERROR_OK;
78 }
79
80
81 void exit_handler(void)
82 {
83         /* close JTAG interface */
84         if (jtag && jtag->quit)
85                 jtag->quit();
86 }
87
88
89 /* OpenOCD can't really handle failure of this command. Patches welcome! :-) */
90 int handle_init_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
91 {
92         int retval;
93         static int initialized=0;
94         if (initialized)
95                 return ERROR_OK;
96         
97         initialized=1;
98         
99         command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);
100
101         atexit(exit_handler);
102
103         
104         if (target_init(cmd_ctx) != ERROR_OK)
105                 return ERROR_FAIL;
106         LOG_DEBUG("target init complete");
107
108         if ((retval=jtag_interface_init(cmd_ctx)) != ERROR_OK)
109         {
110                 /* we must be able to set up the jtag interface */
111                 return retval;
112         }
113         LOG_DEBUG("jtag interface init complete");
114
115         /* Try to initialize & examine the JTAG chain at this point, but
116          * continue startup regardless
117          */
118         if (jtag_init(cmd_ctx) == ERROR_OK)
119         {
120                 LOG_DEBUG("jtag init complete");
121                 if (target_examine(cmd_ctx) == ERROR_OK)
122                 {
123                         LOG_DEBUG("jtag examine complete");
124                 }
125         }
126
127         
128         if (flash_init_drivers(cmd_ctx) != ERROR_OK)
129                 return ERROR_FAIL;
130         LOG_DEBUG("flash init complete");
131
132         if (nand_init(cmd_ctx) != ERROR_OK)
133                 return ERROR_FAIL;
134         LOG_DEBUG("NAND init complete");
135
136         if (pld_init(cmd_ctx) != ERROR_OK)
137                 return ERROR_FAIL;
138         LOG_DEBUG("pld init complete");
139
140         /* initialize tcp server */
141         server_init();
142
143         /* initialize telnet subsystem */
144         telnet_init("Open On-Chip Debugger");
145         gdb_init();
146         tcl_init(); /* allows tcl to just connect without going thru telnet */
147
148         return ERROR_OK;
149 }
150
151
152 /* implementations of OpenOCD that uses multithreading needs to lock OpenOCD while calling
153  * OpenOCD fn's. No-op in vanilla OpenOCD
154  */
155 void lockBigLock()
156 {
157 }
158 void unlockBigLock()
159 {
160 }
161
162
163
164
165
166 Jim_Interp *interp;
167 command_context_t *active_cmd_ctx;
168
169 static int
170 new_int_array_element( Jim_Interp * interp, 
171                                            const char *varname, 
172                                            int idx, 
173                                            u32 val )
174 {
175         char *namebuf;
176         Jim_Obj *nameObjPtr, *valObjPtr;
177         int result;
178
179         namebuf = alloca( strlen(varname) + 30 );
180         sprintf( namebuf, "%s(%d)", varname, idx );
181
182
183     nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
184     valObjPtr = Jim_NewIntObj(interp, val );
185     Jim_IncrRefCount(nameObjPtr);
186     Jim_IncrRefCount(valObjPtr);
187     result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
188     Jim_DecrRefCount(interp, nameObjPtr);
189     Jim_DecrRefCount(interp, valObjPtr);
190         // printf( "%s = 0%08x\n", namebuf, val );
191     return result;
192 }
193
194 static int
195 Jim_Command_mem2array( Jim_Interp *interp, int argc, Jim_Obj *const *argv)
196 {
197         target_t *target;
198         long l;
199         u32 width;
200         u32 endian;
201         u32 len;
202         u32 addr;
203         u32 count;
204         u32 v;
205         const char *varname;
206         u8 buffer[4096];
207         int  i,n,e,retval;
208
209
210         /* argv[1] = name of array to receive the data
211          * argv[2] = desired width
212          * argv[3] = memory address 
213          * argv[4] = length in bytes to read
214          */
215         if( argc != 5 ){
216                 Jim_WrongNumArgs( interp, 1, argv, "varname width addr nelems" );
217                 return JIM_ERR;
218         }
219         varname = Jim_GetString( argv[1], &len );
220         /* given "foo" get space for worse case "foo(%d)" .. add 20 */
221
222
223         e = Jim_GetLong( interp, argv[2], &l );
224         width = l;
225         if( e != JIM_OK ){
226                 return e;
227         }
228         
229         e = Jim_GetLong( interp, argv[3], &l );
230         addr = l;
231         if( e != JIM_OK ){
232                 return e;
233         }
234         e = Jim_GetLong( interp, argv[4], &l );
235         len = l;
236         if( e != JIM_OK ){
237                 return e;
238         }
239         switch(width){
240         case 8:
241                 width = 1;
242                 break;
243         case 16:
244                 width = 2;
245                 break;
246         case 32:
247                 width = 4;
248                 break;
249         default:
250                 Jim_SetResult(interp, 
251                                           Jim_NewEmptyStringObj(interp));
252                 Jim_AppendStrings( interp, Jim_GetResult(interp),
253                                                    "Invalid width param, must be 8/16/32", NULL );
254                 return JIM_ERR;
255         }
256         if( len == 0 ){
257                 Jim_SetResult(interp, 
258                                           Jim_NewEmptyStringObj(interp));
259                 Jim_AppendStrings( interp, Jim_GetResult(interp),
260                                                    "mem2array: zero width read?", NULL );
261                 return JIM_ERR;
262         }
263         if( (addr + (len * width)) < addr ){
264                 Jim_SetResult(interp, 
265                                           Jim_NewEmptyStringObj(interp));
266                 Jim_AppendStrings( interp, Jim_GetResult(interp),
267                                                    "mem2array: addr + len - wraps to zero?", NULL );
268                 return JIM_ERR;
269         }
270         /* absurd transfer size? */
271         if( len > 65536 ){
272                 Jim_SetResult(interp, 
273                                           Jim_NewEmptyStringObj(interp));
274                 Jim_AppendStrings( interp, Jim_GetResult(interp),
275                                                    "mem2array: absurd > 64K item request", NULL );
276                 return JIM_ERR;
277         }               
278                 
279         if( (width == 1) ||
280                 ((width == 2) && ((addr & 1) == 0)) ||
281                 ((width == 4) && ((addr & 3) == 0)) ){
282                 /* all is well */
283         } else {
284                 char buf[100];
285                 Jim_SetResult(interp, 
286                                           Jim_NewEmptyStringObj(interp));
287                 sprintf( buf, 
288                                  "mem2array address: 0x%08x is not aligned for %d byte reads",
289                                  addr, width );
290                                  
291                 Jim_AppendStrings( interp, Jim_GetResult(interp),
292                                                    buf , NULL );
293                 return JIM_ERR;
294         }
295
296         target = get_current_target( active_cmd_ctx );
297         
298         /* Transfer loop */
299
300         /* index counter */
301         n = 0;
302         /* assume ok */
303         e = JIM_OK;
304         while( len ){
305
306                 /* Slurp... in buffer size chunks */
307                 
308                 count = len; /* in objects.. */
309                 if( count > (sizeof(buffer)/width)){
310                         count = (sizeof(buffer)/width);
311                 }
312                 
313                 retval = target->type->read_memory( target, 
314                                                                                         addr, 
315                                                                                         width, 
316                                                                                         count,
317                                                                                         buffer );
318
319                 if( retval != ERROR_OK ){
320                         /* BOO !*/
321                         LOG_ERROR("mem2array: Read @ 0x%08x, w=%d, cnt=%d, failed",
322                                           addr, width, count );
323                         Jim_SetResult(interp, 
324                                                   Jim_NewEmptyStringObj(interp));
325                         Jim_AppendStrings( interp, Jim_GetResult(interp),
326                                                    "mem2array: cannot read memory", NULL );
327                         e = JIM_ERR;
328                         len = 0;
329                 } else {
330                         v = 0; /* shut up gcc */
331                         for( i = 0 ; i < count ; i++, n++ ){
332                                 switch(width){
333                                 case 4:
334                                         v = target_buffer_get_u32( target, &buffer[i*width] );
335                                         break;
336                                 case 2:
337                                         v = target_buffer_get_u16( target, &buffer[i*width] );
338                                         break;
339                                 case 1:
340                                         v = buffer[i] & 0x0ff;
341                                         break;
342                                 }
343                                 new_int_array_element( interp, varname, n, v );
344                         }
345                         len -= count;
346                 }
347         }
348         Jim_SetResult(interp, 
349                                   Jim_NewEmptyStringObj(interp));
350
351         return JIM_OK;
352 }
353
354 static void tcl_output(void *privData, const char *file, int line, 
355                 const char *function, const char *string)
356 {               
357         Jim_Obj *tclOutput=(Jim_Obj *)privData;
358
359         Jim_AppendString(interp, tclOutput, string, strlen(string));
360 }
361
362 /* try to execute as Jim command, otherwise fall back to standard command.
363
364         Note that even if the Jim command caused an error, then we succeeded
365         to execute it, hence this fn pretty much always returns ERROR_OK. 
366
367  */
368 int jim_command(command_context_t *context, char *line)
369 {
370         int retval=ERROR_OK;
371         /* FIX!!!! in reality there is only one cmd_ctx handler, but consider
372         what might happen here if there are multiple handlers w/reentrant callback
373         fn's... shudder!  */
374         active_cmd_ctx=context;
375         int retcode=Jim_Eval(interp, line);
376         
377         const char *result;
378         int reslen;
379     result = Jim_GetString(Jim_GetResult(interp), &reslen);
380     if (retcode == JIM_ERR) {
381             int len, i;
382         
383             LOG_USER_N("Runtime error, file \"%s\", line %d:" JIM_NL,
384                     interp->errorFileName, interp->errorLine);
385             LOG_USER_N("    %s" JIM_NL,
386                     Jim_GetString(interp->result, NULL));
387             Jim_ListLength(interp, interp->stackTrace, &len);
388             for (i = 0; i < len; i+= 3) {
389                 Jim_Obj *objPtr;
390                 const char *proc, *file, *line;
391         
392                 Jim_ListIndex(interp, interp->stackTrace, i, &objPtr, JIM_NONE);
393                 proc = Jim_GetString(objPtr, NULL);
394                 Jim_ListIndex(interp, interp->stackTrace, i+1, &objPtr,
395                         JIM_NONE);
396                 file = Jim_GetString(objPtr, NULL);
397                 Jim_ListIndex(interp, interp->stackTrace, i+2, &objPtr,
398                         JIM_NONE);
399                 line = Jim_GetString(objPtr, NULL);
400                 LOG_USER_N("In procedure '%s' called at file \"%s\", line %s" JIM_NL,
401                         proc, file, line);
402             }
403     } else if (retcode == JIM_EXIT) {
404         // ignore.
405         //exit(Jim_GetExitCode(interp));
406     } else {
407         if (reslen) {
408                 int i;
409                 char buff[256+1];
410                 for (i=0; i<reslen; i+=256)
411                 {
412                         int chunk;
413                         chunk=reslen-i;
414                         if (chunk>256)
415                                 chunk=256;
416                         strncpy(buff, result, chunk);
417                         buff[chunk]=0; 
418                 LOG_USER_N("%s", buff);
419                 }
420                 LOG_USER_N("%s", "\n");
421         }
422     }
423         return retval;
424 }
425
426 static int startLoop=0;
427
428 static int
429 Jim_Command_openocd_ignore(Jim_Interp *interp, 
430                                    int argc,
431                                    Jim_Obj *const *argv,
432                                    int ignore)
433 {
434         int retval;
435     char *cmd = (char*)Jim_GetString(argv[1], NULL);
436
437         lockBigLock();
438         
439     Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
440     
441     if (startLoop)
442     {
443         // We don't know whether or not the telnet/gdb server is running...
444         target_call_timer_callbacks_now();
445     }
446         
447         log_add_callback(tcl_output, tclOutput);
448     retval=command_run_line_internal(active_cmd_ctx, cmd);
449     
450     if (startLoop)
451     {
452         target_call_timer_callbacks_now();
453     }
454         log_remove_callback(tcl_output, tclOutput);
455     
456         Jim_SetResult(interp, tclOutput);
457     unlockBigLock();
458         
459     return (ignore||(retval==ERROR_OK))?JIM_OK:JIM_ERR;
460 }
461
462 static int
463 Jim_Command_openocd(Jim_Interp *interp, 
464                                    int argc,
465                                    Jim_Obj *const *argv)
466 {
467         return Jim_Command_openocd_ignore(interp, argc, argv, 1); 
468 }
469
470 static int
471 Jim_Command_openocd_throw(Jim_Interp *interp, 
472                                    int argc,
473                                    Jim_Obj *const *argv)
474 {
475         return Jim_Command_openocd_ignore(interp, argc, argv, 0); 
476 }
477   
478
479
480
481 /* find full path to file */
482 static int
483 Jim_Command_find(Jim_Interp *interp, 
484                                    int argc,
485                                    Jim_Obj *const *argv)
486 {
487         if (argc!=2)
488                 return JIM_ERR;
489         char *file = (char*)Jim_GetString(argv[1], NULL);
490         char *full_path=find_file(file);
491         if (full_path==NULL)
492                 return JIM_ERR;
493     Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path));
494     free(full_path);
495     
496         Jim_SetResult(interp, result);
497         return JIM_OK;
498 }
499
500 static int
501 Jim_Command_echo(Jim_Interp *interp, 
502                                    int argc,
503                                    Jim_Obj *const *argv)
504 {
505         if (argc!=2)
506                 return JIM_ERR;
507         char *str = (char*)Jim_GetString(argv[1], NULL);
508         LOG_USER("%s", str);
509         return JIM_OK;
510 }
511
512 static size_t
513 openocd_jim_fwrite( const void *_ptr, size_t size, size_t n, void *cookie )
514 {
515         size_t nbytes;
516         const char *ptr;
517
518         /* make it a char easier to read code */
519         ptr = _ptr;
520
521         nbytes = size * n;
522         if( nbytes == 0 ){
523                 return 0;
524         }
525
526         if( !active_cmd_ctx ){
527                 /* FIXME: Where should this go? */              
528                 return n;
529         }
530
531         
532         /* do we have to chunk it? */
533         if( ptr[ nbytes ] == 0 ){
534                 /* no it is a C style string */
535                 command_output_text( active_cmd_ctx, ptr );
536                 return;
537         }
538         /* GRR we must chunk - not null terminated */
539         while( nbytes ){
540                 char chunk[128+1];
541                 int x;
542
543                 x = nbytes;
544                 if( x > 128 ){
545                         x = 128;
546                 }
547                 /* copy it */
548                 memcpy( chunk, ptr, x );
549                 /* terminate it */
550                 chunk[n] = 0;
551                 /* output it */
552                 command_output_text( active_cmd_ctx, chunk );
553                 ptr += x;
554                 nbytes -= x;
555         }
556         
557         return n;
558 }
559
560 static size_t
561 openocd_jim_fread(void *ptr, size_t size, size_t n, void *cookie )
562 {
563         /* TCL wants to read... tell him no */
564         return 0;
565 }
566
567
568 static int
569 openocd_jim_vfprintf( void *cookie, const char *fmt, va_list ap )
570 {
571         char *cp;
572         int n;
573         
574         n = -1;
575         if( active_cmd_ctx ){
576                 cp = alloc_vprintf( fmt, ap );
577                 if( cp ){
578                         command_output_text( active_cmd_ctx, cp );
579                         n = strlen(cp);
580                         free(cp);
581                 }
582         }
583         return n;
584 }
585
586 static int
587 openocd_jim_fflush( void *cookie )
588 {
589         /* nothing to flush */
590         return 0;
591 }
592
593 static char  *
594 openocd_jim_fgets( char *s, int size, void *cookie )
595 {
596         /* not supported */
597         errno = ENOTSUP;
598         return NULL;
599 }
600
601
602
603 void initJim(void)
604 {
605     Jim_InitEmbedded();
606   
607     /* Create an interpreter */
608     interp = Jim_CreateInterp();
609     /* Add all the Jim core commands */
610     Jim_RegisterCoreCommands(interp);
611     Jim_CreateCommand(interp, "openocd", Jim_Command_openocd, NULL, NULL);
612     Jim_CreateCommand(interp, "openocd_throw", Jim_Command_openocd_throw, NULL, NULL);
613     Jim_CreateCommand(interp, "find", Jim_Command_find, NULL, NULL);
614     Jim_CreateCommand(interp, "echo", Jim_Command_echo, NULL, NULL);
615     Jim_CreateCommand(interp, "mem2array", Jim_Command_mem2array, NULL, NULL );
616
617         /* Set Jim's STDIO */
618         interp->cookie_stdin  = NULL;
619         interp->cookie_stdout = NULL;
620         interp->cookie_stderr = NULL;
621         interp->cb_fwrite     = openocd_jim_fwrite;
622         interp->cb_fread      = openocd_jim_fread ;
623         interp->cb_vfprintf   = openocd_jim_vfprintf;
624         interp->cb_fflush     = openocd_jim_fflush;
625         interp->cb_fgets      = openocd_jim_fgets;
626 }
627
628 /*
629 normally this is the main() function entry, but if OpenOCD is linked
630 into application, then this fn will not be invoked, but rather that
631 application will have it's own implementation of main().
632 */
633 int openocd_main(int argc, char *argv[])
634 {
635         initJim();
636         
637         /* initialize commandline interface */
638         command_context_t *cmd_ctx, *cfg_cmd_ctx;
639         cmd_ctx = command_init();
640
641         register_command(cmd_ctx, NULL, "version", handle_version_command,
642                                          COMMAND_EXEC, "show OpenOCD version");
643         register_command(cmd_ctx, NULL, "daemon_startup", handle_daemon_startup_command, COMMAND_CONFIG, 
644                         "deprecated - use \"init\" and \"reset\" at end of startup script instead");
645         
646         /* register subsystem commands */
647         server_register_commands(cmd_ctx);
648         telnet_register_commands(cmd_ctx);
649         gdb_register_commands(cmd_ctx);
650         tcl_register_commands(cmd_ctx); /* tcl server commands */
651         log_register_commands(cmd_ctx);
652         jtag_register_commands(cmd_ctx);
653         interpreter_register_commands(cmd_ctx);
654         xsvf_register_commands(cmd_ctx);
655         target_register_commands(cmd_ctx);
656         flash_register_commands(cmd_ctx);
657         nand_register_commands(cmd_ctx);
658         pld_register_commands(cmd_ctx);
659         
660         if (log_init(cmd_ctx) != ERROR_OK)
661                 return EXIT_FAILURE;
662         LOG_DEBUG("log init complete");
663
664         LOG_OUTPUT( OPENOCD_VERSION "\n" );
665         
666         
667         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
668         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
669         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
670         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
671         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
672         LOG_OUTPUT( "$URL$\n");
673         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
674         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
675         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
676         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
677         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
678
679         register_command(cmd_ctx, NULL, "init", handle_init_command,
680                                          COMMAND_ANY, "initializes target and servers - nop on subsequent invocations");
681
682         cfg_cmd_ctx = copy_command_context(cmd_ctx);
683         cfg_cmd_ctx->mode = COMMAND_CONFIG;
684         command_set_output_handler(cfg_cmd_ctx, configuration_output_handler, NULL);
685         
686         if (parse_cmdline_args(cfg_cmd_ctx, argc, argv) != ERROR_OK)
687                 return EXIT_FAILURE;
688
689     Jim_Eval(interp, "source [find tcl/commands.tcl]");
690
691         if (parse_config_file(cfg_cmd_ctx) != ERROR_OK)
692                 return EXIT_FAILURE;
693         
694         command_done(cfg_cmd_ctx);
695
696         if (command_run_line(cmd_ctx, "init")!=ERROR_OK)
697                 return EXIT_FAILURE;
698         
699         if (daemon_startup)
700                 command_run_line(cmd_ctx, "reset");
701
702
703         startLoop=1;
704
705         /* handle network connections */
706         server_loop(cmd_ctx);
707
708         /* shut server down */
709         server_quit();
710
711         unregister_all_commands(cmd_ctx);
712         
713         /* free commandline interface */
714         command_done(cmd_ctx);
715
716         return EXIT_SUCCESS;
717 }
718
719
720 /*
721  * Local Variables: **
722  * tab-width: 4 **
723  * c-basic-offset: 4 **
724  * End: **
725  */
726