src/helper/configuration.h
[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
147         return ERROR_OK;
148 }
149
150
151 /* implementations of OpenOCD that uses multithreading needs to lock OpenOCD while calling
152  * OpenOCD fn's. No-op in vanilla OpenOCD
153  */
154 void lockBigLock()
155 {
156 }
157 void unlockBigLock()
158 {
159 }
160
161
162
163
164
165 Jim_Interp *interp;
166 command_context_t *active_cmd_ctx;
167
168 static int
169 new_int_array_element( Jim_Interp * interp, 
170                                            const char *varname, 
171                                            int idx, 
172                                            u32 val )
173 {
174         char *namebuf;
175         Jim_Obj *nameObjPtr, *valObjPtr;
176         int result;
177
178         namebuf = alloca( strlen(varname) + 30 );
179         sprintf( namebuf, "%s(%d)", varname, idx );
180
181
182     nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
183     valObjPtr = Jim_NewIntObj(interp, val );
184     Jim_IncrRefCount(nameObjPtr);
185     Jim_IncrRefCount(valObjPtr);
186     result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
187     Jim_DecrRefCount(interp, nameObjPtr);
188     Jim_DecrRefCount(interp, valObjPtr);
189         // printf( "%s = 0%08x\n", namebuf, val );
190     return result;
191 }
192
193 static int
194 Jim_Command_mem2array( Jim_Interp *interp, int argc, Jim_Obj *const *argv)
195 {
196         target_t *target;
197         long l;
198         u32 width;
199         u32 endian;
200         u32 len;
201         u32 addr;
202         u32 count;
203         u32 v;
204         const char *varname;
205         u8 buffer[4096];
206         int  i,n,e,retval;
207
208
209         /* argv[1] = name of array to receive the data
210          * argv[2] = desired width
211          * argv[3] = memory address 
212          * argv[4] = length in bytes to read
213          */
214         if( argc != 5 ){
215                 Jim_WrongNumArgs( interp, 1, argv, "varname width addr nelems" );
216                 return JIM_ERR;
217         }
218         varname = Jim_GetString( argv[1], &len );
219         /* given "foo" get space for worse case "foo(%d)" .. add 20 */
220
221
222         e = Jim_GetLong( interp, argv[2], &l );
223         width = l;
224         if( e != JIM_OK ){
225                 return e;
226         }
227         
228         e = Jim_GetLong( interp, argv[3], &l );
229         addr = l;
230         if( e != JIM_OK ){
231                 return e;
232         }
233         e = Jim_GetLong( interp, argv[4], &l );
234         len = l;
235         if( e != JIM_OK ){
236                 return e;
237         }
238         switch(width){
239         case 8:
240                 width = 1;
241                 break;
242         case 16:
243                 width = 2;
244                 break;
245         case 32:
246                 width = 4;
247                 break;
248         default:
249                 Jim_SetResult(interp, 
250                                           Jim_NewEmptyStringObj(interp));
251                 Jim_AppendStrings( interp, Jim_GetResult(interp),
252                                                    "Invalid width param, must be 8/16/32", NULL );
253                 return JIM_ERR;
254         }
255         if( len == 0 ){
256                 Jim_SetResult(interp, 
257                                           Jim_NewEmptyStringObj(interp));
258                 Jim_AppendStrings( interp, Jim_GetResult(interp),
259                                                    "mem2array: zero width read?", NULL );
260                 return JIM_ERR;
261         }
262         if( (addr + (len * width)) < addr ){
263                 Jim_SetResult(interp, 
264                                           Jim_NewEmptyStringObj(interp));
265                 Jim_AppendStrings( interp, Jim_GetResult(interp),
266                                                    "mem2array: addr + len - wraps to zero?", NULL );
267                 return JIM_ERR;
268         }
269         /* absurd transfer size? */
270         if( len > 65536 ){
271                 Jim_SetResult(interp, 
272                                           Jim_NewEmptyStringObj(interp));
273                 Jim_AppendStrings( interp, Jim_GetResult(interp),
274                                                    "mem2array: absurd > 64K item request", NULL );
275                 return JIM_ERR;
276         }               
277                 
278         if( (width == 1) ||
279                 ((width == 2) && ((addr & 1) == 0)) ||
280                 ((width == 4) && ((addr & 3) == 0)) ){
281                 /* all is well */
282         } else {
283                 char buf[100];
284                 Jim_SetResult(interp, 
285                                           Jim_NewEmptyStringObj(interp));
286                 sprintf( buf, 
287                                  "mem2array address: 0x%08x is not aligned for %d byte reads",
288                                  addr, width );
289                                  
290                 Jim_AppendStrings( interp, Jim_GetResult(interp),
291                                                    buf , NULL );
292                 return JIM_ERR;
293         }
294
295         target = get_current_target( active_cmd_ctx );
296         
297         /* Transfer loop */
298
299         /* index counter */
300         n = 0;
301         /* assume ok */
302         e = JIM_OK;
303         while( len ){
304
305                 /* Slurp... in buffer size chunks */
306                 
307                 count = len; /* in objects.. */
308                 if( count > (sizeof(buffer)/width)){
309                         count = (sizeof(buffer)/width);
310                 }
311                 
312                 retval = target->type->read_memory( target, 
313                                                                                         addr, 
314                                                                                         width, 
315                                                                                         count,
316                                                                                         buffer );
317
318                 if( retval != ERROR_OK ){
319                         /* BOO !*/
320                         LOG_ERROR("mem2array: Read @ 0x%08x, w=%d, cnt=%d, failed",
321                                           addr, width, count );
322                         Jim_SetResult(interp, 
323                                                   Jim_NewEmptyStringObj(interp));
324                         Jim_AppendStrings( interp, Jim_GetResult(interp),
325                                                    "mem2array: cannot read memory", NULL );
326                         e = JIM_ERR;
327                         len = 0;
328                 } else {
329                         v = 0; /* shut up gcc */
330                         for( i = 0 ; i < count ; i++, n++ ){
331                                 switch(width){
332                                 case 4:
333                                         v = target_buffer_get_u32( target, &buffer[i*width] );
334                                         break;
335                                 case 2:
336                                         v = target_buffer_get_u16( target, &buffer[i*width] );
337                                         break;
338                                 case 1:
339                                         v = buffer[i] & 0x0ff;
340                                         break;
341                                 }
342                                 new_int_array_element( interp, varname, n, v );
343                         }
344                         len -= count;
345                 }
346         }
347         Jim_SetResult(interp, 
348                                   Jim_NewEmptyStringObj(interp));
349
350         return JIM_OK;
351 }
352
353 static void tcl_output(void *privData, const char *file, int line, 
354                 const char *function, const char *string)
355 {               
356         Jim_Obj *tclOutput=(Jim_Obj *)privData;
357
358         Jim_AppendString(interp, tclOutput, string, strlen(string));
359 }
360
361 /* try to execute as Jim command, otherwise fall back to standard command.
362
363         Note that even if the Jim command caused an error, then we succeeded
364         to execute it, hence this fn pretty much always returns ERROR_OK. 
365
366  */
367 int jim_command(command_context_t *context, char *line)
368 {
369         int retval=ERROR_OK;
370         /* FIX!!!! in reality there is only one cmd_ctx handler, but consider
371         what might happen here if there are multiple handlers w/reentrant callback
372         fn's... shudder!  */
373         active_cmd_ctx=context;
374         int retcode=Jim_Eval(interp, line);
375         
376         const char *result;
377         int reslen;
378     result = Jim_GetString(Jim_GetResult(interp), &reslen);
379     if (retcode == JIM_ERR) {
380             int len, i;
381         
382             LOG_USER_N("Runtime error, file \"%s\", line %d:" JIM_NL,
383                     interp->errorFileName, interp->errorLine);
384             LOG_USER_N("    %s" JIM_NL,
385                     Jim_GetString(interp->result, NULL));
386             Jim_ListLength(interp, interp->stackTrace, &len);
387             for (i = 0; i < len; i+= 3) {
388                 Jim_Obj *objPtr;
389                 const char *proc, *file, *line;
390         
391                 Jim_ListIndex(interp, interp->stackTrace, i, &objPtr, JIM_NONE);
392                 proc = Jim_GetString(objPtr, NULL);
393                 Jim_ListIndex(interp, interp->stackTrace, i+1, &objPtr,
394                         JIM_NONE);
395                 file = Jim_GetString(objPtr, NULL);
396                 Jim_ListIndex(interp, interp->stackTrace, i+2, &objPtr,
397                         JIM_NONE);
398                 line = Jim_GetString(objPtr, NULL);
399                 LOG_USER_N("In procedure '%s' called at file \"%s\", line %s" JIM_NL,
400                         proc, file, line);
401             }
402     } else if (retcode == JIM_EXIT) {
403         // ignore.
404         //exit(Jim_GetExitCode(interp));
405     } else {
406         if (reslen) {
407                 int i;
408                 char buff[256+1];
409                 for (i=0; i<reslen; i+=256)
410                 {
411                         int chunk;
412                         chunk=reslen-i;
413                         if (chunk>256)
414                                 chunk=256;
415                         strncpy(buff, result, chunk);
416                         buff[chunk]=0; 
417                 LOG_USER_N("%s", buff);
418                 }
419                 LOG_USER_N("%s", "\n");
420         }
421     }
422         return retval;
423 }
424
425 static int startLoop=0;
426
427 static int
428 Jim_Command_openocd_ignore(Jim_Interp *interp, 
429                                    int argc,
430                                    Jim_Obj *const *argv,
431                                    int ignore)
432 {
433         int retval;
434     char *cmd = (char*)Jim_GetString(argv[1], NULL);
435
436         lockBigLock();
437         
438     Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
439     
440     if (startLoop)
441     {
442         // We don't know whether or not the telnet/gdb server is running...
443         target_call_timer_callbacks_now();
444     }
445         
446         log_add_callback(tcl_output, tclOutput);
447     retval=command_run_line_internal(active_cmd_ctx, cmd);
448     
449     if (startLoop)
450     {
451         target_call_timer_callbacks_now();
452     }
453         log_remove_callback(tcl_output, tclOutput);
454     
455         Jim_SetResult(interp, tclOutput);
456     unlockBigLock();
457         
458     return (ignore||(retval==ERROR_OK))?JIM_OK:JIM_ERR;
459 }
460
461 static int
462 Jim_Command_openocd(Jim_Interp *interp, 
463                                    int argc,
464                                    Jim_Obj *const *argv)
465 {
466         return Jim_Command_openocd_ignore(interp, argc, argv, 1); 
467 }
468
469 static int
470 Jim_Command_openocd_throw(Jim_Interp *interp, 
471                                    int argc,
472                                    Jim_Obj *const *argv)
473 {
474         return Jim_Command_openocd_ignore(interp, argc, argv, 0); 
475 }
476   
477
478
479
480 /* find full path to file */
481 static int
482 Jim_Command_find(Jim_Interp *interp, 
483                                    int argc,
484                                    Jim_Obj *const *argv)
485 {
486         if (argc!=2)
487                 return JIM_ERR;
488         char *file = (char*)Jim_GetString(argv[1], NULL);
489         char *full_path=find_file(file);
490         if (full_path==NULL)
491                 return JIM_ERR;
492     Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path));
493     free(full_path);
494     
495         Jim_SetResult(interp, result);
496         return JIM_OK;
497 }
498
499 static int
500 Jim_Command_echo(Jim_Interp *interp, 
501                                    int argc,
502                                    Jim_Obj *const *argv)
503 {
504         if (argc!=2)
505                 return JIM_ERR;
506         char *str = (char*)Jim_GetString(argv[1], NULL);
507         LOG_USER("%s", str);
508         return JIM_OK;
509 }
510
511 static size_t
512 openocd_jim_fwrite( const void *_ptr, size_t size, size_t n, void *cookie )
513 {
514         size_t nbytes;
515         const char *ptr;
516
517         /* make it a char easier to read code */
518         ptr = _ptr;
519
520         nbytes = size * n;
521         if( nbytes == 0 ){
522                 return 0;
523         }
524
525         if( !active_cmd_ctx ){
526                 /* FIXME: Where should this go? */              
527                 return n;
528         }
529
530         
531         /* do we have to chunk it? */
532         if( ptr[ nbytes ] == 0 ){
533                 /* no it is a C style string */
534                 command_output_text( active_cmd_ctx, ptr );
535                 return;
536         }
537         /* GRR we must chunk - not null terminated */
538         while( nbytes ){
539                 char chunk[128+1];
540                 int x;
541
542                 x = nbytes;
543                 if( x > 128 ){
544                         x = 128;
545                 }
546                 /* copy it */
547                 memcpy( chunk, ptr, x );
548                 /* terminate it */
549                 chunk[n] = 0;
550                 /* output it */
551                 command_output_text( active_cmd_ctx, chunk );
552                 ptr += x;
553                 nbytes -= x;
554         }
555         
556         return n;
557 }
558
559 static size_t
560 openocd_jim_fread(void *ptr, size_t size, size_t n, void *cookie )
561 {
562         /* TCL wants to read... tell him no */
563         return 0;
564 }
565
566
567 static int
568 openocd_jim_vfprintf( void *cookie, const char *fmt, va_list ap )
569 {
570         char *cp;
571         int n;
572         
573         n = -1;
574         if( active_cmd_ctx ){
575                 cp = alloc_vprintf( fmt, ap );
576                 if( cp ){
577                         command_output_text( active_cmd_ctx, cp );
578                         n = strlen(cp);
579                         free(cp);
580                 }
581         }
582         return n;
583 }
584
585 static int
586 openocd_jim_fflush( void *cookie )
587 {
588         /* nothing to flush */
589         return 0;
590 }
591
592 static char  *
593 openocd_jim_fgets( char *s, int size, void *cookie )
594 {
595         /* not supported */
596         errno = ENOTSUP;
597         return NULL;
598 }
599
600
601
602 void initJim(void)
603 {
604     Jim_InitEmbedded();
605   
606     /* Create an interpreter */
607     interp = Jim_CreateInterp();
608     /* Add all the Jim core commands */
609     Jim_RegisterCoreCommands(interp);
610     Jim_CreateCommand(interp, "openocd", Jim_Command_openocd, NULL, NULL);
611     Jim_CreateCommand(interp, "openocd_throw", Jim_Command_openocd_throw, NULL, NULL);
612     Jim_CreateCommand(interp, "find", Jim_Command_find, NULL, NULL);
613     Jim_CreateCommand(interp, "echo", Jim_Command_echo, NULL, NULL);
614     Jim_CreateCommand(interp, "mem2array", Jim_Command_mem2array, NULL, NULL );
615
616         /* Set Jim's STDIO */
617         interp->cookie_stdin  = NULL;
618         interp->cookie_stdout = NULL;
619         interp->cookie_stderr = NULL;
620         interp->cb_fwrite     = openocd_jim_fwrite;
621         interp->cb_fread      = openocd_jim_fread ;
622         interp->cb_vfprintf   = openocd_jim_vfprintf;
623         interp->cb_fflush     = openocd_jim_fflush;
624         interp->cb_fgets      = openocd_jim_fgets;
625 }
626
627 int main(int argc, char *argv[])
628 {
629         initJim();
630         
631         /* initialize commandline interface */
632         command_context_t *cmd_ctx, *cfg_cmd_ctx;
633         cmd_ctx = command_init();
634
635         register_command(cmd_ctx, NULL, "version", handle_version_command,
636                                          COMMAND_EXEC, "show OpenOCD version");
637         register_command(cmd_ctx, NULL, "daemon_startup", handle_daemon_startup_command, COMMAND_CONFIG, 
638                         "deprecated - use \"init\" and \"reset\" at end of startup script instead");
639         
640         /* register subsystem commands */
641         server_register_commands(cmd_ctx);
642         telnet_register_commands(cmd_ctx);
643         gdb_register_commands(cmd_ctx);
644         log_register_commands(cmd_ctx);
645         jtag_register_commands(cmd_ctx);
646         interpreter_register_commands(cmd_ctx);
647         xsvf_register_commands(cmd_ctx);
648         target_register_commands(cmd_ctx);
649         flash_register_commands(cmd_ctx);
650         nand_register_commands(cmd_ctx);
651         pld_register_commands(cmd_ctx);
652         
653         if (log_init(cmd_ctx) != ERROR_OK)
654                 return EXIT_FAILURE;
655         LOG_DEBUG("log init complete");
656
657         LOG_OUTPUT( OPENOCD_VERSION "\n" );
658         
659         
660         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
661         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
662         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
663         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
664         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
665         LOG_OUTPUT( "$URL$\n");
666         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
667         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
668         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
669         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
670         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
671
672         register_command(cmd_ctx, NULL, "init", handle_init_command,
673                                          COMMAND_ANY, "initializes target and servers - nop on subsequent invocations");
674
675         cfg_cmd_ctx = copy_command_context(cmd_ctx);
676         cfg_cmd_ctx->mode = COMMAND_CONFIG;
677         command_set_output_handler(cfg_cmd_ctx, configuration_output_handler, NULL);
678         
679         if (parse_cmdline_args(cfg_cmd_ctx, argc, argv) != ERROR_OK)
680                 return EXIT_FAILURE;
681
682     Jim_Eval(interp, "source [find tcl/commands.tcl]");
683
684         if (parse_config_file(cfg_cmd_ctx) != ERROR_OK)
685                 return EXIT_FAILURE;
686         
687         command_done(cfg_cmd_ctx);
688
689         if (command_run_line(cmd_ctx, "init")!=ERROR_OK)
690                 return EXIT_FAILURE;
691         
692         if (daemon_startup)
693                 command_run_line(cmd_ctx, "reset");
694
695
696         startLoop=1;
697
698         /* handle network connections */
699         server_loop(cmd_ctx);
700
701         /* shut server down */
702         server_quit();
703
704         unregister_all_commands(cmd_ctx);
705         
706         /* free commandline interface */
707         command_done(cmd_ctx);
708
709         return EXIT_SUCCESS;
710 }
711
712
713 /*
714  * Local Variables: **
715  * tab-width: 4 **
716  * c-basic-offset: 4 **
717  * End: **
718  */
719