cortex_m.c 73.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
14
15
16
17
18
19
20
21
 *   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     *
22
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
23
24
 *                                                                         *
 *                                                                         *
25
 *   Cortex-M3(tm) TRM, ARM DDI 0337E (r1p1) and 0337G (r2p0)              *
26
 *                                                                         *
27
28
29
30
31
 ***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

32
#include "jtag/interface.h"
33
#include "breakpoints.h"
34
#include "cortex_m.h"
35
#include "target_request.h"
36
#include "target_type.h"
zwelch's avatar
zwelch committed
37
#include "arm_disassembler.h"
38
#include "register.h"
39
#include "arm_opcodes.h"
40
#include "arm_semihosting.h"
Peter Horn's avatar
Peter Horn committed
41
#include <helper/time_support.h>
42

43
44
/* NOTE:  most of this should work fine for the Cortex-M1 and
 * Cortex-M0 cores too, although they're ARMv6-M not ARMv7-M.
Christopher Head's avatar
Christopher Head committed
45
 * Some differences:  M0/M1 doesn't have FPB remapping or the
46
47
 * DWT tracing/profiling support.  (So the cycle counter will
 * not be usable; the other stuff isn't currently used here.)
David Brownell's avatar
David Brownell committed
48
49
50
51
 *
 * Although there are some workarounds for errata seen only in r0p0
 * silicon, such old parts are hard to find and thus not much tested
 * any longer.
52
53
 */

54
/* forward declarations */
55
static int cortex_m_store_core_reg_u32(struct target *target,
56
		uint32_t num, uint32_t value);
57
static void cortex_m_dwt_free(struct target *target);
58

59
static int cortexm_dap_read_coreregister_u32(struct target *target,
60
	uint32_t *value, int regnum)
61
{
62
	struct armv7m_common *armv7m = target_to_armv7m(target);
63
	int retval;
64
	uint32_t dcrdr;
65
66

	/* because the DCB_DCRDR is used for the emulated dcc channel
67
	 * we have to save/restore the DCB_DCRDR when used */
68
	if (target->dbg_msg_enabled) {
69
		retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DCRDR, &dcrdr);
70
71
72
		if (retval != ERROR_OK)
			return retval;
	}
73

74
	retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRSR, regnum);
75
76
	if (retval != ERROR_OK)
		return retval;
77

78
	retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DCRDR, value);
79
80
	if (retval != ERROR_OK)
		return retval;
81

82
83
84
85
	if (target->dbg_msg_enabled) {
		/* restore DCB_DCRDR - this needs to be in a separate
		 * transaction otherwise the emulated DCC channel breaks */
		if (retval == ERROR_OK)
86
			retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DCRDR, dcrdr);
87
	}
88

89
90
91
	return retval;
}

92
static int cortexm_dap_write_coreregister_u32(struct target *target,
93
	uint32_t value, int regnum)
94
{
95
	struct armv7m_common *armv7m = target_to_armv7m(target);
96
	int retval;
97
	uint32_t dcrdr;
98
99

	/* because the DCB_DCRDR is used for the emulated dcc channel
100
	 * we have to save/restore the DCB_DCRDR when used */
101
	if (target->dbg_msg_enabled) {
102
		retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DCRDR, &dcrdr);
103
104
105
		if (retval != ERROR_OK)
			return retval;
	}
106

107
	retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRDR, value);
108
109
	if (retval != ERROR_OK)
		return retval;
110

111
	retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DCRSR, regnum | DCRSR_WnR);
112
113
	if (retval != ERROR_OK)
		return retval;
114

115
116
117
118
	if (target->dbg_msg_enabled) {
		/* restore DCB_DCRDR - this needs to be in a seperate
		 * transaction otherwise the emulated DCC channel breaks */
		if (retval == ERROR_OK)
119
			retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DCRDR, dcrdr);
120
	}
121

122
123
124
	return retval;
}

125
static int cortex_m_write_debug_halt_mask(struct target *target,
126
	uint32_t mask_on, uint32_t mask_off)
127
{
128
	struct cortex_m_common *cortex_m = target_to_cm(target);
129
	struct armv7m_common *armv7m = &cortex_m->armv7m;
zwelch's avatar
zwelch committed
130

131
	/* mask off status bits */
132
	cortex_m->dcb_dhcsr &= ~((0xFFFF << 16) | mask_off);
133
	/* create new register mask */
134
	cortex_m->dcb_dhcsr |= DBGKEY | C_DEBUGEN | mask_on;
zwelch's avatar
zwelch committed
135

136
	return mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DHCSR, cortex_m->dcb_dhcsr);
137
138
}

139
static int cortex_m_clear_halt(struct target *target)
140
{
141
	struct cortex_m_common *cortex_m = target_to_cm(target);
142
	struct armv7m_common *armv7m = &cortex_m->armv7m;
143
	int retval;
zwelch's avatar
zwelch committed
144

145
	/* clear step if any */
146
	cortex_m_write_debug_halt_mask(target, C_HALT, C_STEP);
zwelch's avatar
zwelch committed
147

148
	/* Read Debug Fault Status Register */
149
	retval = mem_ap_read_atomic_u32(armv7m->debug_ap, NVIC_DFSR, &cortex_m->nvic_dfsr);
150
151
	if (retval != ERROR_OK)
		return retval;
David Brownell's avatar
David Brownell committed
152

153
	/* Clear Debug Fault Status */
154
	retval = mem_ap_write_atomic_u32(armv7m->debug_ap, NVIC_DFSR, cortex_m->nvic_dfsr);
155
156
	if (retval != ERROR_OK)
		return retval;
157
	LOG_DEBUG(" NVIC_DFSR 0x%" PRIx32 "", cortex_m->nvic_dfsr);
158
159

	return ERROR_OK;
160
161
}

162
static int cortex_m_single_step_core(struct target *target)
163
{
164
	struct cortex_m_common *cortex_m = target_to_cm(target);
165
	struct armv7m_common *armv7m = &cortex_m->armv7m;
166
	int retval;
zwelch's avatar
zwelch committed
167

168
	/* Mask interrupts before clearing halt, if not done already.  This avoids
David Brownell's avatar
David Brownell committed
169
170
171
	 * Erratum 377497 (fixed in r1p0) where setting MASKINTS while clearing
	 * HALT can put the core into an unknown state.
	 */
172
	if (!(cortex_m->dcb_dhcsr & C_MASKINTS)) {
173
		retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DHCSR,
David Brownell's avatar
David Brownell committed
174
				DBGKEY | C_MASKINTS | C_HALT | C_DEBUGEN);
175
176
177
		if (retval != ERROR_OK)
			return retval;
	}
178
	retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DHCSR,
179
			DBGKEY | C_MASKINTS | C_STEP | C_DEBUGEN);
180
181
	if (retval != ERROR_OK)
		return retval;
182
	LOG_DEBUG(" ");
zwelch's avatar
zwelch committed
183

184
	/* restore dhcsr reg */
185
	cortex_m_clear_halt(target);
zwelch's avatar
zwelch committed
186

187
188
189
	return ERROR_OK;
}

190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
static int cortex_m_enable_fpb(struct target *target)
{
	int retval = target_write_u32(target, FP_CTRL, 3);
	if (retval != ERROR_OK)
		return retval;

	/* check the fpb is actually enabled */
	uint32_t fpctrl;
	retval = target_read_u32(target, FP_CTRL, &fpctrl);
	if (retval != ERROR_OK)
		return retval;

	if (fpctrl & 1)
		return ERROR_OK;

	return ERROR_FAIL;
}

208
static int cortex_m_endreset_event(struct target *target)
209
210
{
	int i;
211
	int retval;
212
	uint32_t dcb_demcr;
213
214
215
216
217
	struct cortex_m_common *cortex_m = target_to_cm(target);
	struct armv7m_common *armv7m = &cortex_m->armv7m;
	struct adiv5_dap *swjdp = cortex_m->armv7m.arm.dap;
	struct cortex_m_fp_comparator *fp_list = cortex_m->fp_comparator_list;
	struct cortex_m_dwt_comparator *dwt_list = cortex_m->dwt_comparator_list;
218

219
	/* REVISIT The four debug monitor bits are currently ignored... */
220
	retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DEMCR, &dcb_demcr);
221
222
	if (retval != ERROR_OK)
		return retval;
223
	LOG_DEBUG("DCB_DEMCR = 0x%8.8" PRIx32 "", dcb_demcr);
zwelch's avatar
zwelch committed
224

David Brownell's avatar
David Brownell committed
225
	/* this register is used for emulated dcc channel */
226
	retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRDR, 0);
227
228
	if (retval != ERROR_OK)
		return retval;
zwelch's avatar
zwelch committed
229

230
	/* Enable debug requests */
231
	retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr);
232
233
	if (retval != ERROR_OK)
		return retval;
234
	if (!(cortex_m->dcb_dhcsr & C_DEBUGEN)) {
235
		retval = cortex_m_write_debug_halt_mask(target, 0, C_HALT | C_STEP | C_MASKINTS);
236
237
238
		if (retval != ERROR_OK)
			return retval;
	}
zwelch's avatar
zwelch committed
239

240
241
242
243
244
	/* Restore proper interrupt masking setting. */
	if (cortex_m->isrmasking_mode == CORTEX_M_ISRMASK_ON)
		cortex_m_write_debug_halt_mask(target, C_MASKINTS, 0);
	else
		cortex_m_write_debug_halt_mask(target, 0, C_MASKINTS);
zwelch's avatar
zwelch committed
245

246
247
	/* Enable features controlled by ITM and DWT blocks, and catch only
	 * the vectors we were told to pay attention to.
David Brownell's avatar
David Brownell committed
248
	 *
249
250
251
	 * Target firmware is responsible for all fault handling policy
	 * choices *EXCEPT* explicitly scripted overrides like "vector_catch"
	 * or manual updates to the NVIC SHCSR and CCR registers.
David Brownell's avatar
David Brownell committed
252
	 */
253
	retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DEMCR, TRCENA | armv7m->demcr);
254
255
	if (retval != ERROR_OK)
		return retval;
256

David Brownell's avatar
David Brownell committed
257
	/* Paranoia: evidently some (early?) chips don't preserve all the
Christopher Head's avatar
Christopher Head committed
258
	 * debug state (including FPB, DWT, etc) across reset...
David Brownell's avatar
David Brownell committed
259
260
	 */

261
	/* Enable FPB */
262
263
264
	retval = cortex_m_enable_fpb(target);
	if (retval != ERROR_OK) {
		LOG_ERROR("Failed to enable the FPB");
265
		return retval;
266
	}
267

268
	cortex_m->fpb_enabled = true;
269
270

	/* Restore FPB registers */
271
	for (i = 0; i < cortex_m->fp_num_code + cortex_m->fp_num_lit; i++) {
272
273
274
		retval = target_write_u32(target, fp_list[i].fpcr_address, fp_list[i].fpcr_value);
		if (retval != ERROR_OK)
			return retval;
275
	}
zwelch's avatar
zwelch committed
276

277
	/* Restore DWT registers */
278
	for (i = 0; i < cortex_m->dwt_num_comp; i++) {
279
		retval = target_write_u32(target, dwt_list[i].dwt_comparator_address + 0,
David Brownell's avatar
David Brownell committed
280
				dwt_list[i].comp);
281
282
283
		if (retval != ERROR_OK)
			return retval;
		retval = target_write_u32(target, dwt_list[i].dwt_comparator_address + 4,
David Brownell's avatar
David Brownell committed
284
				dwt_list[i].mask);
285
286
287
		if (retval != ERROR_OK)
			return retval;
		retval = target_write_u32(target, dwt_list[i].dwt_comparator_address + 8,
David Brownell's avatar
David Brownell committed
288
				dwt_list[i].function);
289
290
		if (retval != ERROR_OK)
			return retval;
291
	}
292
293
294
	retval = dap_run(swjdp);
	if (retval != ERROR_OK)
		return retval;
zwelch's avatar
zwelch committed
295

296
	register_cache_invalidate(armv7m->arm.core_cache);
zwelch's avatar
zwelch committed
297

298
	/* make sure we have latest dhcsr flags */
299
	retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr);
zwelch's avatar
zwelch committed
300

301
	return retval;
302
303
}

304
static int cortex_m_examine_debug_reason(struct target *target)
305
{
306
	struct cortex_m_common *cortex_m = target_to_cm(target);
307

308
309
	/* THIS IS NOT GOOD, TODO - better logic for detection of debug state reason
	 * only check the debug reason if we don't know it already */
zwelch's avatar
zwelch committed
310

311
	if ((target->debug_reason != DBG_REASON_DBGRQ)
312
		&& (target->debug_reason != DBG_REASON_SINGLESTEP)) {
313
		if (cortex_m->nvic_dfsr & DFSR_BKPT) {
314
			target->debug_reason = DBG_REASON_BREAKPOINT;
315
			if (cortex_m->nvic_dfsr & DFSR_DWTTRAP)
316
				target->debug_reason = DBG_REASON_WPTANDBKPT;
317
		} else if (cortex_m->nvic_dfsr & DFSR_DWTTRAP)
318
			target->debug_reason = DBG_REASON_WATCHPOINT;
319
		else if (cortex_m->nvic_dfsr & DFSR_VCATCH)
320
			target->debug_reason = DBG_REASON_BREAKPOINT;
321
		else	/* EXTERNAL, HALTED */
322
			target->debug_reason = DBG_REASON_UNDEFINED;
323
324
325
326
327
	}

	return ERROR_OK;
}

328
static int cortex_m_examine_exception_reason(struct target *target)
329
{
330
	uint32_t shcsr = 0, except_sr = 0, cfsr = -1, except_ar = -1;
331
	struct armv7m_common *armv7m = target_to_armv7m(target);
332
	struct adiv5_dap *swjdp = armv7m->arm.dap;
333
	int retval;
334

335
	retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_SHCSR, &shcsr);
336
337
	if (retval != ERROR_OK)
		return retval;
338
	switch (armv7m->exception_number) {
339
340
341
		case 2:	/* NMI */
			break;
		case 3:	/* Hard Fault */
342
			retval = mem_ap_read_atomic_u32(armv7m->debug_ap, NVIC_HFSR, &except_sr);
343
344
			if (retval != ERROR_OK)
				return retval;
345
			if (except_sr & 0x40000000) {
346
				retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &cfsr);
347
348
				if (retval != ERROR_OK)
					return retval;
349
350
351
			}
			break;
		case 4:	/* Memory Management */
352
			retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr);
353
354
			if (retval != ERROR_OK)
				return retval;
355
			retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_MMFAR, &except_ar);
356
357
			if (retval != ERROR_OK)
				return retval;
358
359
			break;
		case 5:	/* Bus Fault */
360
			retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr);
361
362
			if (retval != ERROR_OK)
				return retval;
363
			retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_BFAR, &except_ar);
364
365
			if (retval != ERROR_OK)
				return retval;
366
367
			break;
		case 6:	/* Usage Fault */
368
			retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr);
369
370
			if (retval != ERROR_OK)
				return retval;
371
372
373
374
			break;
		case 11:	/* SVCall */
			break;
		case 12:	/* Debug Monitor */
375
			retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_DFSR, &except_sr);
376
377
			if (retval != ERROR_OK)
				return retval;
378
379
380
381
382
383
384
385
386
			break;
		case 14:	/* PendSV */
			break;
		case 15:	/* SysTick */
			break;
		default:
			except_sr = 0;
			break;
	}
387
388
389
390
391
392
393
	retval = dap_run(swjdp);
	if (retval == ERROR_OK)
		LOG_DEBUG("%s SHCSR 0x%" PRIx32 ", SR 0x%" PRIx32
			", CFSR 0x%" PRIx32 ", AR 0x%" PRIx32,
			armv7m_exception_string(armv7m->exception_number),
			shcsr, except_sr, cfsr, except_ar);
	return retval;
394
395
}

396
static int cortex_m_debug_entry(struct target *target)
397
{
398
	int i;
399
	uint32_t xPSR;
400
	int retval;
401
402
	struct cortex_m_common *cortex_m = target_to_cm(target);
	struct armv7m_common *armv7m = &cortex_m->armv7m;
403
	struct arm *arm = &armv7m->arm;
David Brownell's avatar
David Brownell committed
404
	struct reg *r;
405

406
	LOG_DEBUG(" ");
407

408
	cortex_m_clear_halt(target);
409
	retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr);
410
411
	if (retval != ERROR_OK)
		return retval;
412

413
414
	retval = armv7m->examine_debug_reason(target);
	if (retval != ERROR_OK)
415
416
		return retval;

417
	/* Examine target state and mode
418
419
	 * First load register accessible through core debug port */
	int num_regs = arm->core_cache->num_regs;
420

421
	for (i = 0; i < num_regs; i++) {
422
423
424
		r = &armv7m->arm.core_cache->reg_list[i];
		if (!r->valid)
			arm->read_core_reg(target, r, i, ARM_MODE_ANY);
425
426
	}

427
	r = arm->cpsr;
David Brownell's avatar
David Brownell committed
428
	xPSR = buf_get_u32(r->value, 0, 32);
429

430
	/* For IT instructions xPSR must be reloaded on resume and clear on debug exec */
431
	if (xPSR & 0xf00) {
David Brownell's avatar
David Brownell committed
432
		r->dirty = r->valid;
433
		cortex_m_store_core_reg_u32(target, 16, xPSR & ~0xff);
434
435
436
	}

	/* Are we in an exception handler */
437
	if (xPSR & 0x1FF) {
438
		armv7m->exception_number = (xPSR & 0x1FF);
439
440
441

		arm->core_mode = ARM_MODE_HANDLER;
		arm->map = armv7m_msp_reg_map;
442
	} else {
443
		unsigned control = buf_get_u32(arm->core_cache
444
445
446
				->reg_list[ARMV7M_CONTROL].value, 0, 2);

		/* is this thread privileged? */
447
		arm->core_mode = control & 1
448
449
			? ARM_MODE_USER_THREAD
			: ARM_MODE_THREAD;
450
451
452
453
454
455
456

		/* which stack is it using? */
		if (control & 2)
			arm->map = armv7m_psp_reg_map;
		else
			arm->map = armv7m_msp_reg_map;

457
458
		armv7m->exception_number = 0;
	}
zwelch's avatar
zwelch committed
459

460
	if (armv7m->exception_number)
461
		cortex_m_examine_exception_reason(target);
462

duane's avatar
duane committed
463
	LOG_DEBUG("entered debug state in core mode: %s at PC 0x%" PRIx32 ", target->state: %s",
464
		arm_mode_name(arm->core_mode),
465
		buf_get_u32(arm->pc->value, 0, 32),
466
		target_state_name(target));
467

468
	if (armv7m->post_debug_entry) {
469
470
471
472
		retval = armv7m->post_debug_entry(target);
		if (retval != ERROR_OK)
			return retval;
	}
473
474
475
476

	return ERROR_OK;
}

477
static int cortex_m_poll(struct target *target)
478
{
479
480
	int detected_failure = ERROR_OK;
	int retval = ERROR_OK;
481
	enum target_state prev_target_state = target->state;
482
	struct cortex_m_common *cortex_m = target_to_cm(target);
483
	struct armv7m_common *armv7m = &cortex_m->armv7m;
484
485

	/* Read from Debug Halting Control and Status Register */
486
	retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr);
487
	if (retval != ERROR_OK) {
488
		target->state = TARGET_UNKNOWN;
489
		return retval;
490
	}
zwelch's avatar
zwelch committed
491

492
493
494
	/* Recover from lockup.  See ARMv7-M architecture spec,
	 * section B1.5.15 "Unrecoverable exception cases".
	 */
495
	if (cortex_m->dcb_dhcsr & S_LOCKUP) {
496
		LOG_ERROR("%s -- clearing lockup after double fault",
497
			target_name(target));
498
		cortex_m_write_debug_halt_mask(target, C_HALT, 0);
499
500
		target->debug_reason = DBG_REASON_DBGRQ;

501
502
503
504
505
		/* We have to execute the rest (the "finally" equivalent, but
		 * still throw this exception again).
		 */
		detected_failure = ERROR_FAIL;

506
		/* refresh status bits */
507
		retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr);
508
509
		if (retval != ERROR_OK)
			return retval;
510
511
	}

512
	if (cortex_m->dcb_dhcsr & S_RESET_ST) {
513
514
515
516
		if (target->state != TARGET_RESET) {
			target->state = TARGET_RESET;
			LOG_INFO("%s: external reset detected", target_name(target));
		}
517
		return ERROR_OK;
518
	}
zwelch's avatar
zwelch committed
519

520
	if (target->state == TARGET_RESET) {
David Brownell's avatar
David Brownell committed
521
522
523
524
		/* Cannot switch context while running so endreset is
		 * called with target->state == TARGET_RESET
		 */
		LOG_DEBUG("Exit from reset with dcb_dhcsr 0x%" PRIx32,
525
			cortex_m->dcb_dhcsr);
526
527
528
529
530
		retval = cortex_m_endreset_event(target);
		if (retval != ERROR_OK) {
			target->state = TARGET_UNKNOWN;
			return retval;
		}
531
532
533
		target->state = TARGET_RUNNING;
		prev_target_state = TARGET_RUNNING;
	}
zwelch's avatar
zwelch committed
534

535
	if (cortex_m->dcb_dhcsr & S_HALT) {
536
537
		target->state = TARGET_HALTED;

538
		if ((prev_target_state == TARGET_RUNNING) || (prev_target_state == TARGET_RESET)) {
539
			retval = cortex_m_debug_entry(target);
540
			if (retval != ERROR_OK)
541
				return retval;
zwelch's avatar
zwelch committed
542

543
544
545
			if (arm_semihosting(target, &retval) != 0)
				return retval;

546
547
			target_call_event_callbacks(target, TARGET_EVENT_HALTED);
		}
548
		if (prev_target_state == TARGET_DEBUG_RUNNING) {
549
			LOG_DEBUG(" ");
550
			retval = cortex_m_debug_entry(target);
551
			if (retval != ERROR_OK)
552
				return retval;
553
554
555
556

			target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
		}
	}
zwelch's avatar
zwelch committed
557

558
559
560
	/* REVISIT when S_SLEEP is set, it's in a Sleep or DeepSleep state.
	 * How best to model low power modes?
	 */
561

562
	if (target->state == TARGET_UNKNOWN) {
563
		/* check if processor is retiring instructions */
564
		if (cortex_m->dcb_dhcsr & S_RETIRE_ST) {
565
			target->state = TARGET_RUNNING;
566
			retval = ERROR_OK;
567
568
		}
	}
zwelch's avatar
zwelch committed
569

570
571
572
573
574
575
576
577
578
579
580
	/* Check that target is truly halted, since the target could be resumed externally */
	if ((prev_target_state == TARGET_HALTED) && !(cortex_m->dcb_dhcsr & S_HALT)) {
		/* registers are now invalid */
		register_cache_invalidate(armv7m->arm.core_cache);

		target->state = TARGET_RUNNING;
		LOG_WARNING("%s: external resume detected", target_name(target));
		target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
		retval = ERROR_OK;
	}

581
582
583
584
	/* Did we detect a failure condition that we cleared? */
	if (detected_failure != ERROR_OK)
		retval = detected_failure;
	return retval;
585
586
}

587
static int cortex_m_halt(struct target *target)
588
{
zwelch's avatar
zwelch committed
589
	LOG_DEBUG("target->state: %s",
590
		target_state_name(target));
zwelch's avatar
zwelch committed
591

592
	if (target->state == TARGET_HALTED) {
593
		LOG_DEBUG("target was already halted");
oharboe's avatar
   
oharboe committed
594
		return ERROR_OK;
595
	}
zwelch's avatar
zwelch committed
596

597
	if (target->state == TARGET_UNKNOWN)
598
		LOG_WARNING("target was in unknown state when halt was requested");
zwelch's avatar
zwelch committed
599

600
601
	if (target->state == TARGET_RESET) {
		if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) {
602
			LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST");
603
			return ERROR_TARGET_FAILURE;
604
		} else {
605
			/* we came here in a reset_halt or reset_init sequence
606
			 * debug entry was already prepared in cortex_m3_assert_reset()
607
608
			 */
			target->debug_reason = DBG_REASON_DBGRQ;
zwelch's avatar
zwelch committed
609
610

			return ERROR_OK;
611
612
613
		}
	}

614
	/* Write to Debug Halting Control and Status Register */
615
	cortex_m_write_debug_halt_mask(target, C_HALT, 0);
616
617

	target->debug_reason = DBG_REASON_DBGRQ;
zwelch's avatar
zwelch committed
618

619
620
621
	return ERROR_OK;
}

622
static int cortex_m_soft_reset_halt(struct target *target)
623
{
624
	struct cortex_m_common *cortex_m = target_to_cm(target);
625
	struct armv7m_common *armv7m = &cortex_m->armv7m;
626
	uint32_t dcb_dhcsr = 0;
ntfreak's avatar
ntfreak committed
627
	int retval, timeout = 0;
628

629
630
631
632
633
634
	/* soft_reset_halt is deprecated on cortex_m as the same functionality
	 * can be obtained by using 'reset halt' and 'cortex_m reset_config vectreset'
	 * As this reset only used VC_CORERESET it would only ever reset the cortex_m
	 * core, not the peripherals */
	LOG_WARNING("soft_reset_halt is deprecated, please use 'reset halt' instead.");

635
	/* Enter debug state on reset; restore DEMCR in endreset_event() */
636
	retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DEMCR,
David Brownell's avatar
David Brownell committed
637
			TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET);
638
639
	if (retval != ERROR_OK)
		return retval;
zwelch's avatar
zwelch committed
640

David Brownell's avatar
David Brownell committed
641
	/* Request a core-only reset */
642
	retval = mem_ap_write_atomic_u32(armv7m->debug_ap, NVIC_AIRCR,
David Brownell's avatar
David Brownell committed
643
			AIRCR_VECTKEY | AIRCR_VECTRESET);
644
645
	if (retval != ERROR_OK)
		return retval;
646
647
648
	target->state = TARGET_RESET;

	/* registers are now invalid */
649
	register_cache_invalidate(cortex_m->armv7m.arm.core_cache);
650

651
	while (timeout < 100) {
652
		retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &dcb_dhcsr);
653
		if (retval == ERROR_OK) {
654
			retval = mem_ap_read_atomic_u32(armv7m->debug_ap, NVIC_DFSR,
655
					&cortex_m->nvic_dfsr);
656
657
			if (retval != ERROR_OK)
				return retval;
David Brownell's avatar
David Brownell committed
658
			if ((dcb_dhcsr & S_HALT)
659
				&& (cortex_m->nvic_dfsr & DFSR_VCATCH)) {
David Brownell's avatar
David Brownell committed
660
661
662
				LOG_DEBUG("system reset-halted, DHCSR 0x%08x, "
					"DFSR 0x%08x",
					(unsigned) dcb_dhcsr,
663
664
					(unsigned) cortex_m->nvic_dfsr);
				cortex_m_poll(target);
David Brownell's avatar
David Brownell committed
665
				/* FIXME restore user's vector catch config */
666
				return ERROR_OK;
667
			} else
David Brownell's avatar
David Brownell committed
668
669
670
				LOG_DEBUG("waiting for system reset-halt, "
					"DHCSR 0x%08x, %d ms",
					(unsigned) dcb_dhcsr, timeout);
671
672
		}
		timeout++;
673
		alive_sleep(1);
674
	}
zwelch's avatar
zwelch committed
675

676
677
678
	return ERROR_OK;
}

679
void cortex_m_enable_breakpoints(struct target *target)
680
{
681
	struct breakpoint *breakpoint = target->breakpoints;
682
683

	/* set any pending breakpoints */
684
	while (breakpoint) {
685
		if (!breakpoint->set)
686
			cortex_m_set_breakpoint(target, breakpoint);
687
688
689
690
		breakpoint = breakpoint->next;
	}
}

691
static int cortex_m_resume(struct target *target, int current,
692
	target_addr_t address, int handle_breakpoints, int debug_execution)
693
{
694
	struct armv7m_common *armv7m = target_to_armv7m(target);
695
	struct breakpoint *breakpoint = NULL;
696
	uint32_t resume_pc;
David Brownell's avatar
David Brownell committed
697
	struct reg *r;
zwelch's avatar
zwelch committed
698

699
	if (target->state != TARGET_HALTED) {
700
		LOG_WARNING("target not halted");
701
702
		return ERROR_TARGET_NOT_HALTED;
	}
zwelch's avatar
zwelch committed
703

704
	if (!debug_execution) {
705
		target_free_all_working_areas(target);
706
707
		cortex_m_enable_breakpoints(target);
		cortex_m_enable_watchpoints(target);
708
	}
zwelch's avatar
zwelch committed
709

710
	if (debug_execution) {
711
		r = armv7m->arm.core_cache->reg_list + ARMV7M_PRIMASK;
David Brownell's avatar
David Brownell committed
712

713
		/* Disable interrupts */
David Brownell's avatar
David Brownell committed
714
715
716
717
718
719
720
721
722
723
724
725
726
		/* We disable interrupts in the PRIMASK register instead of
		 * masking with C_MASKINTS.  This is probably the same issue
		 * as Cortex-M3 Erratum 377493 (fixed in r1p0):  C_MASKINTS
		 * in parallel with disabled interrupts can cause local faults
		 * to not be taken.
		 *
		 * REVISIT this clearly breaks non-debug execution, since the
		 * PRIMASK register state isn't saved/restored...  workaround
		 * by never resuming app code after debug execution.
		 */
		buf_set_u32(r->value, 0, 1, 1);
		r->dirty = true;
		r->valid = true;
727

728
		/* Make sure we are in Thumb mode */
729
		r = armv7m->arm.cpsr;
David Brownell's avatar
David Brownell committed
730
731
732
		buf_set_u32(r->value, 24, 1, 1);
		r->dirty = true;
		r->valid = true;
733
734
735
	}

	/* current = 1: continue on current pc, otherwise continue at <address> */
David Brownell's avatar
David Brownell committed
736
	r = armv7m->arm.pc;
737
	if (!current) {
David Brownell's avatar
David Brownell committed
738
739
740
		buf_set_u32(r->value, 0, 32, address);
		r->dirty = true;
		r->valid = true;
741
	}
zwelch's avatar
zwelch committed
742

743
744
745
746
747
	/* if we halted last time due to a bkpt instruction
	 * then we have to manually step over it, otherwise
	 * the core will break again */

	if (!breakpoint_find(target, buf_get_u32(r->value, 0, 32))
748
		&& !debug_execution)
749
750
		armv7m_maybe_skip_bkpt_inst(target, NULL);

David Brownell's avatar
David Brownell committed
751
	resume_pc = buf_get_u32(r->value, 0, 32);
752

753
	armv7m_restore_context(target);
zwelch's avatar
zwelch committed
754

755
	/* the front-end may request us not to handle breakpoints */
756
	if (handle_breakpoints) {
757
		/* Single step past breakpoint at current address */
758
759
		breakpoint = breakpoint_find(target, resume_pc);
		if (breakpoint) {
760
			LOG_DEBUG("unset breakpoint at " TARGET_ADDR_FMT " (ID: %" PRIu32 ")",
761
762
				breakpoint->address,
				breakpoint->unique_id);
763
764
765
			cortex_m_unset_breakpoint(target, breakpoint);
			cortex_m_single_step_core(target);
			cortex_m_set_breakpoint(target, breakpoint);
766
767
		}
	}
zwelch's avatar
zwelch committed
768

769
	/* Restart core */
770
	cortex_m_write_