- added svn props for previously added file
[openocd.git] / src / helper / tclapi.c
1 /***************************************************************************
2 * Copyright (C) 2007,2008 Øyvind Harboe *
3 * Copyright (C) 2008 Duane Ellis *
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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "replacements.h"
25 #include "target.h"
26 #include "target_request.h"
27
28 #include "log.h"
29 #include "configuration.h"
30 #include "binarybuffer.h"
31 #include "jtag.h"
32 #include "flash.h"
33
34 #include <string.h>
35 #include <stdlib.h>
36 #include <inttypes.h>
37
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <unistd.h>
41 #include <errno.h>
42
43 #include <sys/time.h>
44 #include <time.h>
45
46 #include <time_support.h>
47
48 #include <fileio.h>
49 #include <image.h>
50
51 static int new_int_array_element(Jim_Interp * interp, const char *varname, int idx, u32 val)
52 {
53 char *namebuf;
54 Jim_Obj *nameObjPtr, *valObjPtr;
55 int result;
56
57 namebuf = alloc_printf("%s(%d)", varname, idx);
58 if (!namebuf)
59 return JIM_ERR;
60
61 nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
62 valObjPtr = Jim_NewIntObj(interp, val);
63 if (!nameObjPtr || !valObjPtr)
64 {
65 free(namebuf);
66 return JIM_ERR;
67 }
68
69 Jim_IncrRefCount(nameObjPtr);
70 Jim_IncrRefCount(valObjPtr);
71 result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
72 Jim_DecrRefCount(interp, nameObjPtr);
73 Jim_DecrRefCount(interp, valObjPtr);
74 free(namebuf);
75 /* printf("%s(%d) <= 0%08x\n", varname, idx, val); */
76 return result;
77 }
78
79 static int jim_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
80 {
81 target_t *target;
82 command_context_t *context;
83 long l;
84 u32 width;
85 u32 len;
86 u32 addr;
87 u32 count;
88 u32 v;
89 const char *varname;
90 u8 buffer[4096];
91 int i, n, e, retval;
92
93 /* argv[1] = name of array to receive the data
94 * argv[2] = desired width
95 * argv[3] = memory address
96 * argv[4] = count of times to read
97 */
98 if (argc != 5) {
99 Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems");
100 return JIM_ERR;
101 }
102 varname = Jim_GetString(argv[1], &len);
103 /* given "foo" get space for worse case "foo(%d)" .. add 20 */
104
105 e = Jim_GetLong(interp, argv[2], &l);
106 width = l;
107 if (e != JIM_OK) {
108 return e;
109 }
110
111 e = Jim_GetLong(interp, argv[3], &l);
112 addr = l;
113 if (e != JIM_OK) {
114 return e;
115 }
116 e = Jim_GetLong(interp, argv[4], &l);
117 len = l;
118 if (e != JIM_OK) {
119 return e;
120 }
121 switch (width) {
122 case 8:
123 width = 1;
124 break;
125 case 16:
126 width = 2;
127 break;
128 case 32:
129 width = 4;
130 break;
131 default:
132 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
133 Jim_AppendStrings( interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL );
134 return JIM_ERR;
135 }
136 if (len == 0) {
137 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
138 Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: zero width read?", NULL);
139 return JIM_ERR;
140 }
141 if ((addr + (len * width)) < addr) {
142 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
143 Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: addr + len - wraps to zero?", NULL);
144 return JIM_ERR;
145 }
146 /* absurd transfer size? */
147 if (len > 65536) {
148 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
149 Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: absurd > 64K item request", NULL);
150 return JIM_ERR;
151 }
152
153 if ((width == 1) ||
154 ((width == 2) && ((addr & 1) == 0)) ||
155 ((width == 4) && ((addr & 3) == 0))) {
156 /* all is well */
157 } else {
158 char buf[100];
159 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
160 sprintf(buf, "mem2array address: 0x%08x is not aligned for %d byte reads", addr, width);
161 Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL);
162 return JIM_ERR;
163 }
164
165 context = Jim_GetAssocData(interp, "context");
166 if (context == NULL)
167 {
168 LOG_ERROR("mem2array: no command context");
169 return JIM_ERR;
170 }
171 target = get_current_target(context);
172 if (target == NULL)
173 {
174 LOG_ERROR("mem2array: no current target");
175 return JIM_ERR;
176 }
177
178 /* Transfer loop */
179
180 /* index counter */
181 n = 0;
182 /* assume ok */
183 e = JIM_OK;
184 while (len) {
185 /* Slurp... in buffer size chunks */
186
187 count = len; /* in objects.. */
188 if (count > (sizeof(buffer)/width)) {
189 count = (sizeof(buffer)/width);
190 }
191
192 retval = target->type->read_memory( target, addr, width, count, buffer );
193 if (retval != ERROR_OK) {
194 /* BOO !*/
195 LOG_ERROR("mem2array: Read @ 0x%08x, w=%d, cnt=%d, failed", addr, width, count);
196 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
197 Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL);
198 e = JIM_ERR;
199 len = 0;
200 } else {
201 v = 0; /* shut up gcc */
202 for (i = 0 ;i < count ;i++, n++) {
203 switch (width) {
204 case 4:
205 v = target_buffer_get_u32(target, &buffer[i*width]);
206 break;
207 case 2:
208 v = target_buffer_get_u16(target, &buffer[i*width]);
209 break;
210 case 1:
211 v = buffer[i] & 0x0ff;
212 break;
213 }
214 new_int_array_element(interp, varname, n, v);
215 }
216 len -= count;
217 }
218 }
219
220 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
221
222 return JIM_OK;
223 }
224
225 static int get_int_array_element(Jim_Interp * interp, const char *varname, int idx, u32 *val)
226 {
227 char *namebuf;
228 Jim_Obj *nameObjPtr, *valObjPtr;
229 int result;
230 long l;
231
232 namebuf = alloc_printf("%s(%d)", varname, idx);
233 if (!namebuf)
234 return JIM_ERR;
235
236 nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
237 if (!nameObjPtr)
238 {
239 free(namebuf);
240 return JIM_ERR;
241 }
242
243 Jim_IncrRefCount(nameObjPtr);
244 valObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_ERRMSG);
245 Jim_DecrRefCount(interp, nameObjPtr);
246 free(namebuf);
247 if (valObjPtr == NULL)
248 return JIM_ERR;
249
250 result = Jim_GetLong(interp, valObjPtr, &l);
251 /* printf("%s(%d) => 0%08x\n", varname, idx, val); */
252 *val = l;
253 return result;
254 }
255
256 static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
257 {
258 target_t *target;
259 command_context_t *context;
260 long l;
261 u32 width;
262 u32 len;
263 u32 addr;
264 u32 count;
265 u32 v;
266 const char *varname;
267 u8 buffer[4096];
268 int i, n, e, retval;
269
270 /* argv[1] = name of array to get the data
271 * argv[2] = desired width
272 * argv[3] = memory address
273 * argv[4] = count to write
274 */
275 if (argc != 5) {
276 Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems");
277 return JIM_ERR;
278 }
279 varname = Jim_GetString(argv[1], &len);
280 /* given "foo" get space for worse case "foo(%d)" .. add 20 */
281
282 e = Jim_GetLong(interp, argv[2], &l);
283 width = l;
284 if (e != JIM_OK) {
285 return e;
286 }
287
288 e = Jim_GetLong(interp, argv[3], &l);
289 addr = l;
290 if (e != JIM_OK) {
291 return e;
292 }
293 e = Jim_GetLong(interp, argv[4], &l);
294 len = l;
295 if (e != JIM_OK) {
296 return e;
297 }
298 switch (width) {
299 case 8:
300 width = 1;
301 break;
302 case 16:
303 width = 2;
304 break;
305 case 32:
306 width = 4;
307 break;
308 default:
309 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
310 Jim_AppendStrings( interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL );
311 return JIM_ERR;
312 }
313 if (len == 0) {
314 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
315 Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: zero width read?", NULL);
316 return JIM_ERR;
317 }
318 if ((addr + (len * width)) < addr) {
319 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
320 Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: addr + len - wraps to zero?", NULL);
321 return JIM_ERR;
322 }
323 /* absurd transfer size? */
324 if (len > 65536) {
325 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
326 Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: absurd > 64K item request", NULL);
327 return JIM_ERR;
328 }
329
330 if ((width == 1) ||
331 ((width == 2) && ((addr & 1) == 0)) ||
332 ((width == 4) && ((addr & 3) == 0))) {
333 /* all is well */
334 } else {
335 char buf[100];
336 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
337 sprintf(buf, "array2mem address: 0x%08x is not aligned for %d byte reads", addr, width);
338 Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL);
339 return JIM_ERR;
340 }
341
342 context = Jim_GetAssocData(interp, "context");
343 if (context == NULL)
344 {
345 LOG_ERROR("array2mem: no command context");
346 return JIM_ERR;
347 }
348 target = get_current_target(context);
349 if (target == NULL)
350 {
351 LOG_ERROR("array2mem: no current target");
352 return JIM_ERR;
353 }
354
355 /* Transfer loop */
356
357 /* index counter */
358 n = 0;
359 /* assume ok */
360 e = JIM_OK;
361 while (len) {
362 /* Slurp... in buffer size chunks */
363
364 count = len; /* in objects.. */
365 if (count > (sizeof(buffer)/width)) {
366 count = (sizeof(buffer)/width);
367 }
368
369 v = 0; /* shut up gcc */
370 for (i = 0 ;i < count ;i++, n++) {
371 get_int_array_element(interp, varname, n, &v);
372 switch (width) {
373 case 4:
374 target_buffer_set_u32(target, &buffer[i*width], v);
375 break;
376 case 2:
377 target_buffer_set_u16(target, &buffer[i*width], v);
378 break;
379 case 1:
380 buffer[i] = v & 0x0ff;
381 break;
382 }
383 }
384 len -= count;
385
386 retval = target->type->write_memory(target, addr, width, count, buffer);
387 if (retval != ERROR_OK) {
388 /* BOO !*/
389 LOG_ERROR("array2mem: Write @ 0x%08x, w=%d, cnt=%d, failed", addr, width, count);
390 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
391 Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL);
392 e = JIM_ERR;
393 len = 0;
394 }
395 }
396
397 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
398
399 return JIM_OK;
400 }
401
402 int Jim_Command_drscan(Jim_Interp *interp, int argc, Jim_Obj *const *args)
403 {
404 int retval;
405 scan_field_t *fields;
406 int num_fields;
407 int field_count = 0;
408 int i, e;
409 long device;
410
411 /* args[1] = device
412 * args[2] = num_bits
413 * args[3] = hex string
414 * ... repeat num bits and hex string ...
415 */
416 if ((argc < 4) || ((argc % 2)!=0))
417 {
418 Jim_WrongNumArgs(interp, 1, args, "wrong arguments");
419 return JIM_ERR;
420 }
421
422 for (i = 2; i < argc; i+=2)
423 {
424 long bits;
425
426 e = Jim_GetLong(interp, args[i], &bits);
427 if (e != JIM_OK)
428 return e;
429 }
430
431 e = Jim_GetLong(interp, args[1], &device);
432 if (e != JIM_OK)
433 return e;
434
435 num_fields=(argc-2)/2;
436 fields = malloc(sizeof(scan_field_t) * num_fields);
437 for (i = 2; i < argc; i+=2)
438 {
439 long bits;
440 int len;
441 const char *str;
442
443 Jim_GetLong(interp, args[i], &bits);
444 str = Jim_GetString(args[i+1], &len);
445
446 fields[field_count].device = device;
447 fields[field_count].num_bits = bits;
448 fields[field_count].out_value = malloc(CEIL(bits, 8));
449 str_to_buf(str, len, fields[field_count].out_value, bits, 0);
450 fields[field_count].out_mask = NULL;
451 fields[field_count].in_value = fields[field_count].out_value;
452 fields[field_count].in_check_mask = NULL;
453 fields[field_count].in_check_value = NULL;
454 fields[field_count].in_handler = NULL;
455 fields[field_count++].in_handler_priv = NULL;
456 }
457
458 jtag_add_dr_scan(num_fields, fields, -1);
459 retval = jtag_execute_queue();
460 if (retval != ERROR_OK)
461 {
462 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
463 Jim_AppendStrings(interp, Jim_GetResult(interp), "drscan: jtag execute failed", NULL);
464 return JIM_ERR;
465 }
466
467 field_count=0;
468 Jim_Obj *list = Jim_NewListObj(interp, NULL, 0);
469 for (i = 2; i < argc; i+=2)
470 {
471 long bits;
472 char *str;
473
474 Jim_GetLong(interp, args[i], &bits);
475 str = buf_to_str(fields[field_count].in_value, bits, 16);
476 free(fields[field_count].out_value);
477
478 Jim_ListAppendElement(interp, list, Jim_NewStringObj(interp, str, strlen(str)));
479 free(str);
480 field_count++;
481 }
482
483 Jim_SetResult(interp, list);
484
485 free(fields);
486
487 return JIM_OK;
488 }
489
490 static int jim_flash_banks(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
491 {
492 flash_bank_t *p;
493
494 if (argc != 1) {
495 Jim_WrongNumArgs(interp, 1, argv, "no arguments to flash_banks command");
496 return JIM_ERR;
497 }
498
499 if (!flash_banks)
500 {
501 return JIM_ERR;
502 }
503
504 Jim_Obj *list=Jim_NewListObj(interp, NULL, 0);
505 for (p = flash_banks; p; p = p->next)
506 {
507 Jim_Obj *elem=Jim_NewListObj(interp, NULL, 0);
508
509 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "name", -1));
510 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, p->driver->name, -1));
511 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "base", -1));
512 Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->base));
513 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "size", -1));
514 Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->size));
515 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "bus_width", -1));
516 Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->bus_width));
517 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "chip_width", -1));
518 Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->chip_width));
519
520 Jim_ListAppendElement(interp, list, elem);
521 }
522
523 Jim_SetResult(interp, list);
524
525 return JIM_OK;
526 }
527
528
529 int tclapi_register_commands()
530 {
531 register_jim("ocd_mem2array", jim_mem2array, "read memory and return as a TCL array for script processing");
532 register_jim("ocd_array2mem", jim_array2mem, "convert a TCL array to memory locations and write the values");
533 register_jim("drscan", Jim_Command_drscan, "execute DR scan <device> <num_bits> <value> <num_bits1> <value2> ...");
534 register_jim("ocd_flash_banks", jim_flash_banks, "return information about the flash banks");
535
536 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)