target.c 118 KB
Newer Older
1
2
3
4
/***************************************************************************
 *   Copyright (C) 2005 by Dominic Rath                                    *
 *   Dominic.Rath@gmx.de                                                   *
 *                                                                         *
5
 *   Copyright (C) 2007-2009 Øyvind Harboe                                 *
6
7
 *   oyvind.harboe@zylin.com                                               *
 *                                                                         *
8
9
10
 *   Copyright (C) 2008, Duane Ellis                                       *
 *   openocd@duaneeellis.com                                               *
 *                                                                         *
11
12
13
 *   Copyright (C) 2008 by Spencer Oliver                                  *
 *   spen@spen-soft.co.uk                                                  *
 *                                                                         *
14
15
16
 *   Copyright (C) 2008 by Rick Altherr                                    *
 *   kc8apf@kc8apf.net>                                                    *
 *                                                                         *
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "target.h"
37
#include "target_type.h"
38
#include "target_request.h"
39
40
41
42
#include "time_support.h"
#include "register.h"
#include "trace.h"
#include "image.h"
43
44
45
#include "jtag.h"


46
static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
47

48
49
50
static int target_array2mem(Jim_Interp *interp, target_t *target, int argc, Jim_Obj *const *argv);
static int target_mem2array(Jim_Interp *interp, target_t *target, int argc, Jim_Obj *const *argv);

51
/* targets */
52
53
54
55
56
57
extern target_type_t arm7tdmi_target;
extern target_type_t arm720t_target;
extern target_type_t arm9tdmi_target;
extern target_type_t arm920t_target;
extern target_type_t arm966e_target;
extern target_type_t arm926ejs_target;
58
extern target_type_t fa526_target;
59
extern target_type_t feroceon_target;
60
extern target_type_t dragonite_target;
61
62
extern target_type_t xscale_target;
extern target_type_t cortexm3_target;
63
extern target_type_t cortexa8_target;
oharboe's avatar
oharboe committed
64
extern target_type_t arm11_target;
ntfreak's avatar
ntfreak committed
65
extern target_type_t mips_m4k_target;
66
extern target_type_t avr_target;
67
68
69
70
71
72
73
74
75

target_type_t *target_types[] =
{
	&arm7tdmi_target,
	&arm9tdmi_target,
	&arm920t_target,
	&arm720t_target,
	&arm966e_target,
	&arm926ejs_target,
76
	&fa526_target,
77
	&feroceon_target,
78
	&dragonite_target,
79
80
	&xscale_target,
	&cortexm3_target,
81
	&cortexa8_target,
oharboe's avatar
oharboe committed
82
	&arm11_target,
ntfreak's avatar
ntfreak committed
83
	&mips_m4k_target,
84
	&avr_target,
85
86
87
	NULL,
};

88
target_t *all_targets = NULL;
89
90
91
target_event_callback_t *target_event_callbacks = NULL;
target_timer_callback_t *target_timer_callbacks = NULL;

92
93
94
95
96
97
98
99
const Jim_Nvp nvp_assert[] = {
	{ .name = "assert", NVP_ASSERT },
	{ .name = "deassert", NVP_DEASSERT },
	{ .name = "T", NVP_ASSERT },
	{ .name = "F", NVP_DEASSERT },
	{ .name = "t", NVP_ASSERT },
	{ .name = "f", NVP_DEASSERT },
	{ .name = NULL, .value = -1 }
100
101
};

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
const Jim_Nvp nvp_error_target[] = {
	{ .value = ERROR_TARGET_INVALID, .name = "err-invalid" },
	{ .value = ERROR_TARGET_INIT_FAILED, .name = "err-init-failed" },
	{ .value = ERROR_TARGET_TIMEOUT, .name = "err-timeout" },
	{ .value = ERROR_TARGET_NOT_HALTED, .name = "err-not-halted" },
	{ .value = ERROR_TARGET_FAILURE, .name = "err-failure" },
	{ .value = ERROR_TARGET_UNALIGNED_ACCESS   , .name = "err-unaligned-access" },
	{ .value = ERROR_TARGET_DATA_ABORT , .name = "err-data-abort" },
	{ .value = ERROR_TARGET_RESOURCE_NOT_AVAILABLE , .name = "err-resource-not-available" },
	{ .value = ERROR_TARGET_TRANSLATION_FAULT  , .name = "err-translation-fault" },
	{ .value = ERROR_TARGET_NOT_RUNNING, .name = "err-not-running" },
	{ .value = ERROR_TARGET_NOT_EXAMINED, .name = "err-not-examined" },
	{ .value = -1, .name = NULL }
};

117
const char *target_strerror_safe(int err)
118
119
120
{
	const Jim_Nvp *n;

121
	n = Jim_Nvp_value2name_simple(nvp_error_target, err);
zwelch's avatar
zwelch committed
122
	if (n->name == NULL) {
123
124
125
126
127
128
		return "unknown";
	} else {
		return n->name;
	}
}

129
static const Jim_Nvp nvp_target_event[] = {
130
131
	{ .value = TARGET_EVENT_OLD_gdb_program_config , .name = "old-gdb_program_config" },
	{ .value = TARGET_EVENT_OLD_pre_resume         , .name = "old-pre_resume" },
132

133
	{ .value = TARGET_EVENT_GDB_HALT, .name = "gdb-halt" },
134
135
136
137
138
	{ .value = TARGET_EVENT_HALTED, .name = "halted" },
	{ .value = TARGET_EVENT_RESUMED, .name = "resumed" },
	{ .value = TARGET_EVENT_RESUME_START, .name = "resume-start" },
	{ .value = TARGET_EVENT_RESUME_END, .name = "resume-end" },

139
140
141
	{ .name = "gdb-start", .value = TARGET_EVENT_GDB_START },
	{ .name = "gdb-end", .value = TARGET_EVENT_GDB_END },

142
	/* historical name */
143

144
	{ .value = TARGET_EVENT_RESET_START, .name = "reset-start" },
145
146
147
148
149
150
151
152
153

	{ .value = TARGET_EVENT_RESET_ASSERT_PRE,    .name = "reset-assert-pre" },
	{ .value = TARGET_EVENT_RESET_ASSERT_POST,   .name = "reset-assert-post" },
	{ .value = TARGET_EVENT_RESET_DEASSERT_PRE,  .name = "reset-deassert-pre" },
	{ .value = TARGET_EVENT_RESET_DEASSERT_POST, .name = "reset-deassert-post" },
	{ .value = TARGET_EVENT_RESET_HALT_PRE,      .name = "reset-halt-pre" },
	{ .value = TARGET_EVENT_RESET_HALT_POST,     .name = "reset-halt-post" },
	{ .value = TARGET_EVENT_RESET_WAIT_PRE,      .name = "reset-wait-pre" },
	{ .value = TARGET_EVENT_RESET_WAIT_POST,     .name = "reset-wait-post" },
154
155
156
	{ .value = TARGET_EVENT_RESET_INIT , .name = "reset-init" },
	{ .value = TARGET_EVENT_RESET_END, .name = "reset-end" },

157
	{ .value = TARGET_EVENT_EXAMINE_START, .name = "examine-start" },
158
	{ .value = TARGET_EVENT_EXAMINE_END, .name = "examine-end" },
159

160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
	{ .value = TARGET_EVENT_DEBUG_HALTED, .name = "debug-halted" },
	{ .value = TARGET_EVENT_DEBUG_RESUMED, .name = "debug-resumed" },

	{ .value = TARGET_EVENT_GDB_ATTACH, .name = "gdb-attach" },
	{ .value = TARGET_EVENT_GDB_DETACH, .name = "gdb-detach" },

	{ .value = TARGET_EVENT_GDB_FLASH_WRITE_START, .name = "gdb-flash-write-start" },
	{ .value = TARGET_EVENT_GDB_FLASH_WRITE_END  , .name = "gdb-flash-write-end"   },

	{ .value = TARGET_EVENT_GDB_FLASH_ERASE_START, .name = "gdb-flash-erase-start" },
	{ .value = TARGET_EVENT_GDB_FLASH_ERASE_END  , .name = "gdb-flash-erase-end" },

	{ .value = TARGET_EVENT_RESUME_START, .name = "resume-start" },
	{ .value = TARGET_EVENT_RESUMED     , .name = "resume-ok" },
	{ .value = TARGET_EVENT_RESUME_END  , .name = "resume-end" },

	{ .name = NULL, .value = -1 }
177
178
};

179
180
181
182
183
184
185
const Jim_Nvp nvp_target_state[] = {
	{ .name = "unknown", .value = TARGET_UNKNOWN },
	{ .name = "running", .value = TARGET_RUNNING },
	{ .name = "halted",  .value = TARGET_HALTED },
	{ .name = "reset",   .value = TARGET_RESET },
	{ .name = "debug-running", .value = TARGET_DEBUG_RUNNING },
	{ .name = NULL, .value = -1 },
186
187
};

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
const Jim_Nvp nvp_target_debug_reason [] = {
	{ .name = "debug-request"            , .value = DBG_REASON_DBGRQ },
	{ .name = "breakpoint"               , .value = DBG_REASON_BREAKPOINT },
	{ .name = "watchpoint"               , .value = DBG_REASON_WATCHPOINT },
	{ .name = "watchpoint-and-breakpoint", .value = DBG_REASON_WPTANDBKPT },
	{ .name = "single-step"              , .value = DBG_REASON_SINGLESTEP },
	{ .name = "target-not-halted"        , .value = DBG_REASON_NOTHALTED  },
	{ .name = "undefined"                , .value = DBG_REASON_UNDEFINED },
	{ .name = NULL, .value = -1 },
};

const Jim_Nvp nvp_target_endian[] = {
	{ .name = "big",    .value = TARGET_BIG_ENDIAN },
	{ .name = "little", .value = TARGET_LITTLE_ENDIAN },
	{ .name = "be",     .value = TARGET_BIG_ENDIAN },
203
	{ .name = "le",     .value = TARGET_LITTLE_ENDIAN },
204
205
206
	{ .name = NULL,     .value = -1 },
};

207
208
209
210
211
212
213
214
const Jim_Nvp nvp_reset_modes[] = {
	{ .name = "unknown", .value = RESET_UNKNOWN },
	{ .name = "run"    , .value = RESET_RUN },
	{ .name = "halt"   , .value = RESET_HALT },
	{ .name = "init"   , .value = RESET_INIT },
	{ .name = NULL     , .value = -1 },
};

215
216
217
218
219
220
221
222
223
224
225
226
const char *
target_state_name( target_t *t )
{
	const char *cp;
	cp = Jim_Nvp_value2name_simple(nvp_target_state, t->state)->name;
	if( !cp ){
		LOG_ERROR("Invalid target state: %d", (int)(t->state));
		cp = "(*BUG*unknown*BUG*)";
	}
	return cp;
}

227
/* determine the number of the new target */
228
static int new_target_number(void)
229
230
231
232
233
234
235
{
	target_t *t;
	int x;

	/* number is 0 based */
	x = -1;
	t = all_targets;
zwelch's avatar
zwelch committed
236
237
	while (t) {
		if (x < t->target_number) {
238
239
240
241
			x = t->target_number;
		}
		t = t->next;
	}
zwelch's avatar
zwelch committed
242
	return x + 1;
243
244
}

245
246
/* read a uint32_t from a buffer in target memory endianness */
uint32_t target_buffer_get_u32(target_t *target, const uint8_t *buffer)
247
248
249
250
251
252
253
{
	if (target->endianness == TARGET_LITTLE_ENDIAN)
		return le_to_h_u32(buffer);
	else
		return be_to_h_u32(buffer);
}

zwelch's avatar
zwelch committed
254
255
/* read a uint16_t from a buffer in target memory endianness */
uint16_t target_buffer_get_u16(target_t *target, const uint8_t *buffer)
256
257
258
259
260
261
262
{
	if (target->endianness == TARGET_LITTLE_ENDIAN)
		return le_to_h_u16(buffer);
	else
		return be_to_h_u16(buffer);
}

263
264
/* read a uint8_t from a buffer in target memory endianness */
uint8_t target_buffer_get_u8(target_t *target, const uint8_t *buffer)
265
266
267
268
{
	return *buffer & 0x0ff;
}

269
270
/* write a uint32_t to a buffer in target memory endianness */
void target_buffer_set_u32(target_t *target, uint8_t *buffer, uint32_t value)
271
272
273
274
275
276
277
{
	if (target->endianness == TARGET_LITTLE_ENDIAN)
		h_u32_to_le(buffer, value);
	else
		h_u32_to_be(buffer, value);
}

zwelch's avatar
zwelch committed
278
279
/* write a uint16_t to a buffer in target memory endianness */
void target_buffer_set_u16(target_t *target, uint8_t *buffer, uint16_t value)
280
281
282
283
284
285
286
{
	if (target->endianness == TARGET_LITTLE_ENDIAN)
		h_u16_to_le(buffer, value);
	else
		h_u16_to_be(buffer, value);
}

287
288
/* write a uint8_t to a buffer in target memory endianness */
void target_buffer_set_u8(target_t *target, uint8_t *buffer, uint8_t value)
289
290
291
292
{
	*buffer = value;
}

293
294
295
296
297
298
299
300
301
302
303
304
305
/* return a pointer to a configured target; id is name or number */
target_t *get_target(const char *id)
{
	target_t *target;

	/* try as tcltarget name */
	for (target = all_targets; target; target = target->next) {
		if (target->cmd_name == NULL)
			continue;
		if (strcmp(id, target->cmd_name) == 0)
			return target;
	}

306
307
	/* It's OK to remove this fallback sometime after August 2010 or so */

308
	/* no match, try as number */
309
310
	unsigned num;
	if (parse_uint(id, &num) != ERROR_OK)
311
312
313
		return NULL;

	for (target = all_targets; target; target = target->next) {
314
315
316
		if (target->target_number == (int)num) {
			LOG_WARNING("use '%s' as target identifier, not '%u'",
					target->cmd_name, num);
317
			return target;
318
		}
319
320
321
322
323
	}

	return NULL;
}

324
/* returns a pointer to the n-th configured target */
325
static target_t *get_target_by_num(int num)
326
{
327
	target_t *target = all_targets;
328

zwelch's avatar
zwelch committed
329
330
	while (target) {
		if (target->target_number == num) {
331
			return target;
332
		}
333
334
335
336
337
338
339
340
341
		target = target->next;
	}

	return NULL;
}

target_t* get_current_target(command_context_t *cmd_ctx)
{
	target_t *target = get_target_by_num(cmd_ctx->current_target);
oharboe's avatar
oharboe committed
342

343
344
	if (target == NULL)
	{
345
		LOG_ERROR("BUG: current_target out of bounds");
346
347
348
		exit(-1);
	}

oharboe's avatar
oharboe committed
349
	return target;
350
351
}

352
353
int target_poll(struct target_s *target)
{
354
355
	int retval;

356
	/* We can't poll until after examine */
357
	if (!target_was_examined(target))
358
359
360
361
	{
		/* Fail silently lest we pollute the log */
		return ERROR_FAIL;
	}
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384

	retval = target->type->poll(target);
	if (retval != ERROR_OK)
		return retval;

	if (target->halt_issued)
	{
		if (target->state == TARGET_HALTED)
		{
			target->halt_issued = false;
		} else
		{
			long long t = timeval_ms() - target->halt_issued_time;
			if (t>1000)
			{
				target->halt_issued = false;
				LOG_INFO("Halt timed out, wake up GDB.");
				target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
			}
		}
	}

	return ERROR_OK;
385
386
387
388
}

int target_halt(struct target_s *target)
{
389
	int retval;
390
	/* We can't poll until after examine */
391
	if (!target_was_examined(target))
392
393
394
395
	{
		LOG_ERROR("Target not examined yet");
		return ERROR_FAIL;
	}
396
397
398
399
400
401
402
403
404

	retval = target->type->halt(target);
	if (retval != ERROR_OK)
		return retval;

	target->halt_issued = true;
	target->halt_issued_time = timeval_ms();

	return ERROR_OK;
405
406
}

407
int target_resume(struct target_s *target, int current, uint32_t address, int handle_breakpoints, int debug_execution)
408
{
409
	int retval;
oharboe's avatar
oharboe committed
410

411
	/* We can't poll until after examine */
412
	if (!target_was_examined(target))
413
414
415
416
	{
		LOG_ERROR("Target not examined yet");
		return ERROR_FAIL;
	}
oharboe's avatar
oharboe committed
417

oharboe's avatar
oharboe committed
418
419
420
421
	/* note that resume *must* be asynchronous. The CPU can halt before we poll. The CPU can
	 * even halt at the current PC as a result of a software breakpoint being inserted by (a bug?)
	 * the application.
	 */
422
423
	if ((retval = target->type->resume(target, current, address, handle_breakpoints, debug_execution)) != ERROR_OK)
		return retval;
oharboe's avatar
oharboe committed
424

425
	return retval;
426
427
}

oharboe's avatar
oharboe committed
428
int target_process_reset(struct command_context_s *cmd_ctx, enum target_reset_mode reset_mode)
429
430
{
	char buf[100];
431
	int retval;
432
	Jim_Nvp *n;
433
	n = Jim_Nvp_value2name_simple(nvp_reset_modes, reset_mode);
zwelch's avatar
zwelch committed
434
	if (n->name == NULL) {
435
436
437
438
		LOG_ERROR("invalid reset mode");
		return ERROR_FAIL;
	}

439
440
441
442
	/* disable polling during reset to make reset event scripts
	 * more predictable, i.e. dr/irscan & pathmove in events will
	 * not have JTAG operations injected into the middle of a sequence.
	 */
443
444
445
	bool save_poll = jtag_poll_get_enabled();

	jtag_poll_set_enabled(false);
446

447
448
	sprintf(buf, "ocd_process_reset %s", n->name);
	retval = Jim_Eval(interp, buf);
449

450
	jtag_poll_set_enabled(save_poll);
451

zwelch's avatar
zwelch committed
452
	if (retval != JIM_OK) {
453
		Jim_PrintErrorMessage(interp);
454
455
		return ERROR_FAIL;
	}
456
457

	/* We want any events to be processed before the prompt */
458
	retval = target_call_timer_callbacks_now();
459

460
	return retval;
461
462
}

463
static int default_virt2phys(struct target_s *target, uint32_t virtual, uint32_t *physical)
464
465
466
467
468
469
470
{
	*physical = virtual;
	return ERROR_OK;
}

static int default_mmu(struct target_s *target, int *enabled)
{
471
	*enabled = 0;
472
473
474
	return ERROR_OK;
}

475
static int default_examine(struct target_s *target)
476
{
477
	target_set_examined(target);
478
479
480
	return ERROR_OK;
}

zwelch's avatar
zwelch committed
481
482
483
484
485
int target_examine_one(struct target_s *target)
{
	return target->type->examine(target);
}

zwelch's avatar
zwelch committed
486
487
488
489
490
491
492
493
494
495
496
497
static int jtag_enable_callback(enum jtag_event event, void *priv)
{
	target_t *target = priv;

	if (event != JTAG_TAP_EVENT_ENABLE || !target->tap->enabled)
		return ERROR_OK;

	jtag_unregister_event_callback(jtag_enable_callback, target);
	return target_examine_one(target);
}


zwelch's avatar
zwelch committed
498
/* Targets that correctly implement init + examine, i.e.
499
 * no communication with target during init:
oharboe's avatar
oharboe committed
500
501
 *
 * XScale
502
 */
ntfreak's avatar
ntfreak committed
503
int target_examine(void)
504
505
{
	int retval = ERROR_OK;
zwelch's avatar
zwelch committed
506
507
508
	target_t *target;

	for (target = all_targets; target; target = target->next)
509
	{
zwelch's avatar
zwelch committed
510
511
512
513
		/* defer examination, but don't skip it */
		if (!target->tap->enabled) {
			jtag_register_event_callback(jtag_enable_callback,
					target);
zwelch's avatar
zwelch committed
514
			continue;
zwelch's avatar
zwelch committed
515
		}
zwelch's avatar
zwelch committed
516
		if ((retval = target_examine_one(target)) != ERROR_OK)
517
518
519
520
			return retval;
	}
	return retval;
}
zwelch's avatar
zwelch committed
521
522
523
524
const char *target_get_name(struct target_s *target)
{
	return target->type->name;
}
525

526
static int target_write_memory_imp(struct target_s *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
527
{
528
	if (!target_was_examined(target))
529
530
531
532
533
534
535
	{
		LOG_ERROR("Target not examined yet");
		return ERROR_FAIL;
	}
	return target->type->write_memory_imp(target, address, size, count, buffer);
}

536
static int target_read_memory_imp(struct target_s *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
537
{
538
	if (!target_was_examined(target))
539
540
541
542
543
544
545
546
547
	{
		LOG_ERROR("Target not examined yet");
		return ERROR_FAIL;
	}
	return target->type->read_memory_imp(target, address, size, count, buffer);
}

static int target_soft_reset_halt_imp(struct target_s *target)
{
548
	if (!target_was_examined(target))
549
550
551
552
	{
		LOG_ERROR("Target not examined yet");
		return ERROR_FAIL;
	}
553
554
555
556
557
	if (!target->type->soft_reset_halt_imp) {
		LOG_ERROR("Target %s does not support soft_reset_halt",
				target->cmd_name);
		return ERROR_FAIL;
	}
558
559
560
	return target->type->soft_reset_halt_imp(target);
}

561
static int target_run_algorithm_imp(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_params, reg_param_t *reg_param, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info)
562
{
563
	if (!target_was_examined(target))
564
565
566
567
568
569
	{
		LOG_ERROR("Target not examined yet");
		return ERROR_FAIL;
	}
	return target->type->run_algorithm_imp(target, num_mem_params, mem_params, num_reg_params, reg_param, entry_point, exit_point, timeout_ms, arch_info);
}
570

zwelch's avatar
zwelch committed
571
int target_read_memory(struct target_s *target,
572
		uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
zwelch's avatar
zwelch committed
573
574
575
576
{
	return target->type->read_memory(target, address, size, count, buffer);
}

577
578
579
580
581
582
int target_read_phys_memory(struct target_s *target,
		uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
{
	return target->type->read_phys_memory(target, address, size, count, buffer);
}

zwelch's avatar
zwelch committed
583
int target_write_memory(struct target_s *target,
584
		uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
zwelch's avatar
zwelch committed
585
586
587
{
	return target->type->write_memory(target, address, size, count, buffer);
}
588
589
590
591
592
593
594

int target_write_phys_memory(struct target_s *target,
		uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
{
	return target->type->write_phys_memory(target, address, size, count, buffer);
}

zwelch's avatar
zwelch committed
595
int target_bulk_write_memory(struct target_s *target,
596
		uint32_t address, uint32_t count, uint8_t *buffer)
zwelch's avatar
zwelch committed
597
598
599
600
{
	return target->type->bulk_write_memory(target, address, count, buffer);
}

601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
int target_add_breakpoint(struct target_s *target,
		struct breakpoint_s *breakpoint)
{
	return target->type->add_breakpoint(target, breakpoint);
}
int target_remove_breakpoint(struct target_s *target,
		struct breakpoint_s *breakpoint)
{
	return target->type->remove_breakpoint(target, breakpoint);
}

int target_add_watchpoint(struct target_s *target,
		struct watchpoint_s *watchpoint)
{
	return target->type->add_watchpoint(target, watchpoint);
}
int target_remove_watchpoint(struct target_s *target,
		struct watchpoint_s *watchpoint)
{
	return target->type->remove_watchpoint(target, watchpoint);
}
zwelch's avatar
zwelch committed
622

zwelch's avatar
zwelch committed
623
624
625
626
627
int target_get_gdb_reg_list(struct target_s *target,
		struct reg_s **reg_list[], int *reg_list_size)
{
	return target->type->get_gdb_reg_list(target, reg_list, reg_list_size);
}
zwelch's avatar
zwelch committed
628
int target_step(struct target_s *target,
629
		int current, uint32_t address, int handle_breakpoints)
zwelch's avatar
zwelch committed
630
631
632
633
{
	return target->type->step(target, current, address, handle_breakpoints);
}

zwelch's avatar
zwelch committed
634

zwelch's avatar
zwelch committed
635
636
637
int target_run_algorithm(struct target_s *target,
		int num_mem_params, mem_param_t *mem_params,
		int num_reg_params, reg_param_t *reg_param,
638
		uint32_t entry_point, uint32_t exit_point,
zwelch's avatar
zwelch committed
639
640
641
642
643
644
645
		int timeout_ms, void *arch_info)
{
	return target->type->run_algorithm(target,
			num_mem_params, mem_params, num_reg_params, reg_param,
			entry_point, exit_point, timeout_ms, arch_info);
}

646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
/// @returns @c true if the target has been examined.
bool target_was_examined(struct target_s *target)
{
	return target->type->examined;
}
/// Sets the @c examined flag for the given target.
void target_set_examined(struct target_s *target)
{
	target->type->examined = true;
}
// Reset the @c examined flag for the given target.
void target_reset_examined(struct target_s *target)
{
	target->type->examined = false;
}

zwelch's avatar
zwelch committed
662

663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690

static int default_mrc(struct target_s *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value)
{
	LOG_ERROR("Not implemented");
	return ERROR_FAIL;
}

static int default_mcr(struct target_s *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value)
{
	LOG_ERROR("Not implemented");
	return ERROR_FAIL;
}

static int arm_cp_check(struct target_s *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm)
{
	/* basic check */
	if (!target_was_examined(target))
	{
		LOG_ERROR("Target not examined yet");
		return ERROR_FAIL;
	}

	if ((cpnum <0) || (cpnum > 15))
	{
		LOG_ERROR("Illegal co-processor %d", cpnum);
		return ERROR_FAIL;
	}

691
	if (op1 > 7)
692
693
694
695
696
	{
		LOG_ERROR("Illegal op1");
		return ERROR_FAIL;
	}

697
	if (op2 > 7)
698
699
700
701
702
	{
		LOG_ERROR("Illegal op2");
		return ERROR_FAIL;
	}

703
	if (CRn > 15)
704
705
706
707
708
	{
		LOG_ERROR("Illegal CRn");
		return ERROR_FAIL;
	}

709
	if (CRm > 15)
710
711
712
713
714
	{
		LOG_ERROR("Illegal CRm");
		return ERROR_FAIL;
	}

715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
	return ERROR_OK;
}

int target_mrc(struct target_s *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value)
{
	int retval;

	retval = arm_cp_check(target, cpnum, op1, op2, CRn, CRm);
	if (retval != ERROR_OK)
		return retval;

	return target->type->mrc(target, cpnum, op1, op2, CRn, CRm, value);
}

int target_mcr(struct target_s *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value)
{
	int retval;

	retval = arm_cp_check(target, cpnum, op1, op2, CRn, CRm);
	if (retval != ERROR_OK)
		return retval;

	return target->type->mcr(target, cpnum, op1, op2, CRn, CRm, value);
}

740
741
static int default_read_phys_memory(struct target_s *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
{
742
743
	LOG_ERROR("Not implemented");
	return ERROR_FAIL;
744
745
746
747
}

static int default_write_phys_memory(struct target_s *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
{
748
749
	LOG_ERROR("Not implemented");
	return ERROR_FAIL;
750
751
}

752

753
754
int target_init(struct command_context_s *cmd_ctx)
{
755
	target_t *target = all_targets;
756
	int retval;
oharboe's avatar
oharboe committed
757

758
759
	while (target)
	{
760
		target_reset_examined(target);
761
762
763
764
		if (target->type->examine == NULL)
		{
			target->type->examine = default_examine;
		}
oharboe's avatar
oharboe committed
765

766
		if ((retval = target->type->init_target(cmd_ctx, target)) != ERROR_OK)
767
		{
zwelch's avatar
zwelch committed
768
			LOG_ERROR("target '%s' init failed", target_get_name(target));
769
			return retval;
770
		}
oharboe's avatar
oharboe committed
771

772
773
774
775
776
		/* Set up default functions if none are provided by target */
		if (target->type->virt2phys == NULL)
		{
			target->type->virt2phys = default_virt2phys;
		}
777
778
779

		if (target->type->read_phys_memory == NULL)
		{
780
			target->type->read_phys_memory = default_read_phys_memory;
781
782
783
784
		}

		if (target->type->write_phys_memory == NULL)
		{
785
			target->type->write_phys_memory = default_write_phys_memory;
786
787
		}

788
789
790
		if (target->type->mcr == NULL)
		{
			target->type->mcr = default_mcr;
791
792
793
794
795
796
797
798
		} else
		{
			/* FIX! multiple targets will generally register global commands
			 * multiple times. Only register this one if *one* of the
			 * targets need the command. Hmm... make it a command on the
			 * Jim Tcl target object?
			 */
			register_jim(cmd_ctx, "mcr", jim_mcrmrc, "write coprocessor <cpnum> <op1> <op2> <CRn> <CRm> <value>");
799
800
801
802
803
		}

		if (target->type->mrc == NULL)
		{
			target->type->mrc = default_mrc;
804
805
806
		} else
		{
			register_jim(cmd_ctx, "mrc", jim_mcrmrc, "read coprocessor <cpnum> <op1> <op2> <CRn> <CRm>");
807
808
809
		}


810
811
812
813
814
815
816
817
818
819
820
821
		/* a non-invasive way(in terms of patches) to add some code that
		 * runs before the type->write/read_memory implementation
		 */
		target->type->write_memory_imp = target->type->write_memory;
		target->type->write_memory = target_write_memory_imp;
		target->type->read_memory_imp = target->type->read_memory;
		target->type->read_memory = target_read_memory_imp;
		target->type->soft_reset_halt_imp = target->type->soft_reset_halt;
		target->type->soft_reset_halt = target_soft_reset_halt_imp;
		target->type->run_algorithm_imp = target->type->run_algorithm;
		target->type->run_algorithm = target_run_algorithm_imp;

822
823
824
825
826
827
		if (target->type->mmu == NULL)
		{
			target->type->mmu = default_mmu;
		}
		target = target->next;
	}
oharboe's avatar
oharboe committed
828

829
	if (all_targets)
830
	{
zwelch's avatar
zwelch committed
831
		if ((retval = target_register_user_commands(cmd_ctx)) != ERROR_OK)
832
			return retval;
zwelch's avatar
zwelch committed
833
		if ((retval = target_register_timer_callback(handle_target, 100, 1, NULL)) != ERROR_OK)
834
			return retval;
835
	}
oharboe's avatar
oharboe committed
836

837
838
839
840
841
842
	return ERROR_OK;
}

int target_register_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv)
{
	target_event_callback_t **callbacks_p = &target_event_callbacks;
oharboe's avatar
oharboe committed
843

844
845
846
847
	if (callback == NULL)
	{
		return ERROR_INVALID_ARGUMENTS;
	}
oharboe's avatar
oharboe committed
848

849
850
851
852
853
854
	if (*callbacks_p)
	{
		while ((*callbacks_p)->next)
			callbacks_p = &((*callbacks_p)->next);
		callbacks_p = &((*callbacks_p)->next);
	}
oharboe's avatar
oharboe committed
855

856
857
858
859
	(*callbacks_p) = malloc(sizeof(target_event_callback_t));
	(*callbacks_p)->callback = callback;
	(*callbacks_p)->priv = priv;
	(*callbacks_p)->next = NULL;
oharboe's avatar
oharboe committed
860

861
862
863
864
865
866
867
	return ERROR_OK;
}

int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv)
{
	target_timer_callback_t **callbacks_p = &target_timer_callbacks;
	struct timeval now;
oharboe's avatar
oharboe committed
868

869
870
871
872
	if (callback == NULL)
	{
		return ERROR_INVALID_ARGUMENTS;
	}
oharboe's avatar
oharboe committed
873

874
875
876
877
878
879
	if (*callbacks_p)
	{
		while ((*callbacks_p)->next)
			callbacks_p = &((*callbacks_p)->next);
		callbacks_p = &((*callbacks_p)->next);
	}
oharboe's avatar
oharboe committed
880

881
882
883
884
	(*callbacks_p) = malloc(sizeof(target_timer_callback_t));
	(*callbacks_p)->callback = callback;
	(*callbacks_p)->periodic = periodic;
	(*callbacks_p)->time_ms = time_ms;
oharboe's avatar
oharboe committed
885

886
887
888
889
890
891
892
893
894
	gettimeofday(&now, NULL);
	(*callbacks_p)->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000;
	time_ms -= (time_ms % 1000);
	(*callbacks_p)->when.tv_sec = now.tv_sec + (time_ms / 1000);
	if ((*callbacks_p)->when.tv_usec > 1000000)
	{
		(*callbacks_p)->when.tv_usec = (*callbacks_p)->when.tv_usec - 1000000;
		(*callbacks_p)->when.tv_sec += 1;
	}
oharboe's avatar
oharboe committed
895

896
897
	(*callbacks_p)->priv = priv;
	(*callbacks_p)->next = NULL;
oharboe's avatar
oharboe committed
898

899
900
901
902
903
904
905
	return ERROR_OK;
}

int target_unregister_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv)
{
	target_event_callback_t **p = &target_event_callbacks;
	target_event_callback_t *c = target_event_callbacks;
oharboe's avatar
oharboe committed
906

907
908
909
910
	if (callback == NULL)
	{
		return ERROR_INVALID_ARGUMENTS;
	}
oharboe's avatar
oharboe committed
911

912
913
914
915
916
917
918
919
920
921
922
923
924
	while (c)
	{
		target_event_callback_t *next = c->next;
		if ((c->callback == callback) && (c->priv == priv))
		{
			*p = next;
			free(c);
			return ERROR_OK;
		}
		else
			p = &(c->next);
		c = next;
	}
oharboe's avatar
oharboe committed
925

926
927
928
929
930
931
932
	return ERROR_OK;
}

int target_unregister_timer_callback(int (*callback)(void *priv), void *priv)
{
	target_timer_callback_t **p = &target_timer_callbacks;
	target_timer_callback_t *c = target_timer_callbacks;
oharboe's avatar
oharboe committed
933

934
935
936
937
	if (callback == NULL)
	{
		return ERROR_INVALID_ARGUMENTS;
	}
oharboe's avatar
oharboe committed
938

939
940
941
942
943
944
945
946
947
948
949
950
951
	while (c)
	{
		target_timer_callback_t *next = c->next;
		if ((c->callback == callback) && (c->priv == priv))
		{
			*p = next;
			free(c);
			return ERROR_OK;
		}
		else
			p = &(c->next);
		c = next;
	}
oharboe's avatar
oharboe committed
952

953
954
955
956
957
958
959
	return ERROR_OK;
}

int target_call_event_callbacks(target_t *target, enum target_event event)
{
	target_event_callback_t *callback = target_event_callbacks;
	target_event_callback_t *next_callback;
oharboe's avatar
oharboe committed
960

961
962
963
	if (event == TARGET_EVENT_HALTED)
	{
		/* execute early halted first */
964
		target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
965
966
	}

967
968
	LOG_DEBUG("target event %i (%s)",
			  event,
969
			  Jim_Nvp_value2name_simple(nvp_target_event, event)->name);
oharboe's avatar
oharboe committed
970

971
	target_handle_event(target, event);
972

973
974
975
976
977
978
	while (callback)
	{
		next_callback = callback->next;
		callback->callback(target, event, callback->priv);
		callback = next_callback;
	}
oharboe's avatar
oharboe committed
979

980
981
982
	return ERROR_OK;
}

983
984
static int target_timer_callback_periodic_restart(
		target_timer_callback_t *cb, struct timeval *now)
985
{
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
	int time_ms = cb->time_ms;
	cb->when.tv_usec = now->tv_usec + (time_ms % 1000) * 1000;
	time_ms -= (time_ms % 1000);
	cb->when.tv_sec = now->tv_sec + time_ms / 1000;
	if (cb->when.tv_usec > 1000000)
	{
		cb->when.tv_usec = cb->when.tv_usec - 1000000;
		cb->when.tv_sec += 1;
	}
	return ERROR_OK;
}

static int target_call_timer_callback(target_timer_callback_t *cb,
		struct timeval *now)
{