99afccc490d0e46acc01f1398a63dc82d6c6347e
[openocd.git] / src / target / hla_target.c
1 /***************************************************************************
2 * Copyright (C) 2011 by Mathias Kuester *
3 * Mathias Kuester <kesmtp@freenet.de> *
4 * *
5 * Copyright (C) 2011 by Spencer Oliver *
6 * spen@spen-soft.co.uk *
7 * *
8 * revised: 4/25/13 by brent@mbari.org [DCC target request support] *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
22 ***************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "jtag/interface.h"
29 #include "jtag/jtag.h"
30 #include "jtag/hla/hla_transport.h"
31 #include "jtag/hla/hla_interface.h"
32 #include "jtag/hla/hla_layout.h"
33 #include "register.h"
34 #include "algorithm.h"
35 #include "target.h"
36 #include "breakpoints.h"
37 #include "target_type.h"
38 #include "armv7m.h"
39 #include "cortex_m.h"
40 #include "arm_semihosting.h"
41 #include "target_request.h"
42
43 #define savedDCRDR dbgbase /* FIXME: using target->dbgbase to preserve DCRDR */
44
45 #define ARMV7M_SCS_DCRSR DCB_DCRSR
46 #define ARMV7M_SCS_DCRDR DCB_DCRDR
47
48 static inline struct hl_interface_s *target_to_adapter(struct target *target)
49 {
50 return target->tap->priv;
51 }
52
53 static int adapter_load_core_reg_u32(struct target *target,
54 uint32_t regsel, uint32_t *value)
55 {
56 struct hl_interface_s *adapter = target_to_adapter(target);
57 return adapter->layout->api->read_reg(adapter->handle, regsel, value);
58 }
59
60 static int adapter_store_core_reg_u32(struct target *target,
61 uint32_t regsel, uint32_t value)
62 {
63 struct hl_interface_s *adapter = target_to_adapter(target);
64 return adapter->layout->api->write_reg(adapter->handle, regsel, value);
65 }
66
67 static int adapter_examine_debug_reason(struct target *target)
68 {
69 if ((target->debug_reason != DBG_REASON_DBGRQ)
70 && (target->debug_reason != DBG_REASON_SINGLESTEP)) {
71 target->debug_reason = DBG_REASON_BREAKPOINT;
72 }
73
74 return ERROR_OK;
75 }
76
77 static int hl_dcc_read(struct hl_interface_s *hl_if, uint8_t *value, uint8_t *ctrl)
78 {
79 uint16_t dcrdr;
80 int retval = hl_if->layout->api->read_mem(hl_if->handle,
81 DCB_DCRDR, 1, sizeof(dcrdr), (uint8_t *)&dcrdr);
82 if (retval == ERROR_OK) {
83 *ctrl = (uint8_t)dcrdr;
84 *value = (uint8_t)(dcrdr >> 8);
85
86 LOG_DEBUG("data 0x%x ctrl 0x%x", *value, *ctrl);
87
88 if (dcrdr & 1) {
89 /* write ack back to software dcc register
90 * to signify we have read data */
91 /* atomically clear just the byte containing the busy bit */
92 static const uint8_t zero;
93 retval = hl_if->layout->api->write_mem(hl_if->handle, DCB_DCRDR, 1, 1, &zero);
94 }
95 }
96 return retval;
97 }
98
99 static int hl_target_request_data(struct target *target,
100 uint32_t size, uint8_t *buffer)
101 {
102 struct hl_interface_s *hl_if = target_to_adapter(target);
103 uint8_t data;
104 uint8_t ctrl;
105 uint32_t i;
106
107 for (i = 0; i < (size * 4); i++) {
108 int err = hl_dcc_read(hl_if, &data, &ctrl);
109 if (err != ERROR_OK)
110 return err;
111
112 buffer[i] = data;
113 }
114
115 return ERROR_OK;
116 }
117
118 static int hl_handle_target_request(void *priv)
119 {
120 struct target *target = priv;
121 int err;
122
123 if (!target_was_examined(target))
124 return ERROR_OK;
125 struct hl_interface_s *hl_if = target_to_adapter(target);
126
127 if (!target->dbg_msg_enabled)
128 return ERROR_OK;
129
130 if (target->state == TARGET_RUNNING) {
131 uint8_t data;
132 uint8_t ctrl;
133
134 err = hl_dcc_read(hl_if, &data, &ctrl);
135 if (err != ERROR_OK)
136 return err;
137
138 /* check if we have data */
139 if (ctrl & (1 << 0)) {
140 uint32_t request;
141
142 /* we assume target is quick enough */
143 request = data;
144 err = hl_dcc_read(hl_if, &data, &ctrl);
145 if (err != ERROR_OK)
146 return err;
147
148 request |= (data << 8);
149 err = hl_dcc_read(hl_if, &data, &ctrl);
150 if (err != ERROR_OK)
151 return err;
152
153 request |= (data << 16);
154 err = hl_dcc_read(hl_if, &data, &ctrl);
155 if (err != ERROR_OK)
156 return err;
157
158 request |= (data << 24);
159 target_request(target, request);
160 }
161 }
162
163 return ERROR_OK;
164 }
165
166 static int adapter_init_arch_info(struct target *target,
167 struct cortex_m_common *cortex_m,
168 struct jtag_tap *tap)
169 {
170 struct armv7m_common *armv7m;
171
172 LOG_DEBUG("%s", __func__);
173
174 armv7m = &cortex_m->armv7m;
175 armv7m_init_arch_info(target, armv7m);
176
177 armv7m->load_core_reg_u32 = adapter_load_core_reg_u32;
178 armv7m->store_core_reg_u32 = adapter_store_core_reg_u32;
179
180 armv7m->examine_debug_reason = adapter_examine_debug_reason;
181 armv7m->stlink = true;
182
183 target_register_timer_callback(hl_handle_target_request, 1,
184 TARGET_TIMER_TYPE_PERIODIC, target);
185
186 return ERROR_OK;
187 }
188
189 static int adapter_init_target(struct command_context *cmd_ctx,
190 struct target *target)
191 {
192 LOG_DEBUG("%s", __func__);
193
194 armv7m_build_reg_cache(target);
195 arm_semihosting_init(target);
196 return ERROR_OK;
197 }
198
199 static int adapter_target_create(struct target *target,
200 Jim_Interp *interp)
201 {
202 LOG_DEBUG("%s", __func__);
203 struct adiv5_private_config *pc = target->private_config;
204 if (pc != NULL && pc->ap_num > 0) {
205 LOG_ERROR("hla_target: invalid parameter -ap-num (> 0)");
206 return ERROR_COMMAND_SYNTAX_ERROR;
207 }
208
209 struct cortex_m_common *cortex_m = calloc(1, sizeof(struct cortex_m_common));
210 if (cortex_m == NULL) {
211 LOG_ERROR("No memory creating target");
212 return ERROR_FAIL;
213 }
214
215 adapter_init_arch_info(target, cortex_m, target->tap);
216
217 return ERROR_OK;
218 }
219
220 static int adapter_load_context(struct target *target)
221 {
222 struct armv7m_common *armv7m = target_to_armv7m(target);
223 int num_regs = armv7m->arm.core_cache->num_regs;
224
225 for (int i = 0; i < num_regs; i++) {
226
227 struct reg *r = &armv7m->arm.core_cache->reg_list[i];
228 if (!r->valid)
229 armv7m->arm.read_core_reg(target, r, i, ARM_MODE_ANY);
230 }
231
232 return ERROR_OK;
233 }
234
235 static int adapter_debug_entry(struct target *target)
236 {
237 struct hl_interface_s *adapter = target_to_adapter(target);
238 struct armv7m_common *armv7m = target_to_armv7m(target);
239 struct arm *arm = &armv7m->arm;
240 struct reg *r;
241 uint32_t xPSR;
242 int retval;
243
244 /* preserve the DCRDR across halts */
245 retval = target_read_u32(target, DCB_DCRDR, &target->savedDCRDR);
246 if (retval != ERROR_OK)
247 return retval;
248
249 retval = armv7m->examine_debug_reason(target);
250 if (retval != ERROR_OK)
251 return retval;
252
253 adapter_load_context(target);
254
255 /* make sure we clear the vector catch bit */
256 adapter->layout->api->write_debug_reg(adapter->handle, DCB_DEMCR, TRCENA);
257
258 r = arm->cpsr;
259 xPSR = buf_get_u32(r->value, 0, 32);
260
261 /* Are we in an exception handler */
262 if (xPSR & 0x1FF) {
263 armv7m->exception_number = (xPSR & 0x1FF);
264
265 arm->core_mode = ARM_MODE_HANDLER;
266 arm->map = armv7m_msp_reg_map;
267 } else {
268 unsigned control = buf_get_u32(arm->core_cache
269 ->reg_list[ARMV7M_CONTROL].value, 0, 3);
270
271 /* is this thread privileged? */
272 arm->core_mode = control & 1
273 ? ARM_MODE_USER_THREAD
274 : ARM_MODE_THREAD;
275
276 /* which stack is it using? */
277 if (control & 2)
278 arm->map = armv7m_psp_reg_map;
279 else
280 arm->map = armv7m_msp_reg_map;
281
282 armv7m->exception_number = 0;
283 }
284
285 LOG_DEBUG("entered debug state in core mode: %s at PC 0x%08" PRIx32 ", target->state: %s",
286 arm_mode_name(arm->core_mode),
287 buf_get_u32(arm->pc->value, 0, 32),
288 target_state_name(target));
289
290 return retval;
291 }
292
293 static int adapter_poll(struct target *target)
294 {
295 enum target_state state;
296 struct hl_interface_s *adapter = target_to_adapter(target);
297 struct armv7m_common *armv7m = target_to_armv7m(target);
298 enum target_state prev_target_state = target->state;
299
300 state = adapter->layout->api->state(adapter->handle);
301
302 if (state == TARGET_UNKNOWN) {
303 LOG_ERROR("jtag status contains invalid mode value - communication failure");
304 return ERROR_TARGET_FAILURE;
305 }
306
307 if (prev_target_state == state)
308 return ERROR_OK;
309
310 if (prev_target_state == TARGET_DEBUG_RUNNING && state == TARGET_RUNNING)
311 return ERROR_OK;
312
313 target->state = state;
314
315 if (state == TARGET_HALTED) {
316
317 int retval = adapter_debug_entry(target);
318 if (retval != ERROR_OK)
319 return retval;
320
321 if (prev_target_state == TARGET_DEBUG_RUNNING) {
322 target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
323 } else {
324 if (arm_semihosting(target, &retval) != 0)
325 return retval;
326
327 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
328 }
329
330 LOG_DEBUG("halted: PC: 0x%08" PRIx32, buf_get_u32(armv7m->arm.pc->value, 0, 32));
331 }
332
333 return ERROR_OK;
334 }
335
336 static int hl_assert_reset(struct target *target)
337 {
338 int res = ERROR_OK;
339 struct hl_interface_s *adapter = target_to_adapter(target);
340 struct armv7m_common *armv7m = target_to_armv7m(target);
341 bool use_srst_fallback = true;
342
343 LOG_DEBUG("%s", __func__);
344
345 enum reset_types jtag_reset_config = jtag_get_reset_config();
346
347 bool srst_asserted = false;
348
349 if ((jtag_reset_config & RESET_HAS_SRST) &&
350 (jtag_reset_config & RESET_SRST_NO_GATING)) {
351 res = adapter_assert_reset();
352 srst_asserted = true;
353 }
354
355 adapter->layout->api->write_debug_reg(adapter->handle, DCB_DHCSR, DBGKEY|C_DEBUGEN);
356
357 /* only set vector catch if halt is requested */
358 if (target->reset_halt)
359 adapter->layout->api->write_debug_reg(adapter->handle, DCB_DEMCR, TRCENA|VC_CORERESET);
360 else
361 adapter->layout->api->write_debug_reg(adapter->handle, DCB_DEMCR, TRCENA);
362
363 if (jtag_reset_config & RESET_HAS_SRST) {
364 if (!srst_asserted) {
365 res = adapter_assert_reset();
366 }
367 if (res == ERROR_COMMAND_NOTFOUND)
368 LOG_ERROR("Hardware srst not supported, falling back to software reset");
369 else if (res == ERROR_OK) {
370 /* hardware srst supported */
371 use_srst_fallback = false;
372 }
373 }
374
375 if (use_srst_fallback) {
376 /* stlink v1 api does not support hardware srst, so we use a software reset fallback */
377 adapter->layout->api->write_debug_reg(adapter->handle, NVIC_AIRCR, AIRCR_VECTKEY | AIRCR_SYSRESETREQ);
378 }
379
380 res = adapter->layout->api->reset(adapter->handle);
381
382 if (res != ERROR_OK)
383 return res;
384
385 /* registers are now invalid */
386 register_cache_invalidate(armv7m->arm.core_cache);
387
388 if (target->reset_halt) {
389 target->state = TARGET_RESET;
390 target->debug_reason = DBG_REASON_DBGRQ;
391 } else {
392 target->state = TARGET_HALTED;
393 }
394
395 return ERROR_OK;
396 }
397
398 static int hl_deassert_reset(struct target *target)
399 {
400 enum reset_types jtag_reset_config = jtag_get_reset_config();
401
402 LOG_DEBUG("%s", __func__);
403
404 if (jtag_reset_config & RESET_HAS_SRST)
405 adapter_deassert_reset();
406
407 target->savedDCRDR = 0; /* clear both DCC busy bits on initial resume */
408
409 return target->reset_halt ? ERROR_OK : target_resume(target, 1, 0, 0, 0);
410 }
411
412 static int adapter_halt(struct target *target)
413 {
414 int res;
415 struct hl_interface_s *adapter = target_to_adapter(target);
416
417 LOG_DEBUG("%s", __func__);
418
419 if (target->state == TARGET_HALTED) {
420 LOG_DEBUG("target was already halted");
421 return ERROR_OK;
422 }
423
424 if (target->state == TARGET_UNKNOWN)
425 LOG_WARNING("target was in unknown state when halt was requested");
426
427 res = adapter->layout->api->halt(adapter->handle);
428
429 if (res != ERROR_OK)
430 return res;
431
432 target->debug_reason = DBG_REASON_DBGRQ;
433
434 return ERROR_OK;
435 }
436
437 static int adapter_resume(struct target *target, int current,
438 target_addr_t address, int handle_breakpoints,
439 int debug_execution)
440 {
441 int res;
442 struct hl_interface_s *adapter = target_to_adapter(target);
443 struct armv7m_common *armv7m = target_to_armv7m(target);
444 uint32_t resume_pc;
445 struct breakpoint *breakpoint = NULL;
446 struct reg *pc;
447
448 LOG_DEBUG("%s %d " TARGET_ADDR_FMT " %d %d", __func__, current,
449 address, handle_breakpoints, debug_execution);
450
451 if (target->state != TARGET_HALTED) {
452 LOG_WARNING("target not halted");
453 return ERROR_TARGET_NOT_HALTED;
454 }
455
456 if (!debug_execution) {
457 target_free_all_working_areas(target);
458 cortex_m_enable_breakpoints(target);
459 cortex_m_enable_watchpoints(target);
460 }
461
462 pc = armv7m->arm.pc;
463 if (!current) {
464 buf_set_u32(pc->value, 0, 32, address);
465 pc->dirty = true;
466 pc->valid = true;
467 }
468
469 if (!breakpoint_find(target, buf_get_u32(pc->value, 0, 32))
470 && !debug_execution) {
471 armv7m_maybe_skip_bkpt_inst(target, NULL);
472 }
473
474 resume_pc = buf_get_u32(pc->value, 0, 32);
475
476 /* write any user vector flags */
477 res = target_write_u32(target, DCB_DEMCR, TRCENA | armv7m->demcr);
478 if (res != ERROR_OK)
479 return res;
480
481 armv7m_restore_context(target);
482
483 /* restore savedDCRDR */
484 res = target_write_u32(target, DCB_DCRDR, target->savedDCRDR);
485 if (res != ERROR_OK)
486 return res;
487
488 /* registers are now invalid */
489 register_cache_invalidate(armv7m->arm.core_cache);
490
491 /* the front-end may request us not to handle breakpoints */
492 if (handle_breakpoints) {
493 /* Single step past breakpoint at current address */
494 breakpoint = breakpoint_find(target, resume_pc);
495 if (breakpoint) {
496 LOG_DEBUG("unset breakpoint at " TARGET_ADDR_FMT " (ID: %" PRIu32 ")",
497 breakpoint->address,
498 breakpoint->unique_id);
499 cortex_m_unset_breakpoint(target, breakpoint);
500
501 res = adapter->layout->api->step(adapter->handle);
502
503 if (res != ERROR_OK)
504 return res;
505
506 cortex_m_set_breakpoint(target, breakpoint);
507 }
508 }
509
510 res = adapter->layout->api->run(adapter->handle);
511
512 if (res != ERROR_OK)
513 return res;
514
515 target->debug_reason = DBG_REASON_NOTHALTED;
516
517 if (!debug_execution) {
518 target->state = TARGET_RUNNING;
519 target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
520 } else {
521 target->state = TARGET_DEBUG_RUNNING;
522 target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
523 }
524
525 return ERROR_OK;
526 }
527
528 static int adapter_step(struct target *target, int current,
529 target_addr_t address, int handle_breakpoints)
530 {
531 int res;
532 struct hl_interface_s *adapter = target_to_adapter(target);
533 struct armv7m_common *armv7m = target_to_armv7m(target);
534 struct breakpoint *breakpoint = NULL;
535 struct reg *pc = armv7m->arm.pc;
536 bool bkpt_inst_found = false;
537
538 LOG_DEBUG("%s", __func__);
539
540 if (target->state != TARGET_HALTED) {
541 LOG_WARNING("target not halted");
542 return ERROR_TARGET_NOT_HALTED;
543 }
544
545 if (!current) {
546 buf_set_u32(pc->value, 0, 32, address);
547 pc->dirty = true;
548 pc->valid = true;
549 }
550
551 uint32_t pc_value = buf_get_u32(pc->value, 0, 32);
552
553 /* the front-end may request us not to handle breakpoints */
554 if (handle_breakpoints) {
555 breakpoint = breakpoint_find(target, pc_value);
556 if (breakpoint)
557 cortex_m_unset_breakpoint(target, breakpoint);
558 }
559
560 armv7m_maybe_skip_bkpt_inst(target, &bkpt_inst_found);
561
562 target->debug_reason = DBG_REASON_SINGLESTEP;
563
564 armv7m_restore_context(target);
565
566 /* restore savedDCRDR */
567 res = target_write_u32(target, DCB_DCRDR, target->savedDCRDR);
568 if (res != ERROR_OK)
569 return res;
570
571 target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
572
573 res = adapter->layout->api->step(adapter->handle);
574
575 if (res != ERROR_OK)
576 return res;
577
578 /* registers are now invalid */
579 register_cache_invalidate(armv7m->arm.core_cache);
580
581 if (breakpoint)
582 cortex_m_set_breakpoint(target, breakpoint);
583
584 adapter_debug_entry(target);
585 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
586
587 LOG_INFO("halted: PC: 0x%08" PRIx32, buf_get_u32(armv7m->arm.pc->value, 0, 32));
588
589 return ERROR_OK;
590 }
591
592 static int adapter_read_memory(struct target *target, target_addr_t address,
593 uint32_t size, uint32_t count,
594 uint8_t *buffer)
595 {
596 struct hl_interface_s *adapter = target_to_adapter(target);
597
598 if (!count || !buffer)
599 return ERROR_COMMAND_SYNTAX_ERROR;
600
601 LOG_DEBUG("%s " TARGET_ADDR_FMT " %" PRIu32 " %" PRIu32,
602 __func__, address, size, count);
603
604 return adapter->layout->api->read_mem(adapter->handle, address, size, count, buffer);
605 }
606
607 static int adapter_write_memory(struct target *target, target_addr_t address,
608 uint32_t size, uint32_t count,
609 const uint8_t *buffer)
610 {
611 struct hl_interface_s *adapter = target_to_adapter(target);
612
613 if (!count || !buffer)
614 return ERROR_COMMAND_SYNTAX_ERROR;
615
616 LOG_DEBUG("%s " TARGET_ADDR_FMT " %" PRIu32 " %" PRIu32,
617 __func__, address, size, count);
618
619 return adapter->layout->api->write_mem(adapter->handle, address, size, count, buffer);
620 }
621
622 static const struct command_registration adapter_command_handlers[] = {
623 {
624 .chain = arm_command_handlers,
625 },
626 {
627 .chain = armv7m_trace_command_handlers,
628 },
629 COMMAND_REGISTRATION_DONE
630 };
631
632 struct target_type hla_target = {
633 .name = "hla_target",
634 .deprecated_name = "stm32_stlink",
635
636 .init_target = adapter_init_target,
637 .deinit_target = cortex_m_deinit_target,
638 .target_create = adapter_target_create,
639 .target_jim_configure = adiv5_jim_configure,
640 .examine = cortex_m_examine,
641 .commands = adapter_command_handlers,
642
643 .poll = adapter_poll,
644 .arch_state = armv7m_arch_state,
645
646 .target_request_data = hl_target_request_data,
647 .assert_reset = hl_assert_reset,
648 .deassert_reset = hl_deassert_reset,
649
650 .halt = adapter_halt,
651 .resume = adapter_resume,
652 .step = adapter_step,
653
654 .get_gdb_arch = arm_get_gdb_arch,
655 .get_gdb_reg_list = armv7m_get_gdb_reg_list,
656
657 .read_memory = adapter_read_memory,
658 .write_memory = adapter_write_memory,
659 .checksum_memory = armv7m_checksum_memory,
660 .blank_check_memory = armv7m_blank_check_memory,
661
662 .run_algorithm = armv7m_run_algorithm,
663 .start_algorithm = armv7m_start_algorithm,
664 .wait_algorithm = armv7m_wait_algorithm,
665
666 .add_breakpoint = cortex_m_add_breakpoint,
667 .remove_breakpoint = cortex_m_remove_breakpoint,
668 .add_watchpoint = cortex_m_add_watchpoint,
669 .remove_watchpoint = cortex_m_remove_watchpoint,
670 .profiling = cortex_m_profiling,
671 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)