armv7m.c 25.5 KB
Newer Older
1
2
3
/***************************************************************************
 *   Copyright (C) 2005 by Dominic Rath                                    *
 *   Dominic.Rath@gmx.de                                                   *
oharboe's avatar
oharboe committed
4
 *                                                                         *
5
6
7
 *   Copyright (C) 2006 by Magnus Lundin                                   *
 *   lundin@mlu.mine.nu                                                    *
 *                                                                         *
8
9
10
 *   Copyright (C) 2008 by Spencer Oliver                                  *
 *   spen@spen-soft.co.uk                                                  *
 *                                                                         *
11
 *   Copyright (C) 2007,2008 Øyvind Harboe                                 *
12
13
 *   oyvind.harboe@zylin.com                                               *
 *                                                                         *
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 *   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.             *
28
 *                                                                         *
29
 *	ARMv7-M Architecture, Application Level Reference Manual               *
30
31
 *              ARM DDI 0405C (September 2008)                             *
 *                                                                         *
32
33
34
35
36
37
38
 ***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "armv7m.h"

39
40
#define ARRAY_SIZE(x)	((int)(sizeof(x)/sizeof((x)[0])))

41
42
43
44
45

#if 0
#define _DEBUG_INSTRUCTION_EXECUTION_
#endif

46
47
/** Maps from enum armv7m_mode (except ARMV7M_MODE_ANY) to name. */
char *armv7m_mode_strings[] =
48
{
49
	"Thread", "Thread (User)", "Handler",
50
51
};

52
static char *armv7m_exception_strings[] =
53
{
54
55
56
57
	"", "Reset", "NMI", "HardFault",
	"MemManage", "BusFault", "UsageFault", "RESERVED",
	"RESERVED", "RESERVED", "RESERVED", "SVCall",
	"DebugMonitor", "RESERVED", "PendSV", "SysTick"
58
59
};

60
61
62
static uint8_t armv7m_gdb_dummy_fp_value[12] = {
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
63

64
static reg_t armv7m_gdb_dummy_fp_reg =
65
66
67
68
{
	"GDB dummy floating-point register", armv7m_gdb_dummy_fp_value, 0, 1, 96, NULL, 0, NULL, 0
};

69
static uint8_t armv7m_gdb_dummy_fps_value[] = {0, 0, 0, 0};
70

71
static reg_t armv7m_gdb_dummy_fps_reg =
72
73
74
75
{
	"GDB dummy floating-point status register", armv7m_gdb_dummy_fps_value, 0, 1, 32, NULL, 0, NULL, 0
};

76
#ifdef ARMV7_GDB_HACKS
77
uint8_t armv7m_gdb_dummy_cpsr_value[] = {0, 0, 0, 0};
78
79
80
81
82
83
84

reg_t armv7m_gdb_dummy_cpsr_reg =
{
	"GDB dummy cpsr register", armv7m_gdb_dummy_cpsr_value, 0, 1, 32, NULL, 0, NULL, 0
};
#endif

85
86
87
88
/*
 * These registers are not memory-mapped.  The ARMv7-M profile includes
 * memory mapped registers too, such as for the NVIC (interrupt controller)
 * and SysTick (timer) modules; those can mostly be treated as peripherals.
89
90
91
 *
 * The ARMv6-M profile is almost identical in this respect, except that it
 * doesn't include basepri or faultmask registers.
92
93
94
95
 */
static const struct {
	unsigned id;
	char *name;
96
	unsigned bits;
97
} armv7m_regs[] = {
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
	{ ARMV7M_R0, "r0", 32 },
	{ ARMV7M_R1, "r1", 32 },
	{ ARMV7M_R2, "r2", 32 },
	{ ARMV7M_R3, "r3", 32 },

	{ ARMV7M_R4, "r4", 32 },
	{ ARMV7M_R5, "r5", 32 },
	{ ARMV7M_R6, "r6", 32 },
	{ ARMV7M_R7, "r7", 32 },

	{ ARMV7M_R8, "r8", 32 },
	{ ARMV7M_R9, "r9", 32 },
	{ ARMV7M_R10, "r10", 32 },
	{ ARMV7M_R11, "r11", 32 },

	{ ARMV7M_R12, "r12", 32 },
	{ ARMV7M_R13, "sp", 32 },
	{ ARMV7M_R14, "lr", 32 },
	{ ARMV7M_PC, "pc", 32 },

	{ ARMV7M_xPSR, "xPSR", 32 },
	{ ARMV7M_MSP, "msp", 32 },
	{ ARMV7M_PSP, "psp", 32 },

	{ ARMV7M_PRIMASK, "primask", 1 },
	{ ARMV7M_BASEPRI, "basepri", 8 },
	{ ARMV7M_FAULTMASK, "faultmask", 1 },
	{ ARMV7M_CONTROL, "control", 2 },
126
127
};

128
129
#define ARMV7M_NUM_REGS	ARRAY_SIZE(armv7m_regs)

130
static int armv7m_core_reg_arch_type = -1;
131

132
133
134
135
/**
 * Restores target context using the cache of core registers set up
 * by armv7m_build_reg_cache(), calling optional core-specific hooks.
 */
136
137
138
int armv7m_restore_context(target_t *target)
{
	int i;
139
	struct armv7m_common_s *armv7m = target_to_armv7m(target);
140

141
	LOG_DEBUG(" ");
142
143
144

	if (armv7m->pre_restore_context)
		armv7m->pre_restore_context(target);
145

146
	for (i = ARMV7M_NUM_REGS - 1; i >= 0; i--)
147
148
149
150
151
152
	{
		if (armv7m->core_cache->reg_list[i].dirty)
		{
			armv7m->write_core_reg(target, i);
		}
	}
153

154
155
	if (armv7m->post_restore_context)
		armv7m->post_restore_context(target);
156
157

	return ERROR_OK;
158
159
}

160
/* Core state functions */
161
162
163
164
165
166
167
168

/**
 * Maps ISR number (from xPSR) to name.
 * Note that while names and meanings for the first sixteen are standardized
 * (with zero not a true exception), external interrupts are only numbered.
 * They are assigned by vendors, which generally assign different numbers to
 * peripherals (such as UART0 or a USB peripheral controller).
 */
169
170
char *armv7m_exception_string(int number)
{
171
	static char enamebuf[32];
172

ntfreak's avatar
ntfreak committed
173
174
175
176
177
	if ((number < 0) | (number > 511))
		return "Invalid exception";
	if (number < 16)
		return armv7m_exception_strings[number];
	sprintf(enamebuf, "External Interrupt(%i)", number - 16);
178
179
180
	return enamebuf;
}

181
static int armv7m_get_core_reg(reg_t *reg)
182
183
184
185
{
	int retval;
	armv7m_core_reg_t *armv7m_reg = reg->arch_info;
	target_t *target = armv7m_reg->target;
186
	struct armv7m_common_s *armv7m = target_to_armv7m(target);
187

188
189
190
191
192
	if (target->state != TARGET_HALTED)
	{
		return ERROR_TARGET_NOT_HALTED;
	}

193
	retval = armv7m->read_core_reg(target, armv7m_reg->num);
194

195
196
197
	return retval;
}

198
static int armv7m_set_core_reg(reg_t *reg, uint8_t *buf)
199
200
201
{
	armv7m_core_reg_t *armv7m_reg = reg->arch_info;
	target_t *target = armv7m_reg->target;
202
	uint32_t value = buf_get_u32(buf, 0, 32);
203

204
205
206
207
	if (target->state != TARGET_HALTED)
	{
		return ERROR_TARGET_NOT_HALTED;
	}
208

209
210
211
212
213
214
215
	buf_set_u32(reg->value, 0, 32, value);
	reg->dirty = 1;
	reg->valid = 1;

	return ERROR_OK;
}

216
static int armv7m_read_core_reg(struct target_s *target, int num)
217
{
218
	uint32_t reg_value;
219
220
	int retval;
	armv7m_core_reg_t * armv7m_core_reg;
221
	struct armv7m_common_s *armv7m = target_to_armv7m(target);
222

223
	if ((num < 0) || (num >= ARMV7M_NUM_REGS))
224
225
226
227
228
		return ERROR_INVALID_ARGUMENTS;

	armv7m_core_reg = armv7m->core_cache->reg_list[num].arch_info;
	retval = armv7m->load_core_reg_u32(target, armv7m_core_reg->type, armv7m_core_reg->num, &reg_value);
	buf_set_u32(armv7m->core_cache->reg_list[num].value, 0, 32, reg_value);
229
230
	armv7m->core_cache->reg_list[num].valid = 1;
	armv7m->core_cache->reg_list[num].dirty = 0;
231

232
	return retval;
233
234
}

235
static int armv7m_write_core_reg(struct target_s *target, int num)
236
237
{
	int retval;
238
	uint32_t reg_value;
239
	armv7m_core_reg_t *armv7m_core_reg;
240
	struct armv7m_common_s *armv7m = target_to_armv7m(target);
241

242
	if ((num < 0) || (num >= ARMV7M_NUM_REGS))
243
		return ERROR_INVALID_ARGUMENTS;
244

245
246
247
248
249
	reg_value = buf_get_u32(armv7m->core_cache->reg_list[num].value, 0, 32);
	armv7m_core_reg = armv7m->core_cache->reg_list[num].arch_info;
	retval = armv7m->store_core_reg_u32(target, armv7m_core_reg->type, armv7m_core_reg->num, reg_value);
	if (retval != ERROR_OK)
	{
250
		LOG_ERROR("JTAG failure");
251
		armv7m->core_cache->reg_list[num].dirty = armv7m->core_cache->reg_list[num].valid;
ntfreak's avatar
ntfreak committed
252
		return ERROR_JTAG_DEVICE_ERROR;
253
	}
duane's avatar
duane committed
254
	LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num , reg_value);
255
256
	armv7m->core_cache->reg_list[num].valid = 1;
	armv7m->core_cache->reg_list[num].dirty = 0;
257

258
259
260
	return ERROR_OK;
}

261
/** Invalidates cache of core registers set up by armv7m_build_reg_cache(). */
262
263
int armv7m_invalidate_core_regs(target_t *target)
{
264
	struct armv7m_common_s *armv7m = target_to_armv7m(target);
265
	int i;
266

267
268
269
270
271
	for (i = 0; i < armv7m->core_cache->num_regs; i++)
	{
		armv7m->core_cache->reg_list[i].valid = 0;
		armv7m->core_cache->reg_list[i].dirty = 0;
	}
272

273
274
275
	return ERROR_OK;
}

276
277
278
279
280
281
/**
 * Returns generic ARM userspace registers to GDB.
 * GDB doesn't quite understand that most ARMs don't have floating point
 * hardware, so this also fakes a set of long-obsolete FPA registers that
 * are not used in EABI based software stacks.
 */
282
283
int armv7m_get_gdb_reg_list(target_t *target, reg_t **reg_list[], int *reg_list_size)
{
284
	struct armv7m_common_s *armv7m = target_to_armv7m(target);
285
	int i;
286

287
288
	*reg_list_size = 26;
	*reg_list = malloc(sizeof(reg_t*) * (*reg_list_size));
289

290
291
292
293
294
295
296
	/*
	 * GDB register packet format for ARM:
	 *  - the first 16 registers are r0..r15
	 *  - (obsolete) 8 FPA registers
	 *  - (obsolete) FPA status
	 *  - CPSR
	 */
297
	for (i = 0; i < 16; i++)
298
	{
299
		(*reg_list)[i] = &armv7m->core_cache->reg_list[i];
300
	}
301

302
303
304
305
	for (i = 16; i < 24; i++)
	{
		(*reg_list)[i] = &armv7m_gdb_dummy_fp_reg;
	}
306

307
	(*reg_list)[24] = &armv7m_gdb_dummy_fps_reg;
308
309
310
311

#ifdef ARMV7_GDB_HACKS
	/* use dummy cpsr reg otherwise gdb may try and set the thumb bit */
	(*reg_list)[25] = &armv7m_gdb_dummy_cpsr_reg;
312

313
314
	/* ARMV7M is always in thumb mode, try to make GDB understand this
	 * if it does not support this arch */
315
	*((char*)armv7m->core_cache->reg_list[15].value) |= 1;
316
#else
317
	(*reg_list)[25] = &armv7m->core_cache->reg_list[ARMV7M_xPSR];
318
319
#endif

320
321
322
	return ERROR_OK;
}

323
/* run to exit point. return error if exit point was not reached. */
324
static int armv7m_run_and_wait(struct target_s *target, uint32_t entry_point, int timeout_ms, uint32_t exit_point, armv7m_common_t *armv7m)
325
{
326
	uint32_t pc;
327
328
	int retval;
	/* This code relies on the target specific  resume() and  poll()->debug_entry()
329
	 * sequence to write register values to the processor and the read them back */
zwelch's avatar
zwelch committed
330
	if ((retval = target_resume(target, 0, entry_point, 1, 1)) != ERROR_OK)
331
332
333
334
335
	{
		return retval;
	}

	retval = target_wait_state(target, TARGET_HALTED, timeout_ms);
336
	/* If the target fails to halt due to the breakpoint, force a halt */
337
338
	if (retval != ERROR_OK || target->state != TARGET_HALTED)
	{
zwelch's avatar
zwelch committed
339
		if ((retval = target_halt(target)) != ERROR_OK)
340
			return retval;
zwelch's avatar
zwelch committed
341
		if ((retval = target_wait_state(target, TARGET_HALTED, 500)) != ERROR_OK)
342
343
344
345
346
347
348
349
350
		{
			return retval;
		}
		return ERROR_TARGET_TIMEOUT;
	}

	armv7m->load_core_reg_u32(target, ARMV7M_REGISTER_CORE_GP, 15, &pc);
	if (pc != exit_point)
	{
duane's avatar
duane committed
351
		LOG_DEBUG("failed algoritm halted at 0x%" PRIx32 " ", pc);
352
353
354
355
356
357
		return ERROR_TARGET_TIMEOUT;
	}

	return ERROR_OK;
}

358
359
/** Runs a Thumb algorithm in the target. */
int armv7m_run_algorithm(struct target_s *target,
360
	int num_mem_params, struct mem_param *mem_params,
361
	int num_reg_params, struct reg_param *reg_params,
362
363
	uint32_t entry_point, uint32_t exit_point,
	int timeout_ms, void *arch_info)
364
{
365
	struct armv7m_common_s *armv7m = target_to_armv7m(target);
366
	armv7m_algorithm_t *armv7m_algorithm_info = arch_info;
367
	enum armv7m_mode core_mode = armv7m->core_mode;
368
369
	int retval = ERROR_OK;
	int i;
370
	uint32_t context[ARMV7M_NUM_REGS];
371

372
373
	if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC)
	{
374
		LOG_ERROR("current target isn't an ARMV7M target");
375
376
		return ERROR_TARGET_INVALID;
	}
377

378
379
	if (target->state != TARGET_HALTED)
	{
380
		LOG_WARNING("target not halted");
381
382
		return ERROR_TARGET_NOT_HALTED;
	}
383

384
	/* refresh core register cache */
385
	/* Not needed if core register cache is always consistent with target process state */
386
	for (i = 0; i < ARMV7M_NUM_REGS; i++)
387
388
389
390
391
	{
		if (!armv7m->core_cache->reg_list[i].valid)
			armv7m->read_core_reg(target, i);
		context[i] = buf_get_u32(armv7m->core_cache->reg_list[i].value, 0, 32);
	}
392

393
394
	for (i = 0; i < num_mem_params; i++)
	{
zwelch's avatar
zwelch committed
395
		if ((retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value)) != ERROR_OK)
396
			return retval;
397
	}
398

399
400
401
	for (i = 0; i < num_reg_params; i++)
	{
		reg_t *reg = register_get_by_name(armv7m->core_cache, reg_params[i].reg_name, 0);
402
//		uint32_t regvalue;
403

404
405
		if (!reg)
		{
406
			LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
407
408
			exit(-1);
		}
409

410
411
		if (reg->size != reg_params[i].size)
		{
412
			LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name);
413
414
			exit(-1);
		}
415

mlu's avatar
mlu committed
416
//		regvalue = buf_get_u32(reg_params[i].value, 0, 32);
417
418
		armv7m_set_core_reg(reg, reg_params[i].value);
	}
419

420
	if (armv7m_algorithm_info->core_mode != ARMV7M_MODE_ANY)
421
422
	{
		LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
423
424
		buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_CONTROL].value,
				0, 1, armv7m_algorithm_info->core_mode);
425
426
		armv7m->core_cache->reg_list[ARMV7M_CONTROL].dirty = 1;
		armv7m->core_cache->reg_list[ARMV7M_CONTROL].valid = 1;
427
	}
428

429
430
431
432
433
	/* REVISIT speed things up (3% or so in one case) by requiring
	 * algorithms to include a BKPT instruction at each exit point.
	 * This eliminates overheads of adding/removing a breakpoint.
	 */

ntfreak's avatar
ntfreak committed
434
	/* ARMV7M always runs in Thumb state */
435
	if ((retval = breakpoint_add(target, exit_point, 2, BKPT_SOFT)) != ERROR_OK)
436
	{
437
		LOG_ERROR("can't add breakpoint to finish algorithm execution");
438
439
		return ERROR_TARGET_FAILURE;
	}
440

441
	retval = armv7m_run_and_wait(target, entry_point, timeout_ms, exit_point, armv7m);
442

443
	breakpoint_remove(target, exit_point);
444

445
	if (retval != ERROR_OK)
oharboe's avatar
oharboe committed
446
	{
447
		return retval;
448
	}
449

450
451
452
453
	/* Read memory values to mem_params[] */
	for (i = 0; i < num_mem_params; i++)
	{
		if (mem_params[i].direction != PARAM_OUT)
zwelch's avatar
zwelch committed
454
			if ((retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value)) != ERROR_OK)
455
456
457
			{
				return retval;
			}
458
	}
459

460
461
462
463
464
	/* Copy core register values to reg_params[] */
	for (i = 0; i < num_reg_params; i++)
	{
		if (reg_params[i].direction != PARAM_OUT)
		{
465
			reg_t *reg = register_get_by_name(armv7m->core_cache, reg_params[i].reg_name, 0);
466

467
468
			if (!reg)
			{
469
				LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
470
471
				exit(-1);
			}
472

473
474
			if (reg->size != reg_params[i].size)
			{
475
				LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name);
476
477
				exit(-1);
			}
478

479
480
481
			buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32));
		}
	}
482

483
	for (i = ARMV7M_NUM_REGS - 1; i >= 0; i--)
484
	{
485
		uint32_t regvalue;
486
487
488
		regvalue = buf_get_u32(armv7m->core_cache->reg_list[i].value, 0, 32);
		if (regvalue != context[i])
		{
489
490
491
492
			LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32,
				armv7m->core_cache->reg_list[i].name, context[i]);
			buf_set_u32(armv7m->core_cache->reg_list[i].value,
					0, 32, context[i]);
493
494
495
			armv7m->core_cache->reg_list[i].valid = 1;
			armv7m->core_cache->reg_list[i].dirty = 1;
		}
496
	}
497

498
	armv7m->core_mode = core_mode;
499

500
501
502
	return retval;
}

503
/** Logs summary of ARMv7-M state for a halted target. */
504
int armv7m_arch_state(struct target_s *target)
505
{
506
	struct armv7m_common_s *armv7m = target_to_armv7m(target);
507
508
509
510
	uint32_t ctrl, sp;

	ctrl = buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
	sp = buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_R13].value, 0, 32);
511

512
	LOG_USER("target halted due to %s, current mode: %s %s\n"
513
514
515
		"xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32,
		Jim_Nvp_value2name_simple(nvp_target_debug_reason,
				target->debug_reason)->name,
516
517
518
		armv7m_mode_strings[armv7m->core_mode],
		armv7m_exception_string(armv7m->exception_number),
		buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32),
519
520
521
		buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_PC].value, 0, 32),
		(ctrl & 0x02) ? 'p' : 'm',
		sp);
522

523
524
525
	return ERROR_OK;
}

526
/** Builds cache of architecturally defined registers.  */
527
528
reg_cache_t *armv7m_build_reg_cache(target_t *target)
{
529
	struct armv7m_common_s *armv7m = target_to_armv7m(target);
530
	int num_regs = ARMV7M_NUM_REGS;
531
532
	reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache);
	reg_cache_t *cache = malloc(sizeof(reg_cache_t));
533
534
	reg_t *reg_list = calloc(num_regs, sizeof(reg_t));
	armv7m_core_reg_t *arch_info = calloc(num_regs, sizeof(armv7m_core_reg_t));
535
	int i;
536

537
	if (armv7m_core_reg_arch_type == -1)
538
	{
539
		armv7m_core_reg_arch_type = register_reg_arch_type(armv7m_get_core_reg, armv7m_set_core_reg);
540
	}
541

542
	register_init_dummy(&armv7m_gdb_dummy_fps_reg);
543
#ifdef ARMV7_GDB_HACKS
544
	register_init_dummy(&armv7m_gdb_dummy_cpsr_reg);
545
#endif
546
	register_init_dummy(&armv7m_gdb_dummy_fp_reg);
547
548

	/* Build the process context cache */
549
550
551
552
553
554
	cache->name = "arm v7m registers";
	cache->next = NULL;
	cache->reg_list = reg_list;
	cache->num_regs = num_regs;
	(*cache_p) = cache;
	armv7m->core_cache = cache;
555

556
557
	for (i = 0; i < num_regs; i++)
	{
558
		arch_info[i].num = armv7m_regs[i].id;
559
560
		arch_info[i].target = target;
		arch_info[i].armv7m_common = armv7m;
561
		reg_list[i].name = armv7m_regs[i].name;
562
		reg_list[i].size = armv7m_regs[i].bits;
563
564
565
566
567
568
569
570
		reg_list[i].value = calloc(1, 4);
		reg_list[i].dirty = 0;
		reg_list[i].valid = 0;
		reg_list[i].bitfield_desc = NULL;
		reg_list[i].num_bitfields = 0;
		reg_list[i].arch_type = armv7m_core_reg_arch_type;
		reg_list[i].arch_info = &arch_info[i];
	}
571

572
	return cache;
573
574
}

575
/** Sets up target as a generic ARMv7-M core */
576
577
578
int armv7m_init_arch_info(target_t *target, armv7m_common_t *armv7m)
{
	/* register arch-specific functions */
579

580
581
582
	target->arch_info = armv7m;
	armv7m->read_core_reg = armv7m_read_core_reg;
	armv7m->write_core_reg = armv7m_write_core_reg;
583

584
585
586
	return ERROR_OK;
}

587
588
589
/** Generates a CRC32 checksum of a memory region. */
int armv7m_checksum_memory(struct target_s *target,
		uint32_t address, uint32_t count, uint32_t* checksum)
ntfreak's avatar
ntfreak committed
590
591
592
{
	working_area_t *crc_algorithm;
	armv7m_algorithm_t armv7m_info;
593
	struct reg_param reg_params[2];
ntfreak's avatar
ntfreak committed
594
	int retval;
595

596
	static const uint16_t cortex_m3_crc_code[] = {
ntfreak's avatar
ntfreak committed
597
598
599
600
601
602
603
604
605
		0x4602,					/* mov	r2, r0 */
		0xF04F, 0x30FF,			/* mov	r0, #0xffffffff */
		0x460B,					/* mov	r3, r1 */
		0xF04F, 0x0400,			/* mov	r4, #0 */
		0xE013,					/* b	ncomp */
								/* nbyte: */
		0x5D11,					/* ldrb	r1, [r2, r4] */
		0xF8DF, 0x7028,			/* ldr		r7, CRC32XOR */
		0xEA80, 0x6001,			/* eor		r0, r0, r1, asl #24 */
606

ntfreak's avatar
ntfreak committed
607
608
609
610
611
612
613
614
615
616
		0xF04F, 0x0500,			/* mov		r5, #0 */
								/* loop: */
		0x2800,					/* cmp		r0, #0 */
		0xEA4F, 0x0640,			/* mov		r6, r0, asl #1 */
		0xF105, 0x0501,			/* add		r5, r5, #1 */
		0x4630,					/* mov		r0, r6 */
		0xBFB8,					/* it		lt */
		0xEA86, 0x0007,			/* eor		r0, r6, r7 */
		0x2D08, 				/* cmp		r5, #8 */
		0xD1F4,					/* bne		loop */
617

ntfreak's avatar
ntfreak committed
618
619
620
621
622
623
624
625
626
		0xF104, 0x0401,			/* add	r4, r4, #1 */
								/* ncomp: */
		0x429C,					/* cmp	r4, r3 */
		0xD1E9,					/* bne	nbyte */
								/* end: */
		0xE7FE,					/* b	end */
		0x1DB7, 0x04C1			/* CRC32XOR:	.word 0x04C11DB7 */
	};

627
	uint32_t i;
628

ntfreak's avatar
ntfreak committed
629
630
631
632
	if (target_alloc_working_area(target, sizeof(cortex_m3_crc_code), &crc_algorithm) != ERROR_OK)
	{
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	}
633

ntfreak's avatar
ntfreak committed
634
	/* convert flash writing code into a buffer in target endianness */
zwelch's avatar
zwelch committed
635
	for (i = 0; i < (sizeof(cortex_m3_crc_code)/sizeof(uint16_t)); i++)
zwelch's avatar
zwelch committed
636
		if ((retval = target_write_u16(target, crc_algorithm->address + i*sizeof(uint16_t), cortex_m3_crc_code[i])) != ERROR_OK)
637
638
639
		{
			return retval;
		}
640

ntfreak's avatar
ntfreak committed
641
642
	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARMV7M_MODE_ANY;
643

ntfreak's avatar
ntfreak committed
644
645
	init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
646

ntfreak's avatar
ntfreak committed
647
648
	buf_set_u32(reg_params[0].value, 0, 32, address);
	buf_set_u32(reg_params[1].value, 0, 32, count);
649

zwelch's avatar
zwelch committed
650
	if ((retval = target_run_algorithm(target, 0, NULL, 2, reg_params,
ntfreak's avatar
ntfreak committed
651
652
		crc_algorithm->address, crc_algorithm->address + (sizeof(cortex_m3_crc_code)-6), 20000, &armv7m_info)) != ERROR_OK)
	{
653
		LOG_ERROR("error executing cortex_m3 crc algorithm");
ntfreak's avatar
ntfreak committed
654
655
656
657
658
		destroy_reg_param(&reg_params[0]);
		destroy_reg_param(&reg_params[1]);
		target_free_working_area(target, crc_algorithm);
		return retval;
	}
659

ntfreak's avatar
ntfreak committed
660
	*checksum = buf_get_u32(reg_params[0].value, 0, 32);
661

ntfreak's avatar
ntfreak committed
662
663
	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
664

ntfreak's avatar
ntfreak committed
665
	target_free_working_area(target, crc_algorithm);
666

ntfreak's avatar
ntfreak committed
667
668
669
	return ERROR_OK;
}

670
671
672
/** Checks whether a memory region is zeroed. */
int armv7m_blank_check_memory(struct target_s *target,
		uint32_t address, uint32_t count, uint32_t* blank)
673
674
{
	working_area_t *erase_check_algorithm;
675
	struct reg_param reg_params[3];
676
677
	armv7m_algorithm_t armv7m_info;
	int retval;
678
	uint32_t i;
679

680
	static const uint16_t erase_check_code[] =
681
	{
682
		/* loop: */
683
684
		0xF810, 0x3B01,		/* ldrb r3, [r0], #1 */
		0xEA02, 0x0203,		/* and  r2, r2, r3 */
685
686
687
688
		0x3901,				/* subs	r1, r1, #1 */
		0xD1F9,				/* bne	loop */
		/* end: */
		0xE7FE,				/* b	end */
689
690
691
692
693
694
695
	};

	/* make sure we have a working area */
	if (target_alloc_working_area(target, sizeof(erase_check_code), &erase_check_algorithm) != ERROR_OK)
	{
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	}
696

697
	/* convert flash writing code into a buffer in target endianness */
zwelch's avatar
zwelch committed
698
699
	for (i = 0; i < (sizeof(erase_check_code)/sizeof(uint16_t)); i++)
		target_write_u16(target, erase_check_algorithm->address + i*sizeof(uint16_t), erase_check_code[i]);
700

701
702
703
704
705
706
707
708
709
710
711
	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARMV7M_MODE_ANY;

	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
	buf_set_u32(reg_params[0].value, 0, 32, address);

	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
	buf_set_u32(reg_params[1].value, 0, 32, count);

	init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
	buf_set_u32(reg_params[2].value, 0, 32, 0xff);
712

zwelch's avatar
zwelch committed
713
	if ((retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
714
715
716
717
718
719
720
721
			erase_check_algorithm->address, erase_check_algorithm->address + (sizeof(erase_check_code)-2), 10000, &armv7m_info)) != ERROR_OK)
	{
		destroy_reg_param(&reg_params[0]);
		destroy_reg_param(&reg_params[1]);
		destroy_reg_param(&reg_params[2]);
		target_free_working_area(target, erase_check_algorithm);
		return 0;
	}
722

723
	*blank = buf_get_u32(reg_params[2].value, 0, 32);
724

725
726
727
	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
	destroy_reg_param(&reg_params[2]);
728

729
	target_free_working_area(target, erase_check_algorithm);
730

731
732
	return ERROR_OK;
}
733

734
735
736
737
738
739
740
741
742
743
/*--------------------------------------------------------------------------*/

/*
 * Only stuff below this line should need to verify that its target
 * is an ARMv7-M node.
 *
 * FIXME yet none of it _does_ verify target types yet!
 */


744
745
746
747
/*
 * Return the debug ap baseaddress in hexadecimal;
 * no extra output to simplify script processing
 */
748
COMMAND_HANDLER(handle_dap_baseaddr_command)
mlu's avatar
mlu committed
749
750
{
	target_t *target = get_current_target(cmd_ctx);
751
	struct armv7m_common_s *armv7m = target_to_armv7m(target);
mlu's avatar
mlu committed
752
	swjdp_common_t *swjdp = &armv7m->swjdp_info;
753
	uint32_t apsel, apselsave, baseaddr;
mlu's avatar
mlu committed
754
755
756
	int retval;

	apselsave = swjdp->apsel;
757
758
759
760
761
762
763
764
765
	switch (argc) {
	case 0:
		apsel = swjdp->apsel;
		break;
	case 1:
		COMMAND_PARSE_NUMBER(u32, args[0], apsel);
		break;
	default:
		return ERROR_COMMAND_SYNTAX_ERROR;
mlu's avatar
mlu committed
766
	}
767

mlu's avatar
mlu committed
768
769
770
771
772
	if (apselsave != apsel)
		dap_ap_select(swjdp, apsel);

	dap_ap_read_reg_u32(swjdp, 0xF8, &baseaddr);
	retval = swjdp_transaction_endcheck(swjdp);
duane's avatar
duane committed
773
	command_print(cmd_ctx, "0x%8.8" PRIx32 "", baseaddr);
mlu's avatar
mlu committed
774
775
776
777
778
779
780

	if (apselsave != apsel)
		dap_ap_select(swjdp, apselsave);

	return retval;
}

781
782
783
784
/*
 * Return the debug ap id in hexadecimal;
 * no extra output to simplify script processing
 */
785
COMMAND_HANDLER(handle_dap_apid_command)
mlu's avatar
mlu committed
786
787
{
	target_t *target = get_current_target(cmd_ctx);
788
	struct armv7m_common_s *armv7m = target_to_armv7m(target);
mlu's avatar
mlu committed
789
790
	swjdp_common_t *swjdp = &armv7m->swjdp_info;

791
	return CALL_COMMAND_HANDLER(dap_apid_command, swjdp);
mlu's avatar
mlu committed
792
793
}

794
COMMAND_HANDLER(handle_dap_apsel_command)
795
796
{
	target_t *target = get_current_target(cmd_ctx);
797
	struct armv7m_common_s *armv7m = target_to_armv7m(target);
798
799
	swjdp_common_t *swjdp = &armv7m->swjdp_info;

800
	return CALL_COMMAND_HANDLER(dap_apsel_command, swjdp);
801
802
}

803
COMMAND_HANDLER(handle_dap_memaccess_command)
804
805
{
	target_t *target = get_current_target(cmd_ctx);
806
	struct armv7m_common_s *armv7m = target_to_armv7m(target);
807
808
	swjdp_common_t *swjdp = &armv7m->swjdp_info;

809
	return CALL_COMMAND_HANDLER(dap_memaccess_command, swjdp);
810
811
}

812

813
COMMAND_HANDLER(handle_dap_info_command)
814
815
{
	target_t *target = get_current_target(cmd_ctx);
816
	struct armv7m_common_s *armv7m = target_to_armv7m(target);
817
	swjdp_common_t *swjdp = &armv7m->swjdp_info;
818
	uint32_t apsel;
819

820
821
822
823
824
825
826
827
828
829
	switch (argc) {
	case 0:
		apsel = swjdp->apsel;
		break;
	case 1:
		COMMAND_PARSE_NUMBER(u32, args[0], apsel);
		break;
	default:
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
830

831
	return dap_info_command(cmd_ctx, swjdp, apsel);
832
833
}

834
/** Registers commands used to access DAP resources. */
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
int armv7m_register_commands(struct command_context_s *cmd_ctx)
{
	command_t *arm_adi_v5_dap_cmd;

	arm_adi_v5_dap_cmd = register_command(cmd_ctx, NULL, "dap",
			NULL, COMMAND_ANY,
			"cortex dap specific commands");

	register_command(cmd_ctx, arm_adi_v5_dap_cmd, "info",
			handle_dap_info_command, COMMAND_EXEC,
			"Displays dap info for ap [num],"
			"default currently selected AP");
	register_command(cmd_ctx, arm_adi_v5_dap_cmd, "apsel",
			handle_dap_apsel_command, COMMAND_EXEC,
			"Select a different AP [num] (default 0)");
	register_command(cmd_ctx, arm_adi_v5_dap_cmd, "apid",
			handle_dap_apid_command, COMMAND_EXEC,
			"Displays id reg from AP [num], "
			"default currently selected AP");
	register_command(cmd_ctx, arm_adi_v5_dap_cmd, "baseaddr",
			handle_dap_baseaddr_command, COMMAND_EXEC,
			"Displays debug base address from AP [num],"
			"default currently selected AP");
	register_command(cmd_ctx, arm_adi_v5_dap_cmd, "memaccess",
			handle_dap_memaccess_command, COMMAND_EXEC,
			"set/get number of extra tck for mem-ap "
			"memory bus access [0-255]");

	return ERROR_OK;
}