target.c 128 KB
Newer Older
3001
3002
3003
3004
3005
 * Translate a virtual address to a physical address.
 *
 * The low-level target implementation must have logged a detailed error
 * which is forwarded to telnet/GDB session.
 */
3006
COMMAND_HANDLER(handle_virt2phys_command)
3007
{
3008
	if (CMD_ARGC != 1)
3009
3010
		return ERROR_COMMAND_SYNTAX_ERROR;

3011
	uint32_t va;
3012
	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], va);
3013
	uint32_t pa;
3014

3015
	struct target *target = get_current_target(CMD_CTX);
3016
	int retval = target->type->virt2phys(target, va, &pa);
3017
	if (retval == ERROR_OK)
3018
		command_print(CMD_CTX, "Physical address 0x%08" PRIx32 "", pa);
3019

3020
3021
	return retval;
}
3022

3023
3024
static void writeData(FILE *f, const void *data, size_t len)
{
3025
	size_t written = fwrite(data, 1, len, f);
3026
	if (written != len)
3027
		LOG_ERROR("failed to write %zu bytes: %s", len, strerror(errno));
3028
3029
}

3030
3031
3032
static void writeLong(FILE *f, int l)
{
	int i;
zwelch's avatar
zwelch committed
3033
	for (i = 0; i < 4; i++)
3034
	{
zwelch's avatar
zwelch committed
3035
		char c = (l >> (i*8))&0xff;
3036
		writeData(f, &c, 1);
3037
	}
oharboe's avatar
oharboe committed
3038

3039
}
3040

3041
3042
static void writeString(FILE *f, char *s)
{
3043
	writeData(f, s, strlen(s));
3044
3045
}

3046
/* Dump a gmon.out histogram file. */
3047
static void writeGmon(uint32_t *samples, uint32_t sampleNum, const char *filename)
3048
{
3049
	uint32_t i;
zwelch's avatar
zwelch committed
3050
	FILE *f = fopen(filename, "w");
zwelch's avatar
zwelch committed
3051
	if (f == NULL)
3052
		return;
3053
	writeString(f, "gmon");
3054
3055
3056
3057
	writeLong(f, 0x00000001); /* Version */
	writeLong(f, 0); /* padding */
	writeLong(f, 0); /* padding */
	writeLong(f, 0); /* padding */
oharboe's avatar
oharboe committed
3058

3059
	uint8_t zero = 0;  /* GMON_TAG_TIME_HIST */
3060
	writeData(f, &zero, 1);
3061

3062
	/* figure out bucket size */
zwelch's avatar
zwelch committed
3063
3064
	uint32_t min = samples[0];
	uint32_t max = samples[0];
zwelch's avatar
zwelch committed
3065
	for (i = 0; i < sampleNum; i++)
3066
	{
zwelch's avatar
zwelch committed
3067
		if (min > samples[i])
3068
		{
zwelch's avatar
zwelch committed
3069
			min = samples[i];
3070
		}
zwelch's avatar
zwelch committed
3071
		if (max < samples[i])
3072
		{
zwelch's avatar
zwelch committed
3073
			max = samples[i];
3074
3075
3076
		}
	}

zwelch's avatar
zwelch committed
3077
	int addressSpace = (max-min + 1);
oharboe's avatar
oharboe committed
3078

3079
3080
	static const uint32_t maxBuckets = 256 * 1024; /* maximum buckets. */
	uint32_t length = addressSpace;
3081
3082
	if (length > maxBuckets)
	{
zwelch's avatar
zwelch committed
3083
		length = maxBuckets;
3084
	}
zwelch's avatar
zwelch committed
3085
	int *buckets = malloc(sizeof(int)*length);
zwelch's avatar
zwelch committed
3086
	if (buckets == NULL)
3087
3088
3089
3090
3091
	{
		fclose(f);
		return;
	}
	memset(buckets, 0, sizeof(int)*length);
zwelch's avatar
zwelch committed
3092
	for (i = 0; i < sampleNum;i++)
3093
	{
zwelch's avatar
zwelch committed
3094
3095
3096
3097
		uint32_t address = samples[i];
		long long a = address-min;
		long long b = length-1;
		long long c = addressSpace-1;
Øyvind Harboe's avatar
Øyvind Harboe committed
3098
3099
		int index_t = (a*b)/c; /* danger!!!! int32 overflows */
		buckets[index_t]++;
3100
	}
oharboe's avatar
oharboe committed
3101

3102
3103
3104
3105
3106
	/* append binary memory gmon.out &profile_hist_hdr ((char*)&profile_hist_hdr + sizeof(struct gmon_hist_hdr)) */
	writeLong(f, min); 			/* low_pc */
	writeLong(f, max);			/* high_pc */
	writeLong(f, length);		/* # of samples */
	writeLong(f, 64000000); 	/* 64MHz */
3107
	writeString(f, "seconds");
zwelch's avatar
zwelch committed
3108
	for (i = 0; i < (15-strlen("seconds")); i++)
3109
		writeData(f, &zero, 1);
3110
	writeString(f, "s");
oharboe's avatar
oharboe committed
3111

3112
	/*append binary memory gmon.out profile_hist_data (profile_hist_data + profile_hist_hdr.hist_size) */
oharboe's avatar
oharboe committed
3113

zwelch's avatar
zwelch committed
3114
	char *data = malloc(2*length);
zwelch's avatar
zwelch committed
3115
	if (data != NULL)
3116
	{
zwelch's avatar
zwelch committed
3117
		for (i = 0; i < length;i++)
3118
3119
		{
			int val;
zwelch's avatar
zwelch committed
3120
			val = buckets[i];
zwelch's avatar
zwelch committed
3121
			if (val > 65535)
3122
			{
zwelch's avatar
zwelch committed
3123
				val = 65535;
3124
3125
			}
			data[i*2]=val&0xff;
zwelch's avatar
zwelch committed
3126
			data[i*2 + 1]=(val >> 8)&0xff;
3127
3128
		}
		free(buckets);
3129
		writeData(f, data, length * 2);
3130
3131
3132
3133
3134
3135
3136
3137
3138
		free(data);
	} else
	{
		free(buckets);
	}

	fclose(f);
}

3139
3140
/* profiling samples the CPU PC as quickly as OpenOCD is able,
 * which will be used as a random sampling of PC */
3141
COMMAND_HANDLER(handle_profile_command)
3142
{
3143
	struct target *target = get_current_target(CMD_CTX);
3144
	struct timeval timeout, now;
oharboe's avatar
oharboe committed
3145

3146
	gettimeofday(&timeout, NULL);
3147
	if (CMD_ARGC != 2)
3148
3149
3150
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
3151
	unsigned offset;
3152
	COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], offset);
3153
3154

	timeval_add_time(&timeout, offset, 0);
oharboe's avatar
oharboe committed
3155

3156
3157
3158
3159
3160
3161
	/**
	 * @todo: Some cores let us sample the PC without the
	 * annoying halt/resume step; for example, ARMv7 PCSR.
	 * Provide a way to use that more efficient mechanism.
	 */

3162
	command_print(CMD_CTX, "Starting profiling. Halting and resuming the target as often as we can...");
3163

zwelch's avatar
zwelch committed
3164
3165
	static const int maxSample = 10000;
	uint32_t *samples = malloc(sizeof(uint32_t)*maxSample);
zwelch's avatar
zwelch committed
3166
	if (samples == NULL)
3167
		return ERROR_OK;
oharboe's avatar
oharboe committed
3168

zwelch's avatar
zwelch committed
3169
	int numSamples = 0;
3170
	/* hopefully it is safe to cache! We want to stop/restart as quickly as possible. */
Zachary T Welch's avatar
Zachary T Welch committed
3171
	struct reg *reg = register_get_by_name(target->reg_cache, "pc", 1);
oharboe's avatar
oharboe committed
3172

3173
3174
	for (;;)
	{
3175
		int retval;
3176
		target_poll(target);
3177
3178
		if (target->state == TARGET_HALTED)
		{
3179
			uint32_t t=*((uint32_t *)reg->value);
3180
			samples[numSamples++]=t;
3181
3182
			retval = target_resume(target, 1, 0, 0, 0); /* current pc, addr = 0, do not handle breakpoints, not debugging */
			target_poll(target);
3183
			alive_sleep(10); /* sleep 10ms, i.e. <100 samples/second. */
3184
3185
		} else if (target->state == TARGET_RUNNING)
		{
3186
			/* We want to quickly sample the PC. */
zwelch's avatar
zwelch committed
3187
			if ((retval = target_halt(target)) != ERROR_OK)
3188
3189
3190
3191
			{
				free(samples);
				return retval;
			}
3192
3193
		} else
		{
3194
			command_print(CMD_CTX, "Target not halted or running");
zwelch's avatar
zwelch committed
3195
			retval = ERROR_OK;
3196
3197
			break;
		}
zwelch's avatar
zwelch committed
3198
		if (retval != ERROR_OK)
3199
3200
3201
		{
			break;
		}
oharboe's avatar
oharboe committed
3202

3203
		gettimeofday(&now, NULL);
zwelch's avatar
zwelch committed
3204
		if ((numSamples >= maxSample) || ((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec)))
3205
		{
3206
			command_print(CMD_CTX, "Profiling completed. %d samples.", numSamples);
zwelch's avatar
zwelch committed
3207
			if ((retval = target_poll(target)) != ERROR_OK)
3208
3209
3210
3211
			{
				free(samples);
				return retval;
			}
3212
3213
			if (target->state == TARGET_HALTED)
			{
3214
				target_resume(target, 1, 0, 0, 0); /* current pc, addr = 0, do not handle breakpoints, not debugging */
3215
			}
zwelch's avatar
zwelch committed
3216
			if ((retval = target_poll(target)) != ERROR_OK)
3217
3218
3219
3220
			{
				free(samples);
				return retval;
			}
3221
			writeGmon(samples, numSamples, CMD_ARGV[1]);
3222
			command_print(CMD_CTX, "Wrote %s", CMD_ARGV[1]);
3223
3224
3225
3226
			break;
		}
	}
	free(samples);
oharboe's avatar
oharboe committed
3227

3228
3229
	return ERROR_OK;
}
3230

3231
static int new_int_array_element(Jim_Interp * interp, const char *varname, int idx, uint32_t val)
3232
3233
3234
3235
3236
3237
3238
3239
{
	char *namebuf;
	Jim_Obj *nameObjPtr, *valObjPtr;
	int result;

	namebuf = alloc_printf("%s(%d)", varname, idx);
	if (!namebuf)
		return JIM_ERR;
oharboe's avatar
oharboe committed
3240

3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
	nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
	valObjPtr = Jim_NewIntObj(interp, val);
	if (!nameObjPtr || !valObjPtr)
	{
		free(namebuf);
		return JIM_ERR;
	}

	Jim_IncrRefCount(nameObjPtr);
	Jim_IncrRefCount(valObjPtr);
	result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
	Jim_DecrRefCount(interp, nameObjPtr);
	Jim_DecrRefCount(interp, valObjPtr);
	free(namebuf);
	/* printf("%s(%d) <= 0%08x\n", varname, idx, val); */
	return result;
}

static int jim_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
3261
	struct command_context *context;
Zachary T Welch's avatar
Zachary T Welch committed
3262
	struct target *target;
3263

3264
3265
3266
	context = current_command_context(interp);
	assert (context != NULL);

3267
3268
3269
3270
3271
3272
3273
	target = get_current_target(context);
	if (target == NULL)
	{
		LOG_ERROR("mem2array: no current target");
		return JIM_ERR;
	}

zwelch's avatar
zwelch committed
3274
	return 	target_mem2array(interp, target, argc-1, argv + 1);
3275
3276
}

Zachary T Welch's avatar
Zachary T Welch committed
3277
static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv)
3278
{
3279
	long l;
3280
	uint32_t width;
3281
	int len;
3282
3283
3284
	uint32_t addr;
	uint32_t count;
	uint32_t v;
3285
	const char *varname;
3286
	int  n, e, retval;
3287
	uint32_t i;
3288
3289
3290

	/* argv[1] = name of array to receive the data
	 * argv[2] = desired width
oharboe's avatar
oharboe committed
3291
	 * argv[3] = memory address
3292
3293
	 * argv[4] = count of times to read
	 */
3294
	if (argc != 4) {
3295
3296
3297
		Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems");
		return JIM_ERR;
	}
3298
	varname = Jim_GetString(argv[0], &len);
3299
3300
	/* given "foo" get space for worse case "foo(%d)" .. add 20 */

3301
	e = Jim_GetLong(interp, argv[1], &l);
3302
3303
3304
3305
	width = l;
	if (e != JIM_OK) {
		return e;
	}
oharboe's avatar
oharboe committed
3306

3307
	e = Jim_GetLong(interp, argv[2], &l);
3308
3309
3310
3311
	addr = l;
	if (e != JIM_OK) {
		return e;
	}
3312
	e = Jim_GetLong(interp, argv[3], &l);
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
	len = l;
	if (e != JIM_OK) {
		return e;
	}
	switch (width) {
		case 8:
			width = 1;
			break;
		case 16:
			width = 2;
			break;
		case 32:
			width = 4;
			break;
		default:
			Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
3329
			Jim_AppendStrings(interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL);
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
			return JIM_ERR;
	}
	if (len == 0) {
		Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
		Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: zero width read?", NULL);
		return JIM_ERR;
	}
	if ((addr + (len * width)) < addr) {
		Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
		Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: addr + len - wraps to zero?", NULL);
		return JIM_ERR;
	}
	/* absurd transfer size? */
	if (len > 65536) {
		Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
		Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: absurd > 64K item request", NULL);
		return JIM_ERR;
oharboe's avatar
oharboe committed
3347
3348
	}

3349
3350
3351
3352
3353
3354
3355
	if ((width == 1) ||
		((width == 2) && ((addr & 1) == 0)) ||
		((width == 4) && ((addr & 3) == 0))) {
		/* all is well */
	} else {
		char buf[100];
		Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
3356
3357
		sprintf(buf, "mem2array address: 0x%08" PRIx32 " is not aligned for %" PRId32 " byte reads",
				addr,
duane's avatar
duane committed
3358
				width);
3359
3360
3361
3362
3363
3364
3365
3366
		Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL);
		return JIM_ERR;
	}

	/* Transfer loop */

	/* index counter */
	n = 0;
Øyvind Harboe's avatar
Øyvind Harboe committed
3367
3368
3369
3370
3371
3372

	size_t buffersize = 4096;
	uint8_t *buffer = malloc(buffersize);
	if (buffer == NULL)
		return JIM_ERR;

3373
3374
3375
3376
	/* assume ok */
	e = JIM_OK;
	while (len) {
		/* Slurp... in buffer size chunks */
oharboe's avatar
oharboe committed
3377

3378
		count = len; /* in objects.. */
Øyvind Harboe's avatar
Øyvind Harboe committed
3379
3380
		if (count > (buffersize/width)) {
			count = (buffersize/width);
3381
		}
oharboe's avatar
oharboe committed
3382

3383
		retval = target_read_memory(target, addr, width, count, buffer);
3384
3385
		if (retval != ERROR_OK) {
			/* BOO !*/
3386
3387
3388
			LOG_ERROR("mem2array: Read @ 0x%08x, w=%d, cnt=%d, failed",
					  (unsigned int)addr,
					  (int)width,
duane's avatar
duane committed
3389
					  (int)count);
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
			Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
			Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL);
			e = JIM_ERR;
			len = 0;
		} else {
			v = 0; /* shut up gcc */
			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;
				}
				new_int_array_element(interp, varname, n, v);
			}
			len -= count;
		}
	}
oharboe's avatar
oharboe committed
3413

Øyvind Harboe's avatar
Øyvind Harboe committed
3414
3415
	free(buffer);

3416
3417
3418
3419
3420
	Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));

	return JIM_OK;
}

3421
static int get_int_array_element(Jim_Interp * interp, const char *varname, int idx, uint32_t *val)
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
{
	char *namebuf;
	Jim_Obj *nameObjPtr, *valObjPtr;
	int result;
	long l;

	namebuf = alloc_printf("%s(%d)", varname, idx);
	if (!namebuf)
		return JIM_ERR;

	nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
	if (!nameObjPtr)
	{
		free(namebuf);
		return JIM_ERR;
	}

	Jim_IncrRefCount(nameObjPtr);
	valObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_ERRMSG);
	Jim_DecrRefCount(interp, nameObjPtr);
	free(namebuf);
	if (valObjPtr == NULL)
		return JIM_ERR;

	result = Jim_GetLong(interp, valObjPtr, &l);
	/* printf("%s(%d) => 0%08x\n", varname, idx, val); */
	*val = l;
	return result;
}

static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
3454
	struct command_context *context;
Zachary T Welch's avatar
Zachary T Welch committed
3455
	struct target *target;
3456

3457
3458
3459
	context = current_command_context(interp);
	assert (context != NULL);

3460
	target = get_current_target(context);
zwelch's avatar
zwelch committed
3461
	if (target == NULL) {
3462
3463
3464
		LOG_ERROR("array2mem: no current target");
		return JIM_ERR;
	}
3465

3466
	return target_array2mem(interp,target, argc-1, argv + 1);
3467
}
3468
3469
3470

static int target_array2mem(Jim_Interp *interp, struct target *target,
		int argc, Jim_Obj *const *argv)
3471
{
3472
	long l;
3473
	uint32_t width;
3474
	int len;
3475
3476
3477
	uint32_t addr;
	uint32_t count;
	uint32_t v;
3478
	const char *varname;
3479
	int  n, e, retval;
3480
	uint32_t i;
3481
3482
3483

	/* argv[1] = name of array to get the data
	 * argv[2] = desired width
oharboe's avatar
oharboe committed
3484
	 * argv[3] = memory address
3485
3486
	 * argv[4] = count to write
	 */
3487
	if (argc != 4) {
3488
		Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems");
3489
3490
		return JIM_ERR;
	}
3491
	varname = Jim_GetString(argv[0], &len);
3492
3493
	/* given "foo" get space for worse case "foo(%d)" .. add 20 */

3494
	e = Jim_GetLong(interp, argv[1], &l);
3495
3496
3497
3498
	width = l;
	if (e != JIM_OK) {
		return e;
	}
oharboe's avatar
oharboe committed
3499

3500
	e = Jim_GetLong(interp, argv[2], &l);
3501
3502
3503
3504
	addr = l;
	if (e != JIM_OK) {
		return e;
	}
3505
	e = Jim_GetLong(interp, argv[3], &l);
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
	len = l;
	if (e != JIM_OK) {
		return e;
	}
	switch (width) {
		case 8:
			width = 1;
			break;
		case 16:
			width = 2;
			break;
		case 32:
			width = 4;
			break;
		default:
			Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
3522
			Jim_AppendStrings(interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL);
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
			return JIM_ERR;
	}
	if (len == 0) {
		Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
		Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: zero width read?", NULL);
		return JIM_ERR;
	}
	if ((addr + (len * width)) < addr) {
		Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
		Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: addr + len - wraps to zero?", NULL);
		return JIM_ERR;
	}
	/* absurd transfer size? */
	if (len > 65536) {
		Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
		Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: absurd > 64K item request", NULL);
		return JIM_ERR;
oharboe's avatar
oharboe committed
3540
3541
	}

3542
3543
3544
3545
3546
3547
3548
	if ((width == 1) ||
		((width == 2) && ((addr & 1) == 0)) ||
		((width == 4) && ((addr & 3) == 0))) {
		/* all is well */
	} else {
		char buf[100];
		Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
3549
3550
		sprintf(buf, "array2mem address: 0x%08x is not aligned for %d byte reads",
				(unsigned int)addr,
duane's avatar
duane committed
3551
				(int)width);
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
		Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL);
		return JIM_ERR;
	}

	/* Transfer loop */

	/* index counter */
	n = 0;
	/* assume ok */
	e = JIM_OK;
Øyvind Harboe's avatar
Øyvind Harboe committed
3562
3563
3564
3565
3566
3567

	size_t buffersize = 4096;
	uint8_t *buffer = malloc(buffersize);
	if (buffer == NULL)
		return JIM_ERR;

3568
3569
	while (len) {
		/* Slurp... in buffer size chunks */
oharboe's avatar
oharboe committed
3570

3571
		count = len; /* in objects.. */
Øyvind Harboe's avatar
Øyvind Harboe committed
3572
3573
		if (count > (buffersize/width)) {
			count = (buffersize/width);
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
		}

		v = 0; /* shut up gcc */
		for (i = 0 ;i < count ;i++, n++) {
			get_int_array_element(interp, varname, n, &v);
			switch (width) {
			case 4:
				target_buffer_set_u32(target, &buffer[i*width], v);
				break;
			case 2:
				target_buffer_set_u16(target, &buffer[i*width], v);
				break;
			case 1:
				buffer[i] = v & 0x0ff;
				break;
			}
		}
		len -= count;

zwelch's avatar
zwelch committed
3593
		retval = target_write_memory(target, addr, width, count, buffer);
3594
3595
		if (retval != ERROR_OK) {
			/* BOO !*/
3596
3597
3598
			LOG_ERROR("array2mem: Write @ 0x%08x, w=%d, cnt=%d, failed",
					  (unsigned int)addr,
					  (int)width,
duane's avatar
duane committed
3599
					  (int)count);
3600
			Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
3601
			Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: cannot read memory", NULL);
3602
3603
3604
3605
			e = JIM_ERR;
			len = 0;
		}
	}
oharboe's avatar
oharboe committed
3606

Øyvind Harboe's avatar
Øyvind Harboe committed
3607
3608
	free(buffer);

3609
3610
3611
3612
	Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));

	return JIM_OK;
}
3613

3614
3615
3616
/* FIX? should we propagate errors here rather than printing them
 * and continuing?
 */
Zachary T Welch's avatar
Zachary T Welch committed
3617
void target_handle_event(struct target *target, enum target_event e)
3618
{
3619
	struct target_event_action *teap;
3620

dbrownell's avatar
dbrownell committed
3621
	for (teap = target->event_action; teap != NULL; teap = teap->next) {
zwelch's avatar
zwelch committed
3622
		if (teap->event == e) {
3623
			LOG_DEBUG("target: (%d) %s (%s) event: %d (%s) action: %s",
3624
					   target->target_number,
3625
					   target_name(target),
3626
					   target_type_name(target),
3627
					   e,
3628
3629
					   Jim_Nvp_value2name_simple(nvp_target_event, e)->name,
					   Jim_GetString(teap->body, NULL));
3630
			if (Jim_EvalObj(teap->interp, teap->body) != JIM_OK)
3631
			{
3632
				Jim_PrintErrorMessage(teap->interp);
3633
			}
3634
3635
3636
3637
		}
	}
}

3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
/**
 * Returns true only if the target has a handler for the specified event.
 */
bool target_has_event_action(struct target *target, enum target_event event)
{
	struct target_event_action *teap;

	for (teap = target->event_action; teap != NULL; teap = teap->next) {
		if (teap->event == event)
			return true;
	}
	return false;
}

3652
3653
enum target_cfg_param {
	TCFG_TYPE,
3654
	TCFG_EVENT,
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
	TCFG_WORK_AREA_VIRT,
	TCFG_WORK_AREA_PHYS,
	TCFG_WORK_AREA_SIZE,
	TCFG_WORK_AREA_BACKUP,
	TCFG_ENDIAN,
	TCFG_VARIANT,
	TCFG_CHAIN_POSITION,
};

static Jim_Nvp nvp_config_opts[] = {
	{ .name = "-type",             .value = TCFG_TYPE },
	{ .name = "-event",            .value = TCFG_EVENT },
	{ .name = "-work-area-virt",   .value = TCFG_WORK_AREA_VIRT },
	{ .name = "-work-area-phys",   .value = TCFG_WORK_AREA_PHYS },
	{ .name = "-work-area-size",   .value = TCFG_WORK_AREA_SIZE },
	{ .name = "-work-area-backup", .value = TCFG_WORK_AREA_BACKUP },
	{ .name = "-endian" ,          .value = TCFG_ENDIAN },
	{ .name = "-variant",          .value = TCFG_VARIANT },
	{ .name = "-chain-position",   .value = TCFG_CHAIN_POSITION },
3674

3675
3676
	{ .name = NULL, .value = -1 }
};
3677

Zachary T Welch's avatar
Zachary T Welch committed
3678
static int target_configure(Jim_GetOptInfo *goi, struct target *target)
3679
3680
3681
3682
3683
3684
3685
3686
{
	Jim_Nvp *n;
	Jim_Obj *o;
	jim_wide w;
	char *cp;
	int e;

	/* parse config or cget options ... */
zwelch's avatar
zwelch committed
3687
	while (goi->argc > 0) {
3688
3689
		Jim_SetEmptyResult(goi->interp);
		/* Jim_GetOpt_Debug(goi); */
3690

zwelch's avatar
zwelch committed
3691
		if (target->type->target_jim_configure) {
3692
3693
			/* target defines a configure function */
			/* target gets first dibs on parameters */
3694
			e = (*(target->type->target_jim_configure))(target, goi);
zwelch's avatar
zwelch committed
3695
			if (e == JIM_OK) {
3696
3697
3698
				/* more? */
				continue;
			}
zwelch's avatar
zwelch committed
3699
			if (e == JIM_ERR) {
3700
3701
3702
3703
3704
				/* An error */
				return e;
			}
			/* otherwise we 'continue' below */
		}
3705
		e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n);
zwelch's avatar
zwelch committed
3706
		if (e != JIM_OK) {
3707
			Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0);
3708
3709
			return e;
		}
zwelch's avatar
zwelch committed
3710
		switch (n->value) {
3711
3712
		case TCFG_TYPE:
			/* not setable */
zwelch's avatar
zwelch committed
3713
			if (goi->isconfigure) {
3714
3715
				Jim_SetResult_sprintf(goi->interp,
						"not settable: %s", n->name);
3716
3717
3718
				return JIM_ERR;
			} else {
			no_params:
zwelch's avatar
zwelch committed
3719
				if (goi->argc != 0) {
3720
3721
3722
					Jim_WrongNumArgs(goi->interp,
							goi->argc, goi->argv,
							"NO PARAMS");
3723
3724
3725
					return JIM_ERR;
				}
			}
3726
3727
			Jim_SetResultString(goi->interp,
					target_type_name(target), -1);
3728
3729
3730
			/* loop for more */
			break;
		case TCFG_EVENT:
zwelch's avatar
zwelch committed
3731
			if (goi->argc == 0) {
3732
				Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ...");
3733
3734
3735
				return JIM_ERR;
			}

3736
			e = Jim_GetOpt_Nvp(goi, nvp_target_event, &n);
zwelch's avatar
zwelch committed
3737
			if (e != JIM_OK) {
3738
				Jim_GetOpt_NvpUnknown(goi, nvp_target_event, 1);
3739
3740
3741
				return e;
			}

zwelch's avatar
zwelch committed
3742
3743
			if (goi->isconfigure) {
				if (goi->argc != 1) {
3744
					Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?");
3745
					return JIM_ERR;
3746
				}
3747
			} else {
zwelch's avatar
zwelch committed
3748
				if (goi->argc != 0) {
3749
3750
3751
3752
3753
					Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name?");
					return JIM_ERR;
				}
			}

3754
			{
3755
				struct target_event_action *teap;
3756

3757
3758
				teap = target->event_action;
				/* replace existing? */
zwelch's avatar
zwelch committed
3759
3760
				while (teap) {
					if (teap->event == (enum target_event)n->value) {
3761
3762
3763
3764
						break;
					}
					teap = teap->next;
				}
3765

zwelch's avatar
zwelch committed
3766
				if (goi->isconfigure) {
3767
					bool replace = true;
zwelch's avatar
zwelch committed
3768
					if (teap == NULL) {
3769
						/* create new */
3770
						teap = calloc(1, sizeof(*teap));
3771
						replace = false;
3772
3773
					}
					teap->event = n->value;
3774
					teap->interp = goi->interp;
3775
					Jim_GetOpt_Obj(goi, &o);
zwelch's avatar
zwelch committed
3776
					if (teap->body) {
3777
						Jim_DecrRefCount(teap->interp, teap->body);
3778
					}
3779
					teap->body  = Jim_DuplicateObj(goi->interp, o);
3780
					/*
3781
					 * FIXME:
3782
3783
3784
3785
3786
3787
3788
3789
					 *     Tcl/TK - "tk events" have a nice feature.
					 *     See the "BIND" command.
					 *    We should support that here.
					 *     You can specify %X and %Y in the event code.
					 *     The idea is: %T - target name.
					 *     The idea is: %N - target number
					 *     The idea is: %E - event name.
					 */
3790
					Jim_IncrRefCount(teap->body);
3791

3792
3793
3794
3795
3796
3797
					if (!replace)
					{
						/* add to head of event list */
						teap->next = target->event_action;
						target->event_action = teap;
					}
3798
3799
3800
					Jim_SetEmptyResult(goi->interp);
				} else {
					/* get */
zwelch's avatar
zwelch committed
3801
					if (teap == NULL) {
3802
						Jim_SetEmptyResult(goi->interp);
3803
					} else {
3804
						Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, teap->body));
3805
3806
3807
3808
3809
3810
3811
					}
				}
			}
			/* loop for more */
			break;

		case TCFG_WORK_AREA_VIRT:
zwelch's avatar
zwelch committed
3812
			if (goi->isconfigure) {
3813
				target_free_all_working_areas(target);
3814
				e = Jim_GetOpt_Wide(goi, &w);
zwelch's avatar
zwelch committed
3815
				if (e != JIM_OK) {
3816
3817
3818
					return e;
				}
				target->working_area_virt = w;
3819
				target->working_area_virt_spec = true;
3820
			} else {
zwelch's avatar
zwelch committed
3821
				if (goi->argc != 0) {
3822
3823
					goto no_params;
				}
3824
			}
3825
			Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_virt));
3826
3827
			/* loop for more */
			break;
3828

3829
		case TCFG_WORK_AREA_PHYS:
zwelch's avatar
zwelch committed
3830
			if (goi->isconfigure) {
3831
				target_free_all_working_areas(target);
3832
				e = Jim_GetOpt_Wide(goi, &w);
zwelch's avatar
zwelch committed
3833
				if (e != JIM_OK) {
3834
3835
3836
					return e;
				}
				target->working_area_phys = w;
3837
				target->working_area_phys_spec = true;
3838
			} else {
zwelch's avatar
zwelch committed
3839
				if (goi->argc != 0) {
3840
3841
					goto no_params;
				}
3842
			}
3843
			Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_phys));
3844
3845
3846
3847
			/* loop for more */
			break;

		case TCFG_WORK_AREA_SIZE:
zwelch's avatar
zwelch committed
3848
			if (goi->isconfigure) {
3849
				target_free_all_working_areas(target);
3850
				e = Jim_GetOpt_Wide(goi, &w);
zwelch's avatar
zwelch committed
3851
				if (e != JIM_OK) {
3852
3853
3854
3855
					return e;
				}
				target->working_area_size = w;
			} else {
zwelch's avatar
zwelch committed
3856
				if (goi->argc != 0) {
3857
3858
					goto no_params;
				}
3859
			}
3860
			Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_size));
3861
3862
3863
3864
			/* loop for more */
			break;

		case TCFG_WORK_AREA_BACKUP:
zwelch's avatar
zwelch committed
3865
			if (goi->isconfigure) {
3866
				target_free_all_working_areas(target);
3867
				e = Jim_GetOpt_Wide(goi, &w);
zwelch's avatar
zwelch committed
3868
				if (e != JIM_OK) {
3869
3870
3871
3872
3873
					return e;
				}
				/* make this exactly 1 or 0 */
				target->backup_working_area = (!!w);
			} else {
zwelch's avatar
zwelch committed
3874
				if (goi->argc != 0) {
3875
3876
					goto no_params;
				}
3877
			}
3878
			Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->backup_working_area));
3879
3880
3881
3882
			/* loop for more e*/
			break;

		case TCFG_ENDIAN:
zwelch's avatar
zwelch committed
3883
			if (goi->isconfigure) {
3884
				e = Jim_GetOpt_Nvp(goi, nvp_target_endian, &n);
zwelch's avatar
zwelch committed
3885
				if (e != JIM_OK) {
3886
					Jim_GetOpt_NvpUnknown(goi, nvp_target_endian, 1);
3887
3888
3889
3890
					return e;
				}
				target->endianness = n->value;
			} else {
zwelch's avatar
zwelch committed
3891
				if (goi->argc != 0) {
3892
3893
3894
					goto no_params;
				}
			}
3895
			n = Jim_Nvp_value2name_simple(nvp_target_endian, target->endianness);
zwelch's avatar
zwelch committed
3896
			if (n->name == NULL) {
3897
				target->endianness = TARGET_LITTLE_ENDIAN;
3898
				n = Jim_Nvp_value2name_simple(nvp_target_endian, target->endianness);
3899
			}
3900
			Jim_SetResultString(goi->interp, n->name, -1);
3901
3902
3903
3904
			/* loop for more */
			break;

		case TCFG_VARIANT:
zwelch's avatar
zwelch committed
3905
3906
			if (goi->isconfigure) {
				if (goi->argc < 1) {
3907
					Jim_SetResult_sprintf(goi->interp,
3908
										   "%s ?STRING?",
3909
										   n->name);
oharboe's avatar