armv7m.c 24.7 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
12
13
 *   Copyright (C) 2007,2008 yvind Harboe                                 *
 *   oyvind.harboe@zylin.com                                               *
 *                                                                         *
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 *   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 "replacements.h"

#include "armv7m.h"
#include "register.h"
#include "target.h"
#include "log.h"
#include "jtag.h"
#include "arm_jtag.h"

#include <stdlib.h>
#include <string.h>

#if 0
#define _DEBUG_INSTRUCTION_EXECUTION_
#endif

char* armv7m_mode_strings[] =
{
51
	"Thread", "Thread (User)", "Handler",
52
53
54
55
56
57
58
59
60
61
};

char* armv7m_exception_strings[] =
{
	"", "Reset", "NMI", "HardFault", "MemManage", "BusFault", "UsageFault", "RESERVED", "RESERVED", "RESERVED", "RESERVED",
	"SVCall", "DebugMonitor", "RESERVED", "PendSV", "SysTick"
};

char* armv7m_core_reg_list[] =
{
62
	/* Registers accessed through core debug */
63
64
65
	"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12",
	"sp", "lr", "pc",
	"xPSR", "msp", "psp",
66
	/* Registers accessed through special reg 20 */
67
68
69
70
71
72
73
74
75
76
	"primask", "basepri", "faultmask", "control"
};

u8 armv7m_gdb_dummy_fp_value[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

reg_t armv7m_gdb_dummy_fp_reg =
{
	"GDB dummy floating-point register", armv7m_gdb_dummy_fp_value, 0, 1, 96, NULL, 0, NULL, 0
};

77
78
79
80
81
82
83
u8 armv7m_gdb_dummy_fps_value[] = {0, 0, 0, 0};

reg_t armv7m_gdb_dummy_fps_reg =
{
	"GDB dummy floating-point status register", armv7m_gdb_dummy_fps_value, 0, 1, 32, NULL, 0, NULL, 0
};

84
85
86
87
88
89
90
91
92
#ifdef ARMV7_GDB_HACKS
u8 armv7m_gdb_dummy_cpsr_value[] = {0, 0, 0, 0};

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

93
armv7m_core_reg_t armv7m_core_reg_list_arch_info[] =
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
{
	/*  CORE_GP are accesible using the core debug registers */
	{0, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
	{1, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
	{2, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
	{3, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
	{4, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
	{5, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
	{6, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
	{7, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
	{8, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
	{9, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
	{10, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
	{11, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
	{12, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
	{13, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
110
	{14, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},
111
112
113
114
115
116
	{15, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL},

	{16, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL}, /* xPSR */
	{17, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL}, /* MSP */
	{18, ARMV7M_REGISTER_CORE_GP, ARMV7M_MODE_ANY, NULL, NULL}, /* PSP */

117
118
119
120
121
	/*  CORE_SP are accesible using coreregister 20 */
	{19, ARMV7M_REGISTER_CORE_SP, ARMV7M_MODE_ANY, NULL, NULL}, /* PRIMASK */
	{20, ARMV7M_REGISTER_CORE_SP, ARMV7M_MODE_ANY, NULL, NULL}, /* BASEPRI */
	{21, ARMV7M_REGISTER_CORE_SP, ARMV7M_MODE_ANY, NULL, NULL}, /* FAULTMASK */
	{22, ARMV7M_REGISTER_CORE_SP, ARMV7M_MODE_ANY, NULL, NULL}  /* CONTROL */
122
123
124
};

int armv7m_core_reg_arch_type = -1;
125
int armv7m_dummy_core_reg_arch_type = -1;
126

127
128
129
int armv7m_restore_context(target_t *target)
{
	int i;
130

131
132
133
	/* get pointers to arch-specific information */
	armv7m_common_t *armv7m = target->arch_info;

134
	LOG_DEBUG(" ");
135
136
137

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

139
	for (i = ARMV7NUMCOREREGS-1; i >= 0; i--)
140
141
142
143
144
145
	{
		if (armv7m->core_cache->reg_list[i].dirty)
		{
			armv7m->write_core_reg(target, i);
		}
	}
146

147
148
	if (armv7m->post_restore_context)
		armv7m->post_restore_context(target);
149
150

	return ERROR_OK;
151
152
}

153
154
155
/* Core state functions */
char *armv7m_exception_string(int number)
{
156
	static char enamebuf[32];
157

ntfreak's avatar
ntfreak committed
158
159
160
161
162
	if ((number < 0) | (number > 511))
		return "Invalid exception";
	if (number < 16)
		return armv7m_exception_strings[number];
	sprintf(enamebuf, "External Interrupt(%i)", number - 16);
163
164
165
166
167
168
169
170
171
	return enamebuf;
}

int armv7m_get_core_reg(reg_t *reg)
{
	int retval;
	armv7m_core_reg_t *armv7m_reg = reg->arch_info;
	target_t *target = armv7m_reg->target;
	armv7m_common_t *armv7m_target = target->arch_info;
172

173
174
175
176
177
178
	if (target->state != TARGET_HALTED)
	{
		return ERROR_TARGET_NOT_HALTED;
	}

	retval = armv7m_target->read_core_reg(target, armv7m_reg->num);
179

180
181
182
183
184
185
186
187
	return retval;
}

int armv7m_set_core_reg(reg_t *reg, u8 *buf)
{
	armv7m_core_reg_t *armv7m_reg = reg->arch_info;
	target_t *target = armv7m_reg->target;
	u32 value = buf_get_u32(buf, 0, 32);
188

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

194
195
196
197
198
199
200
201
202
203
204
205
	buf_set_u32(reg->value, 0, 32, value);
	reg->dirty = 1;
	reg->valid = 1;

	return ERROR_OK;
}

int armv7m_read_core_reg(struct target_s *target, int num)
{
	u32 reg_value;
	int retval;
	armv7m_core_reg_t * armv7m_core_reg;
206

207
208
	/* get pointers to arch-specific information */
	armv7m_common_t *armv7m = target->arch_info;
209

210
211
212
213
214
215
	if ((num < 0) || (num >= ARMV7NUMCOREREGS))
		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);
216
217
	armv7m->core_cache->reg_list[num].valid = 1;
	armv7m->core_cache->reg_list[num].dirty = 0;
218

219
	return retval;
220
221
222
223
224
225
}

int armv7m_write_core_reg(struct target_s *target, int num)
{
	int retval;
	u32 reg_value;
226
	armv7m_core_reg_t *armv7m_core_reg;
227

228
229
230
231
232
	/* get pointers to arch-specific information */
	armv7m_common_t *armv7m = target->arch_info;

	if ((num < 0) || (num >= ARMV7NUMCOREREGS))
		return ERROR_INVALID_ARGUMENTS;
233

234
235
236
237
238
	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)
	{
239
		LOG_ERROR("JTAG failure");
240
		armv7m->core_cache->reg_list[num].dirty = armv7m->core_cache->reg_list[num].valid;
ntfreak's avatar
ntfreak committed
241
		return ERROR_JTAG_DEVICE_ERROR;
242
	}
243
	LOG_DEBUG("write core reg %i value 0x%x", num , reg_value);
244
245
	armv7m->core_cache->reg_list[num].valid = 1;
	armv7m->core_cache->reg_list[num].dirty = 0;
246

247
248
249
250
251
252
253
254
	return ERROR_OK;
}

int armv7m_invalidate_core_regs(target_t *target)
{
	/* get pointers to arch-specific information */
	armv7m_common_t *armv7m = target->arch_info;
	int i;
255

256
257
258
259
260
	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;
	}
261

262
263
264
265
266
267
268
269
	return ERROR_OK;
}

int armv7m_get_gdb_reg_list(target_t *target, reg_t **reg_list[], int *reg_list_size)
{
	/* get pointers to arch-specific information */
	armv7m_common_t *armv7m = target->arch_info;
	int i;
270

271
272
	*reg_list_size = 26;
	*reg_list = malloc(sizeof(reg_t*) * (*reg_list_size));
273

274
	for (i = 0; i < 16; i++)
275
	{
276
		(*reg_list)[i] = &armv7m->core_cache->reg_list[i];
277
	}
278

279
280
281
282
	for (i = 16; i < 24; i++)
	{
		(*reg_list)[i] = &armv7m_gdb_dummy_fp_reg;
	}
283

284
	(*reg_list)[24] = &armv7m_gdb_dummy_fps_reg;
285
286
287
288

#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;
289

290
291
	/* ARMV7M is always in thumb mode, try to make GDB understand this
	 * if it does not support this arch */
292
	armv7m->core_cache->reg_list[15].value[0] |= 1;
293
#else
294
	(*reg_list)[25] = &armv7m->core_cache->reg_list[ARMV7M_xPSR];
295
296
#endif

297
298
299
	return ERROR_OK;
}

300
301
302
303
304
305
/* run to exit point. return error if exit point was not reached. */
static int armv7m_run_and_wait(struct target_s *target, u32 entry_point, int timeout_ms, u32 exit_point, armv7m_common_t *armv7m)
{
	u32 pc;
	int retval;
	/* This code relies on the target specific  resume() and  poll()->debug_entry()
306
	 * sequence to write register values to the processor and the read them back */
307
308
309
310
311
312
	if((retval = target_resume(target, 0, entry_point, 1, 1)) != ERROR_OK)
	{
		return retval;
	}

	retval = target_wait_state(target, TARGET_HALTED, timeout_ms);
313
	/* If the target fails to halt due to the breakpoint, force a halt */
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
	if (retval != ERROR_OK || target->state != TARGET_HALTED)
	{
		if ((retval=target_halt(target))!=ERROR_OK)
			return retval;
		if ((retval=target_wait_state(target, TARGET_HALTED, 500))!=ERROR_OK)
		{
			return retval;
		}
		return ERROR_TARGET_TIMEOUT;
	}

	armv7m->load_core_reg_u32(target, ARMV7M_REGISTER_CORE_GP, 15, &pc);
	if (pc != exit_point)
	{
		LOG_DEBUG("failed algoritm halted at 0x%x ", pc);
		return ERROR_TARGET_TIMEOUT;
	}

	return ERROR_OK;
}

335
336
int armv7m_run_algorithm(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_params, reg_param_t *reg_params, u32 entry_point, u32 exit_point, int timeout_ms, void *arch_info)
{
337
	/* get pointers to arch-specific information */
338
339
	armv7m_common_t *armv7m = target->arch_info;
	armv7m_algorithm_t *armv7m_algorithm_info = arch_info;
340
	enum armv7m_mode core_mode = armv7m->core_mode;
341
342
	int retval = ERROR_OK;
	int i;
343
	u32 context[ARMV7NUMCOREREGS];
344

345
346
	if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC)
	{
347
		LOG_ERROR("current target isn't an ARMV7M target");
348
349
		return ERROR_TARGET_INVALID;
	}
350

351
352
	if (target->state != TARGET_HALTED)
	{
353
		LOG_WARNING("target not halted");
354
355
		return ERROR_TARGET_NOT_HALTED;
	}
356

357
	/* refresh core register cache */
358
	/* Not needed if core register cache is always consistent with target process state */
359
360
361
362
363
364
	for (i = 0; i < ARMV7NUMCOREREGS; i++)
	{
		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);
	}
365

366
367
	for (i = 0; i < num_mem_params; i++)
	{
368
369
		if ((retval=target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value))!=ERROR_OK)
			return retval;
370
	}
371

372
373
374
	for (i = 0; i < num_reg_params; i++)
	{
		reg_t *reg = register_get_by_name(armv7m->core_cache, reg_params[i].reg_name, 0);
mlu's avatar
mlu committed
375
//		u32 regvalue;
376

377
378
		if (!reg)
		{
379
			LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
380
381
			exit(-1);
		}
382

383
384
		if (reg->size != reg_params[i].size)
		{
385
			LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name);
386
387
			exit(-1);
		}
388

mlu's avatar
mlu committed
389
//		regvalue = buf_get_u32(reg_params[i].value, 0, 32);
390
391
		armv7m_set_core_reg(reg, reg_params[i].value);
	}
392

393
394
395
396
397
398
399
	if (armv7m_algorithm_info->core_mode != ARMV7M_MODE_ANY)
	{
		LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
		buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 1, armv7m_algorithm_info->core_mode);
		armv7m->core_cache->reg_list[ARMV7M_CONTROL].dirty = 1;
		armv7m->core_cache->reg_list[ARMV7M_CONTROL].valid = 1;
	}
400

ntfreak's avatar
ntfreak committed
401
	/* ARMV7M always runs in Thumb state */
402
	if ((retval = breakpoint_add(target, exit_point, 2, BKPT_SOFT)) != ERROR_OK)
403
	{
404
		LOG_ERROR("can't add breakpoint to finish algorithm execution");
405
406
		return ERROR_TARGET_FAILURE;
	}
407

408
	retval = armv7m_run_and_wait(target, entry_point, timeout_ms, exit_point, armv7m);
409

410
	breakpoint_remove(target, exit_point);
411

412
	if (retval != ERROR_OK)
oharboe's avatar
oharboe committed
413
	{
414
		return retval;
415
	}
416

417
418
419
420
	/* Read memory values to mem_params[] */
	for (i = 0; i < num_mem_params; i++)
	{
		if (mem_params[i].direction != PARAM_OUT)
421
422
423
424
			if((retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value)) != ERROR_OK)
			{
				return retval;
			}
425
	}
426

427
428
429
430
431
	/* Copy core register values to reg_params[] */
	for (i = 0; i < num_reg_params; i++)
	{
		if (reg_params[i].direction != PARAM_OUT)
		{
432
			reg_t *reg = register_get_by_name(armv7m->core_cache, reg_params[i].reg_name, 0);
433

434
435
			if (!reg)
			{
436
				LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
437
438
				exit(-1);
			}
439

440
441
			if (reg->size != reg_params[i].size)
			{
442
				LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name);
443
444
				exit(-1);
			}
445

446
447
448
			buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32));
		}
	}
449

450
451
	for (i = ARMV7NUMCOREREGS-1; i >= 0; i--)
	{
452
453
454
455
456
457
458
459
460
		u32 regvalue;
		regvalue = buf_get_u32(armv7m->core_cache->reg_list[i].value, 0, 32);
		if (regvalue != context[i])
		{
			LOG_DEBUG("restoring register %s with value 0x%8.8x", armv7m->core_cache->reg_list[i].name, context[i]);
			buf_set_u32(armv7m->core_cache->reg_list[i].value, 0, 32, context[i]);
			armv7m->core_cache->reg_list[i].valid = 1;
			armv7m->core_cache->reg_list[i].dirty = 1;
		}
461
	}
462

463
	armv7m->core_mode = core_mode;
464

465
466
467
	return retval;
}

468
int armv7m_arch_state(struct target_s *target)
469
470
471
{
	/* get pointers to arch-specific information */
	armv7m_common_t *armv7m = target->arch_info;
472

473
	LOG_USER("target halted due to %s, current mode: %s %s\nxPSR: 0x%8.8x pc: 0x%8.8x",
474
		 Jim_Nvp_value2name_simple( nvp_target_debug_reason,target->debug_reason)->name,
475
476
477
478
		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),
		buf_get_u32(armv7m->core_cache->reg_list[15].value, 0, 32));
479

480
481
482
483
484
485
486
487
488
489
490
491
492
493
	return ERROR_OK;
}

reg_cache_t *armv7m_build_reg_cache(target_t *target)
{
	/* get pointers to arch-specific information */
	armv7m_common_t *armv7m = target->arch_info;

	int num_regs = ARMV7NUMCOREREGS;
	reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache);
	reg_cache_t *cache = malloc(sizeof(reg_cache_t));
	reg_t *reg_list = malloc(sizeof(reg_t) * num_regs);
	armv7m_core_reg_t *arch_info = malloc(sizeof(armv7m_core_reg_t) * num_regs);
	int i;
494

495
	if (armv7m_core_reg_arch_type == -1)
496
	{
497
		armv7m_core_reg_arch_type = register_reg_arch_type(armv7m_get_core_reg, armv7m_set_core_reg);
498
	}
499

500
	register_init_dummy(&armv7m_gdb_dummy_fps_reg);
501
#ifdef ARMV7_GDB_HACKS
502
	register_init_dummy(&armv7m_gdb_dummy_cpsr_reg);
503
#endif
504
	register_init_dummy(&armv7m_gdb_dummy_fp_reg);
505
506

	/* Build the process context cache */
507
508
509
510
511
512
	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;
513

514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
	for (i = 0; i < num_regs; i++)
	{
		arch_info[i] = armv7m_core_reg_list_arch_info[i];
		arch_info[i].target = target;
		arch_info[i].armv7m_common = armv7m;
		reg_list[i].name = armv7m_core_reg_list[i];
		reg_list[i].size = 32;
		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];
	}
529

530
	return cache;
531
532
533
534
535
}

int armv7m_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
{
	armv7m_build_reg_cache(target);
536

537
538
539
540
541
542
	return ERROR_OK;
}

int armv7m_init_arch_info(target_t *target, armv7m_common_t *armv7m)
{
	/* register arch-specific functions */
543

544
545
546
	target->arch_info = armv7m;
	armv7m->read_core_reg = armv7m_read_core_reg;
	armv7m->write_core_reg = armv7m_write_core_reg;
547

548
549
550
551
552
	return ERROR_OK;
}

int armv7m_register_commands(struct command_context_s *cmd_ctx)
{
553
554
555
	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");		
mlu's avatar
mlu committed
556
	register_command(cmd_ctx, arm_adi_v5_dap_cmd, "info", handle_dap_info_command, COMMAND_EXEC, "dap info for ap [num], default currently selected AP");
557
	register_command(cmd_ctx, arm_adi_v5_dap_cmd, "apsel", handle_dap_apsel_command, COMMAND_EXEC, "select a different AP [num] (default 0)");
mlu's avatar
mlu committed
558
559
	register_command(cmd_ctx, arm_adi_v5_dap_cmd, "apid", handle_dap_apid_command, COMMAND_EXEC, "return 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, "return debug base address from AP [num], default currently selected AP");
560

561
562
	return ERROR_OK;
}
ntfreak's avatar
ntfreak committed
563
564
565
566
567
568
569

int armv7m_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum)
{
	working_area_t *crc_algorithm;
	armv7m_algorithm_t armv7m_info;
	reg_param_t reg_params[2];
	int retval;
570
571

	u16 cortex_m3_crc_code[] = {
ntfreak's avatar
ntfreak committed
572
573
574
575
576
577
578
579
580
		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 */
581

ntfreak's avatar
ntfreak committed
582
583
584
585
586
587
588
589
590
591
		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 */
592

ntfreak's avatar
ntfreak committed
593
594
595
596
597
598
599
600
601
		0xF104, 0x0401,			/* add	r4, r4, #1 */
								/* ncomp: */
		0x429C,					/* cmp	r4, r3 */
		0xD1E9,					/* bne	nbyte */
								/* end: */
		0xE7FE,					/* b	end */
		0x1DB7, 0x04C1			/* CRC32XOR:	.word 0x04C11DB7 */
	};

602
	u32 i;
603

ntfreak's avatar
ntfreak committed
604
605
606
607
	if (target_alloc_working_area(target, sizeof(cortex_m3_crc_code), &crc_algorithm) != ERROR_OK)
	{
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	}
608

ntfreak's avatar
ntfreak committed
609
610
	/* convert flash writing code into a buffer in target endianness */
	for (i = 0; i < (sizeof(cortex_m3_crc_code)/sizeof(u16)); i++)
611
612
613
614
		if((retval = target_write_u16(target, crc_algorithm->address + i*sizeof(u16), cortex_m3_crc_code[i])) != ERROR_OK)
		{
			return retval;
		}
615

ntfreak's avatar
ntfreak committed
616
617
	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARMV7M_MODE_ANY;
618

ntfreak's avatar
ntfreak committed
619
620
	init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
621

ntfreak's avatar
ntfreak committed
622
623
	buf_set_u32(reg_params[0].value, 0, 32, address);
	buf_set_u32(reg_params[1].value, 0, 32, count);
624

ntfreak's avatar
ntfreak committed
625
626
627
	if ((retval = target->type->run_algorithm(target, 0, NULL, 2, reg_params,
		crc_algorithm->address, crc_algorithm->address + (sizeof(cortex_m3_crc_code)-6), 20000, &armv7m_info)) != ERROR_OK)
	{
628
		LOG_ERROR("error executing cortex_m3 crc algorithm");
ntfreak's avatar
ntfreak committed
629
630
631
632
633
		destroy_reg_param(&reg_params[0]);
		destroy_reg_param(&reg_params[1]);
		target_free_working_area(target, crc_algorithm);
		return retval;
	}
634

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

ntfreak's avatar
ntfreak committed
637
638
	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
639

ntfreak's avatar
ntfreak committed
640
	target_free_working_area(target, crc_algorithm);
641

ntfreak's avatar
ntfreak committed
642
643
644
	return ERROR_OK;
}

645
646
647
648
649
650
int armv7m_blank_check_memory(struct target_s *target, u32 address, u32 count, u32* blank)
{
	working_area_t *erase_check_algorithm;
	reg_param_t reg_params[3];
	armv7m_algorithm_t armv7m_info;
	int retval;
651
	u32 i;
652

653
654
655
	u16 erase_check_code[] =
	{
							/* loop: */
ntfreak's avatar
ntfreak committed
656
657
658
659
660
661
		0xF810, 0x3B01,		/* ldrb 	r3, [r0], #1 */
		0xEA02, 0x0203,		/* and 	r2, r2, r3 */
		0x3901,				/* subs 	r1, r1, #1 */
		0xD1F9,				/* bne		loop */
							/* end: */
		0xE7FE,				/* b		end */
662
663
664
665
666
667
668
	};

	/* 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;
	}
669

670
671
672
	/* convert flash writing code into a buffer in target endianness */
	for (i = 0; i < (sizeof(erase_check_code)/sizeof(u16)); i++)
		target_write_u16(target, erase_check_algorithm->address + i*sizeof(u16), erase_check_code[i]);
673

674
675
676
677
678
679
680
681
682
683
684
	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);
685

686
	if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params,
687
688
689
690
691
692
693
694
			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;
	}
695

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

698
699
700
	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
	destroy_reg_param(&reg_params[2]);
701

702
	target_free_working_area(target, erase_check_algorithm);
703

704
705
	return ERROR_OK;
}
706

mlu's avatar
mlu committed
707
708
709
710
711
712
713
714
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
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
/********************************************************************************************************************
* Return the debug ap baseaddress in hexadecimal, no extra output to simplify script processing
*********************************************************************************************************************/
int handle_dap_baseaddr_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	target_t *target = get_current_target(cmd_ctx);
	armv7m_common_t *armv7m = target->arch_info;
	swjdp_common_t *swjdp = &armv7m->swjdp_info;
	u32 apsel, apselsave, baseaddr;
	int retval;

	apsel = swjdp->apsel;
	apselsave = swjdp->apsel;
	if (argc > 0)
	{	
		apsel = strtoul(args[0], NULL, 0);
	}
	if (apselsave != apsel)
	{
		dap_ap_select(swjdp, apsel);
	}

	dap_ap_read_reg_u32(swjdp, 0xF8, &baseaddr);
	retval = swjdp_transaction_endcheck(swjdp);
	command_print(cmd_ctx, "0x%8.8x", baseaddr);

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

	return retval;
}


/********************************************************************************************************************
* Return the debug ap id in hexadecimal, no extra output to simplify script processing
*********************************************************************************************************************/
extern int handle_dap_apid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	target_t *target = get_current_target(cmd_ctx);
	armv7m_common_t *armv7m = target->arch_info;
	swjdp_common_t *swjdp = &armv7m->swjdp_info;
	u32 apsel, apselsave, apid;
	int retval;

	apsel = swjdp->apsel;
	apselsave = swjdp->apsel;
	if (argc > 0)
	{	
		apsel = strtoul(args[0], NULL, 0);
	}

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

	dap_ap_read_reg_u32(swjdp, 0xFC, &apid);
	retval = swjdp_transaction_endcheck(swjdp);
	command_print(cmd_ctx, "0x%8.8x", apid);
	if (apselsave != apsel)
	{
		dap_ap_select(swjdp, apselsave);
	}

	return retval;
}

776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
int handle_dap_apsel_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	target_t *target = get_current_target(cmd_ctx);
	armv7m_common_t *armv7m = target->arch_info;
	swjdp_common_t *swjdp = &armv7m->swjdp_info;
	u32 apsel, apid;
	int retval;

	apsel = 0;
	if (argc > 0)
	{	
		apsel = strtoul(args[0], NULL, 0);
	}

	dap_ap_select(swjdp, apsel);
	dap_ap_read_reg_u32(swjdp, 0xFC, &apid);
	retval = swjdp_transaction_endcheck(swjdp);
	command_print(cmd_ctx, "ap %i selected, identification register 0x%8.8x", apsel, apid);

	return retval;
}

int handle_dap_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	target_t *target = get_current_target(cmd_ctx);
	armv7m_common_t *armv7m = target->arch_info;
	swjdp_common_t *swjdp = &armv7m->swjdp_info;
	int retval;
	u32 apsel;

mlu's avatar
mlu committed
806
	apsel =  swjdp->apsel;
807
808
809
810
811
812
813
814
815
816
	if (argc > 0)
	{	
		apsel = strtoul(args[0], NULL, 0);
	}
	
	retval = dap_info_command(cmd_ctx, swjdp, apsel);

	return retval;
}