source: rtems/cpukit/libdebugger/rtems-debugger-arm.c @ 21275b58

5
Last change on this file since 21275b58 was 6ad3f471, checked in by Sebastian Huber <sebastian.huber@…>, on 12/13/17 at 07:42:07

libdebugger: Avoid use of <bsp/linker-symbols.h>

Update #3254.

  • Property mode set to 100644
File size: 43.1 KB
Line 
1/*
2 * Copyright (c) 2016-2017 Chris Johns <chrisj@rtems.org>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#define TARGET_DEBUG 0
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <errno.h>
34#include <inttypes.h>
35#include <stdlib.h>
36
37#include <rtems.h>
38#include <rtems/score/threadimpl.h>
39
40#include "rtems-debugger-target.h"
41#include "rtems-debugger-threads.h"
42
43#if TARGET_DEBUG
44#include <rtems/bspIo.h>
45#endif
46
47/*
48 * ARM Variant controls.
49 */
50#if defined(__ARM_ARCH_7A__) || \
51    defined(__ARM_ARCH_7R__)
52  #define ARM_CP15 1
53#endif
54
55#if (defined(__ARM_ARCH_7M__) || \
56     defined(__ARM_ARCH_7EM__))
57  #define ARM_THUMB_ONLY 1
58#else
59  #define ARM_THUMB_ONLY 0
60#endif
61
62#if defined(ARM_MULTILIB_ARCH_V4)
63 #define ARM_PSR_HAS_INT_MASK 1
64 #define ARM_PSR_HAS_THUMB    1
65#else
66 #define ARM_PSR_HAS_INT_MASK 0
67 #define ARM_PSR_HAS_THUMB    0
68#endif
69
70#if ARM_CP15
71#include <libcpu/arm-cp15.h>
72#endif
73
74/**
75 * If thumb build of code switch the asm to thumb as required.
76 *
77 * If the variant only supports thumb insturctions disable the support.
78 */
79#define ARM_SWITCH_REG     uint32_t arm_switch_reg
80#define ARM_SWITCH_REG_ASM [arm_switch_reg] "=&r" (arm_switch_reg)
81#if !ARM_THUMB_ONLY && defined(__thumb__)
82  #define ASM_ARM_MODE   ".align 2\nbx pc\n.arm\n"
83  #define ASM_THUMB_MODE "add %[arm_switch_reg], pc, #1\nbx %[arm_switch_reg]\n.thumb\n"
84#else
85  #define ASM_ARM_MODE
86  #define ASM_THUMB_MODE
87#endif
88
89/*
90 * Hack to work around ARMv7-M not having a the T and I bits in the PSR.
91 *
92 * This needs to be fixed when real support for this ARM variant is added.
93 */
94#if !defined(ARM_PSR_I)
95  #define ARM_PSR_I 0
96#endif
97#if !defined(ARM_PSR_T)
98  #define ARM_PSR_T 0
99#endif
100
101/*
102 * The ARM has 2 interrupt bits.
103 */
104#define CPSR_IRQ_DISABLE 0x80    /* IIQ disabled when 1 */
105#define CPSR_FIQ_DISABLE 0x40    /* FIQ disabled when 1 */
106#define CPSR_INTS_MASK   (CPSR_IRQ_DISABLE | CPSR_FIQ_DISABLE)
107
108/*
109 * Software breakpoint block size.
110 */
111#define RTEMS_DEBUGGER_SWBREAK_NUM 64
112
113/*
114 * Number of registers.
115 */
116#define RTEMS_DEBUGGER_NUMREGS 26
117
118/*
119 * Number of bytes per register.
120 */
121#define RTEMS_DEBUGGER_REGBYTES 4
122
123/*
124 * Number of bytes of registers.
125 */
126#define RTEMS_DEBUGGER_NUMREGBYTES \
127  (RTEMS_DEBUGGER_NUMREGS * RTEMS_DEBUGGER_REGBYTES)
128
129/*
130 * Debugger registers layout.
131 */
132#define REG_R0    0
133#define REG_R1    1
134#define REG_R2    2
135#define REG_R3    3
136#define REG_R4    4
137#define REG_R5    5
138#define REG_R6    6
139#define REG_R7    7
140#define REG_R8    8
141#define REG_R9    9
142#define REG_R10   10
143#define REG_R11   11
144#define REG_R12   12
145#define REG_SP    13
146#define REG_LR    14
147#define REG_PC    15
148#define REG_CPSR  25
149
150/**
151 * The various status registers.
152 */
153#if defined(ARM_MULTILIB_ARCH_V4)
154 #define FRAME_SR frame->register_cpsr
155#elif defined(ARM_MULTILIB_ARCH_V7M)
156 #define FRAME_SR frame->register_xpsr
157#else
158 #error ARM architecture is not supported.
159#endif
160
161/**
162 * The breakpoint.
163 */
164#ifdef __thumb__
165 static const uint8_t breakpoint[2] = { 0x55, 0xbe };
166#else
167 static const uint8_t breakpoint[4] = { 0x75, 0xe0, 0x20, 0xe1 };
168#endif
169
170/**
171 * Target lock.
172 */
173RTEMS_INTERRUPT_LOCK_DEFINE(static, target_lock, "target_lock")
174
175/**
176 * Is a session active?
177 */
178static bool debug_session_active;
179
180/*
181 * ARM debug hardware.
182 */
183static int debug_version;
184static int debug_revision;;
185static int hw_breakpoints;
186static int hw_watchpoints;
187
188/**
189 * Hardware break and watch points.
190 */
191typedef struct
192{
193  bool                 enabled;
194  bool                 loaded;
195  void*                address;
196  size_t               length;
197  CPU_Exception_frame* frame;
198  uint32_t             control;
199  uint32_t             value;
200} arm_debug_hwbreak;
201
202#define ARM_HW_BREAKPOINT_MAX (16)
203#define ARM_HW_WATCHPOINT_MAX (16)
204
205/*
206 * Types of break points. Only the 2 we use listed.
207 */
208#define ARM_HW_BP_UNLINKED_INSTR_MATCH    (0x00)
209#define ARM_HW_BP_UNLINKED_INSTR_MISMATCH (0x04)
210
211/*
212 * Privilege levels.
213 */
214#define ARM_HW_BP_PRIV_PL0_SUP_SYS (0x00)
215#define ARM_HW_BP_PRIV_PL1_ONLY    (0x01)
216#define ARM_HW_BP_PRIV_PL0_ONLY    (0x02)
217#define ARM_HW_BP_PRIV_ALL_MODES   (0x03)
218
219static arm_debug_hwbreak hw_breaks[ARM_HW_BREAKPOINT_MAX];
220//static arm_debug_hwbreak hw_watches[ARM_HW_WATCHPOINT_MAX];
221
222#if TARGET_DEBUG
223void rtems_debugger_printk_lock(rtems_interrupt_lock_context* lock_context);
224void rtems_debugger_printk_unlock(rtems_interrupt_lock_context* lock_context);
225
226static void target_printk(const char* format, ...) RTEMS_PRINTFLIKE(1, 2);
227static void
228target_printk(const char* format, ...)
229{
230  rtems_interrupt_lock_context lock_context;
231  va_list ap;
232  va_start(ap, format);
233  rtems_debugger_printk_lock(&lock_context);
234  vprintk(format, ap);
235  rtems_debugger_printk_unlock(&lock_context);
236  va_end(ap);
237}
238static const char*
239mode_label(int mode)
240{
241  switch (mode) {
242  case 0x10:
243    return "USR";
244  case 0x11:
245    return "FIQ";
246  case 0x12:
247    return "IRQ";
248  case 0x13:
249    return "SVC";
250  case 0x16:
251    return "MON";
252  case 0x17:
253    return "ABT";
254  case 0x1a:
255    return "HYP";
256  case 0x1b:
257    return "UND";
258  case 0x1f:
259    return "SYS";
260  }
261  return "---";
262}
263#else
264#define target_printk(_fmt, ...)
265#define mode_labels(_m) NULL
266#endif
267
268/*
269 * CP register access.
270 */
271#define ARM_CP_INSTR(_opc, _cp, _op1, _val, _CRn, _CRm, _op2)           \
272  #_opc " p" #_cp ", " #_op1 ", %[" #_val "], c" #_CRn ", c" #_CRm ", " #_op2 "\n"
273
274#define ARM_CP_WRITE(_cp, _op1, _val, _CRn, _CRm, _op2)    \
275  do {                                                     \
276    ARM_SWITCH_REG;                                        \
277    asm volatile(                                          \
278      ASM_ARM_MODE                                         \
279      ARM_CP_INSTR(mcr, _cp, _op1, val, _CRn, _CRm, _op2)  \
280      ASM_THUMB_MODE                                       \
281      : ARM_SWITCH_REG_ASM                                 \
282      : [val] "r" (_val));                                 \
283  } while (0)
284
285#define ARM_CP_READ(_cp, _op1, _val, _CRn, _CRm, _op2)     \
286  do {                                                     \
287    ARM_SWITCH_REG;                                        \
288    asm volatile(                                          \
289      ASM_ARM_MODE                                         \
290      ARM_CP_INSTR(mrc, _cp, _op1, val, _CRn, _CRm, _op2)  \
291      ASM_THUMB_MODE                                       \
292      : ARM_SWITCH_REG_ASM,                                \
293        [val] "=&r" (_val));                               \
294  } while (0)
295
296/*
297 * Read and write a CP14 register.
298 *
299 * The software debug event registers are not easy to program because there are
300 * up to 32 registers and the instructions have to assembler for each of the 32
301 * registers, you cannot program it. This means there is a switch table to do
302 * this.
303 */
304#define ARM_CP14_WRITE(_val, _CRn, _CRm, _op2) \
305  ARM_CP_WRITE(14, 0, _val, _CRn, _CRm, _op2)
306
307#define ARM_CP14_READ(_val, _CRn, _CRm, _op2)  \
308  ARM_CP_READ(14, 0, _val, _CRn, _CRm, _op2)
309
310/*
311 * Read and write a CP15 register.
312 *
313 * The Context ID register is a process level context and used to scope
314 * hardware break points.
315 */
316#define ARM_CP15_WRITE(_val, _op1, _CRn, _CRm, _op2) \
317  ARM_CP_WRITE(15, _op1, _val, _CRn, _CRm, _op2)
318
319#define ARM_CP15_READ(_val, _op1, _CRn, _CRm, _op2)  \
320  ARM_CP_READ(15, _op1, _val, _CRn, _CRm, _op2)
321
322static int
323arm_debug_probe(rtems_debugger_target* target)
324{
325  #define ID_VALUE(_i, _h, _l) ((_i >> _l) & ((1 << ((_h - _l) + 1)) -1))
326  uint32_t          val;
327  const char*       vl = "[Invalid version]";
328  const char* const labels[] = {
329    "ARMv6 [v6]",
330    "ARMv6 [v6.1]",
331    "ARMv7 [v7, all CP14 registers]",
332    "ARMv7 [v7, baseline CP14 registers]",
333    "ARMv7 [v7.1]"
334  };
335  ARM_CP14_READ(val, 0, 0, 0);
336  debug_version = ID_VALUE(val, 19, 16);
337  if (debug_version < 1 || debug_version > 5) {
338    rtems_debugger_printf("rtems-db: arm debug: (v%d.%d) not supported\n",
339                          debug_version, debug_revision);
340    errno = EIO;
341    return -1;
342  }
343  vl = labels[debug_version - 1];
344  debug_revision = ID_VALUE(val, 3, 0);
345  hw_breakpoints = ID_VALUE(val, 27, 24);
346  hw_watchpoints = ID_VALUE(val, 31, 28);
347  rtems_debugger_printf("rtems-db: arm debug: (v%d.%d) %s breakpoints:%d watchpoints:%d\n",
348                        debug_version, debug_revision, vl,
349                        hw_breakpoints, hw_watchpoints);
350  ARM_CP14_READ(val, 0, 1, 0);
351  if ((val & (1 << 15)) == 0) {
352    switch (debug_version) {
353    case 1:
354    case 2:
355      ARM_CP14_WRITE(val | (1 << 15), 0, 1, 0);
356      break;
357    case 3:
358    case 4:
359    case 5:
360    default:
361      ARM_CP14_WRITE(val | (1 << 15), 0, 2, 2);
362      break;
363    }
364    ARM_CP14_READ(val, 0, 1, 0);
365    if ((val & (1 << 15)) == 0) {
366      rtems_debugger_printf("rtems-db: arm debug: cannot enter monitor mode\n");
367      errno = EIO;
368      return -1;
369    }
370  }
371  return 0;
372}
373
374static inline void
375arm_debug_break_setup(arm_debug_hwbreak* bp,
376                      uint32_t           address,
377                      uint32_t           type,
378                      uint32_t           byte_address_select,
379                      uint32_t           privilege)
380{
381  bp->control = (((type & 0xf) << 20) |
382                 ((byte_address_select & 0xf) << 5) |
383                 ((privilege & 0x3) << 1) | 1);
384  bp->value = (intptr_t) address;
385}
386
387static void
388arm_debug_break_write_control(int bp, uint32_t control)
389{
390  switch (bp) {
391  case 0:
392    ARM_CP14_WRITE(control, 0, 0, 5);
393    break;
394  case 1:
395    ARM_CP14_WRITE(control, 0, 1, 5);
396    break;
397  case 2:
398    ARM_CP14_WRITE(control, 0, 2, 5);
399    break;
400  case 3:
401    ARM_CP14_WRITE(control, 0, 3, 5);
402    break;
403  case 4:
404    ARM_CP14_WRITE(control, 0, 4, 5);
405    break;
406  case 5:
407    ARM_CP14_WRITE(control, 0, 5, 5);
408    break;
409  case 6:
410    ARM_CP14_WRITE(control, 0, 6, 5);
411    break;
412  case 7:
413    ARM_CP14_WRITE(control, 0, 7, 5);
414    break;
415  case 8:
416    ARM_CP14_WRITE(control, 0, 8, 5);
417    break;
418  case 9:
419    ARM_CP14_WRITE(control, 0, 9, 5);
420    break;
421  case 10:
422    ARM_CP14_WRITE(control, 0, 10, 5);
423    break;
424  case 11:
425    ARM_CP14_WRITE(control, 0, 11, 5);
426    break;
427  case 12:
428    ARM_CP14_WRITE(control, 0, 12, 5);
429    break;
430  case 13:
431    ARM_CP14_WRITE(control, 0, 13, 5);
432    break;
433  case 14:
434    ARM_CP14_WRITE(control, 0, 14, 5);
435    break;
436  case 15:
437    ARM_CP14_WRITE(control, 0, 15, 5);
438    break;
439  }
440}
441
442static void
443arm_debug_break_write_value(int bp, uint32_t value)
444{
445  switch (bp) {
446  case 0:
447    ARM_CP14_WRITE(value, 0, 0, 4);
448    break;
449  case 1:
450    ARM_CP14_WRITE(value, 0, 1, 4);
451    break;
452  case 2:
453    ARM_CP14_WRITE(value, 0, 2, 4);
454    break;
455  case 3:
456    ARM_CP14_WRITE(value, 0, 3, 4);
457    break;
458  case 4:
459    ARM_CP14_WRITE(value, 0, 4, 4);
460    break;
461  case 5:
462    ARM_CP14_WRITE(value, 0, 5, 4);
463    break;
464  case 6:
465    ARM_CP14_WRITE(value, 0, 6, 4);
466    break;
467  case 7:
468    ARM_CP14_WRITE(value, 0, 7, 4);
469    break;
470  case 8:
471    ARM_CP14_WRITE(value, 0, 8, 4);
472    break;
473  case 9:
474    ARM_CP14_WRITE(value, 0, 9, 4);
475    break;
476  case 10:
477    ARM_CP14_WRITE(value, 0, 10, 4);
478    break;
479  case 11:
480    ARM_CP14_WRITE(value, 0, 11, 4);
481    break;
482  case 12:
483    ARM_CP14_WRITE(value, 0, 12, 4);
484    break;
485  case 13:
486    ARM_CP14_WRITE(value, 0, 13, 4);
487    break;
488  case 14:
489    ARM_CP14_WRITE(value, 0, 14, 4);
490    break;
491  case 15:
492    ARM_CP14_WRITE(value, 0, 15, 4);
493    break;
494  }
495}
496
497static void
498arm_debug_break_clear(void)
499{
500  rtems_interrupt_lock_context lock_context;
501  arm_debug_hwbreak*           bp = &hw_breaks[0];
502  int                          i;
503  rtems_interrupt_lock_acquire(&target_lock, &lock_context);
504  for (i = 0; i < hw_breakpoints; ++i, ++bp) {
505    bp->enabled = false;
506    bp->loaded = false;
507  }
508  rtems_interrupt_lock_release(&target_lock, &lock_context);
509}
510
511static inline void
512arm_debug_set_context_id(const uint32_t id)
513{
514  ARM_CP15_WRITE(id, 0, 13, 0, 1);
515}
516
517/*
518 * You can only load the hardware breaks points when in the SVC mode or the
519 * single step inverted break point will trigger.
520 */
521static void
522arm_debug_break_load(void)
523{
524  rtems_interrupt_lock_context lock_context;
525  arm_debug_hwbreak*            bp = &hw_breaks[0];
526  int                           i;
527  rtems_interrupt_lock_acquire(&target_lock, &lock_context);
528  if (bp->enabled && !bp->loaded) {
529    arm_debug_set_context_id(0xdead1111);
530    arm_debug_break_write_value(0, bp->value);
531    arm_debug_break_write_control(0, bp->control);
532  }
533  ++bp;
534  for (i = 1; i < hw_breakpoints; ++i, ++bp) {
535    if (bp->enabled && !bp->loaded) {
536      bp->loaded = true;
537      arm_debug_break_write_value(i, bp->value);
538      arm_debug_break_write_control(i, bp->control);
539    }
540  }
541  rtems_interrupt_lock_release(&target_lock, &lock_context);
542}
543
544static void
545arm_debug_break_unload(void)
546{
547  rtems_interrupt_lock_context lock_context;
548  arm_debug_hwbreak*           bp = &hw_breaks[0];
549  int                i;
550  rtems_interrupt_lock_acquire(&target_lock, &lock_context);
551  arm_debug_set_context_id(0);
552  for (i = 0; i < hw_breakpoints; ++i, ++bp) {
553    bp->loaded = false;
554    arm_debug_break_write_control(i, 0);
555  }
556  rtems_interrupt_lock_release(&target_lock, &lock_context);
557}
558
559#if NOT_USED_BUT_KEEPING
560static size_t
561arm_debug_break_length(void* pc)
562{
563  arm_debug_hwbreak* bp = &hw_breaks[0];
564  int                i;
565
566  for (i = 0; i < hw_breakpoints; ++i, ++bp) {
567    if (bp->enabled && bp->address == pc) {
568      return bp->length;
569    }
570  }
571  return sizeof(DB_UINT);
572}
573#endif
574
575int
576rtems_debugger_target_configure(rtems_debugger_target* target)
577{
578  target->capabilities = (RTEMS_DEBUGGER_TARGET_CAP_SWBREAK);
579  target->reg_num = RTEMS_DEBUGGER_NUMREGS;
580  target->reg_size = sizeof(uint32_t);
581  target->breakpoint = &breakpoint[0];
582  target->breakpoint_size = sizeof(breakpoint);
583  return arm_debug_probe(target);
584}
585
586static void
587target_exception(CPU_Exception_frame* frame)
588{
589#if TARGET_DEBUG
590  uint32_t ifsr = arm_cp15_get_instruction_fault_status();
591#endif
592
593  target_printk("[} frame = %08lx sig=%d vector=%x ifsr=%08lx pra=%08x\n",
594                (uint32_t) frame,
595                rtems_debugger_target_exception_to_signal(frame),
596                frame->vector, ifsr, (intptr_t) frame->register_pc);
597
598  if ((FRAME_SR & (1 <<  5)) == 0)
599    frame->register_pc = (void*) ((intptr_t) frame->register_pc - 8);
600  else
601    frame->register_pc = (void*) ((intptr_t) frame->register_pc - 4);
602
603  target_printk("[}  R0 = %08" PRIx32 "  R1 = %08" PRIx32       \
604                "  R2 = %08" PRIx32 "  R3 = %08" PRIx32 "\n",
605                frame->register_r0, frame->register_r1,
606                frame->register_r2, frame->register_r3);
607  target_printk("[}  R4 = %08" PRIx32 "  R5 = %08" PRIx32       \
608                "  R6 = %08" PRIx32 "  R7 = %08" PRIx32 "\n",
609                frame->register_r4, frame->register_r5,
610                frame->register_r6, frame->register_r7);
611  target_printk("[}  R8 = %08" PRIx32 "  R9 = %08" PRIx32       \
612                " R10 = %08" PRIx32 " R11 = %08" PRIx32 "\n",
613                frame->register_r8, frame->register_r9,
614                frame->register_r10, frame->register_r11);
615  target_printk("[} R12 = %08" PRIx32 "  SP = %08" PRIx32       \
616                "  LR = %08" PRIxPTR "  PC = %08" PRIxPTR "\n", \
617                frame->register_r12, frame->register_sp,
618                (intptr_t) frame->register_lr, (intptr_t) frame->register_pc);
619  target_printk("[}  CPSR = %08" PRIx32 " %c%c%c%c%c%c%c%c%c%c%c" \
620                " GE:%" PRIx32 " IT:%02" PRIx32 " M:%" PRIx32 " %s\n",
621                FRAME_SR,
622                (FRAME_SR & (1 << 31)) != 0 ? 'N' : '-',
623                (FRAME_SR & (1 << 30)) != 0 ? 'Z' : '-',
624                (FRAME_SR & (1 << 29)) != 0 ? 'C' : '-',
625                (FRAME_SR & (1 << 28)) != 0 ? 'V' : '-',
626                (FRAME_SR & (1 << 27)) != 0 ? 'Q' : '-',
627                (FRAME_SR & (1 << 24)) != 0 ? 'J' : '-',
628                (FRAME_SR & (1 <<  9)) != 0 ? 'E' : '-',
629                (FRAME_SR & (1 <<  8)) != 0 ? 'A' : '-',
630                (FRAME_SR & (1 <<  7)) != 0 ? 'I' : '-',
631                (FRAME_SR & (1 <<  6)) != 0 ? 'F' : '-',
632                (FRAME_SR & (1 <<  5)) != 0 ? 'T' : '-',
633                ((FRAME_SR >> (25 - 5)) & (0x3 << 5)) | ((FRAME_SR >> 10) & 0x1f),
634                (FRAME_SR >> 16) & 0xf,
635                FRAME_SR & 0x1f, mode_label(FRAME_SR & 0x1f));
636
637  arm_debug_break_clear();
638
639  if (!debug_session_active)
640    _ARM_Exception_default(frame);
641
642  switch (rtems_debugger_target_exception(frame)) {
643  case rtems_debugger_target_exc_consumed:
644  default:
645    break;
646  case rtems_debugger_target_exc_step:
647    FRAME_SR |= CPSR_INTS_MASK;
648    break;
649  case rtems_debugger_target_exc_cascade:
650    target_printk("rtems-db: unhandled exception: cascading\n");
651    _ARM_Exception_default(frame);
652    break;
653  }
654
655  target_printk("[} resuming frame = %08lx PC = %08" PRIxPTR " CPSR = %08" PRIx32 "\n",
656                (uint32_t) frame, (intptr_t) frame->register_pc, FRAME_SR);
657}
658
659/**
660 * Exception stack frame size.
661 *
662 * The size is the exception stack frame plus the CPSR from the exception. We
663 * save the CPSR and restore it when we exit the exception.
664 */
665#define EXCEPTION_FRAME_SIZE (sizeof(CPU_Exception_frame) + sizeof(uint32_t))
666
667/**
668 * Exception stack frame FPU offsets and sizes.
669 */
670#define EXCEPTION_FRAME_FPU_SIZE   ARM_VFP_CONTEXT_SIZE
671#define EXCEPTION_FRAME_FPU_OFFSET ARM_EXCEPTION_FRAME_VFP_CONTEXT_OFFSET
672
673/**
674 * Exception entry.
675 *
676 * We have switched from svc (or even user) to an exception mode. Save the
677 * current CPSR and create an exception frame on the exception's stack and then
678 * copy it to the thread's stack. Switch back to the thread's context and mode
679 * to handle the exception to avoid any stack checks thinking the stack is
680 * blown. This lets the thread be suspended.
681 *
682 * The entry is in two parts, the exception mode entry and the trhead mode
683 * entry. This lets us disable any hardware breakpoint support. We need to do
684 * this because it is enabled in PL0 mode.
685 *
686 * Note, the code currently assumes cp15 has been set up to match the
687 *       instruction set being used.
688 */
689#define EXCEPTION_ENTRY_EXC()                                           \
690  __asm__ volatile(                                                     \
691    ASM_ARM_MODE                                                        \
692    "sub  sp, %[frame_size]\n"           /* alloc the frame and CPSR */ \
693    "stm  sp, {r0-r12}\n"                            /* store r0-r12 */ \
694    "sub  sp, #4\n"                                                     \
695    "str  lr, [sp]\n"                           /* save the link reg */ \
696    ASM_THUMB_MODE                                                      \
697    : ARM_SWITCH_REG_ASM                                                \
698    : [frame_size] "i" (EXCEPTION_FRAME_SIZE)                           \
699    : "memory")
700
701/*
702 * FPU entry. Conditionally D16 or D32 support.
703 */
704#ifdef ARM_MULTILIB_VFP
705#ifdef ARM_MULTILIB_VFP_D32
706#define FPU_ENTRY_VFP_D32                                               \
707    "vstmia  r5!, {d16-d31}\n"
708#else  /* ARM_MULTILIB_VFP_D32 */
709#define FPU_ENTRY_VFP_D32                                               \
710    "mov    r3, #0\n"                                                   \
711    "mov    r4, #0\n"                                                   \
712    "adds   r6, r5, #128\n"                                             \
713    "3:\n"                                                              \
714    "stmia  r5!, {r3-r4}\n"                                             \
715    "cmp    r5, r6\n"                                                   \
716    "bne    3b\n"
717#endif /* ARM_MULTILIB_VFP_D32 */
718#define EXCEPTION_ENTRY_FPU(frame_fpu_size)                             \
719    "sub    sp, %[frame_fpu_size]\n" /* size includes alignment size */ \
720    "add    r5, sp, #4\n"                        /* up to align down */ \
721    "bic    r5, r5, #7\n"                     /* align the FPU frame */ \
722    "str    r5, [r2]\n"               /* store the FPU frame pointer */ \
723    "vmrs   r3, FPEXC\n"                                                \
724    "vmrs   r4, FPSCR\n"                                                \
725    "stmia  r5!, {r3-r4}\n"                                             \
726    "vstmia r5!, {d0-d15}\n"                                            \
727    FPU_ENTRY_VFP_D32
728#else  /* ARM_MULTILIB_VFP */
729#define EXCEPTION_ENTRY_FPU(frame_fpu_size)
730#endif /* ARM_MULTILIB_VFP */
731
732#define EXCEPTION_ENTRY_THREAD(_frame)                                  \
733  __asm__ volatile(                                                     \
734    ASM_ARM_MODE                                                        \
735    "ldr  lr, [sp]\n"                        /* recover the link reg */ \
736    "add  sp, #4\n"                                                     \
737    "add  r0, sp, %[r0_r12_size]\n"       /* get the sp in the frame */ \
738    "mrs  r1, spsr\n"                            /* get the saved sr */ \
739    "mov  r6, r1\n"                            /* stash it for later */ \
740    "bic  r1, r1, %[psr_t]\n"         /* clear thumb mode, not sure? */ \
741    "orr  r1, r1, %[psr_i]\n"                           /* mask irqs */ \
742    "mrs  r2, cpsr\n"                          /* get the current sr */ \
743    "str  r2, [sp, %[frame_cpsr]]\n"          /* save for exc return */ \
744    "msr  cpsr, r1\n"                         /* switch to user mode */ \
745    "mov  r3, sp\n"                         /* get the stack pointer */ \
746    "mov  r4, lr\n"                              /* get the link reg */ \
747    "msr  cpsr, r2\n"                            /* back to exc mode */ \
748    "mov  r5, lr\n"                                   /* get the PRA */ \
749    "stm  r0, {r3-r6}\n"                      /* save into the frame */ \
750    "sub  r4, r3, %[frame_size]\n"            /* destination address */ \
751    "mov  r6, r4\n"                                /* save the frame */ \
752    "sub  r4, #1\n"                          /* one before the start */ \
753    "add  r3, #1\n"                              /* one past the end */ \
754    "sub  r5, sp, #1\n"                            /* source address */ \
755    "1:\n"                                                              \
756    "ldrb r0, [r5, #1]!\n"                             /* get a byte */ \
757    "strb r0, [r4, #1]!\n"                           /* put the byte */ \
758    "cmp  r3, r4\n"                                      /* the end? */ \
759    "bne  1b\n"                                                         \
760    "add  sp, %[frame_size]\n"            /* free the frame and CPSR */ \
761    "mrs  r1, spsr\n"                   /* get the thread's saved sr */ \
762    "orr  r2, r1, %[psr_i]\n"                           /* mask irqs */ \
763    "msr  cpsr, r2\n"         /* switch back to the thread's context */ \
764    "sub  sp, %[frame_size]\n"          /* alloc in the thread stack */ \
765    "mov  %[o_frame], sp\n"                        /* save the frame */ \
766    "add  r2, sp, %[o_frame_fpu]\n"            /* get the FPU offset */ \
767    "mov  r3, #0\n"                                                     \
768    "str  r3, [r2]\n"                 /* clear the FPU frame pointer */ \
769    EXCEPTION_ENTRY_FPU(frame_fpu_size)                                 \
770    "bic  r1, r1, %[psr_i]\n"        /* clear irq mask, debug checks */ \
771    "msr  cpsr, r1\n"       /* restore the state with irq mask clear */ \
772    ASM_THUMB_MODE                                                      \
773    : ARM_SWITCH_REG_ASM,                                               \
774      [o_frame] "=r" (_frame)                                           \
775    : [psr_t] "i" (ARM_PSR_T),                                          \
776      [psr_i] "i" (ARM_PSR_I),                                          \
777      [r0_r12_size] "i" (13 * sizeof(uint32_t)),                        \
778      [frame_cpsr] "i" (EXCEPTION_FRAME_SIZE - sizeof(uint32_t)),       \
779      [frame_size] "i" (EXCEPTION_FRAME_SIZE),                          \
780      [o_frame_fpu] "i" (EXCEPTION_FRAME_FPU_OFFSET),                   \
781      [frame_fpu_size] "i" (EXCEPTION_FRAME_FPU_SIZE + 4)               \
782    : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "memory")
783
784/*
785 * FPU exit. Conditionally D16 or D32 support.
786 */
787#ifdef ARM_MULTILIB_VFP
788#ifdef ARM_MULTILIB_VFP_D32
789#define FPU_EXIT_VFP_D32                                                \
790    "vldmia r0, {d16-d31}\n"
791#else  /* ARM_MULTILIB_VFP_D32 */
792#define FPU_EXIT_VFP_D32
793#endif /* ARM_MULTILIB_VFP_D32 */
794#define EXCEPTION_EXIT_FPU(frame_fpu_size)                              \
795    "ldmia  r0!, {r1-r2}\n"                                             \
796    "vldmia r0!, {d0-d15}\n"                                            \
797    FPU_EXIT_VFP_D32                                                    \
798    "vmsr   FPEXC, r1\n"                                                \
799    "vmsr   FPSCR, r2\n"                                                \
800    "add    sp, %[frame_fpu_size]\n" /* size includes alignment size */
801#else  /* ARM_MULTILIB_VFP */
802#define EXCEPTION_EXIT_FPU(frame_fpu_size)
803#endif /* ARM_MULTILIB_VFP */
804
805/**
806 * Exception exit.
807 *
808 * The thread is to be resumed so we are still in the thread's mode. Copy the
809 * exception frame from the thread's stack back to the exception's stack and
810 * restore the thread's context before returning from the exception to the
811 * thread.
812 *
813 * Note, the code currently assumes cp15 has been set up to match the
814 *       instruction set being used.
815 */
816#define EXCEPTION_EXIT_THREAD(_frame)                                   \
817  __asm__ volatile(                                                     \
818    ASM_ARM_MODE                                                        \
819    "mov  r0, %[i_frame]\n"                         /* get the frame */ \
820    "ldr  r0, [r0, %[frame_fpu]]\n"     /* recover FPU frame pointer */ \
821    EXCEPTION_EXIT_FPU(frame_fpu_size)                                  \
822    "ldr  r2, [sp, %[frame_cpsr]]\n" /* recover exc CPSR from thread */ \
823    "mov  r0, sp\n"                  /* get the thread frame pointer */ \
824    "msr  cpsr, r2\n"            /* switch back to the exc's context */ \
825    "add  r3, sp, #1\n"                               /* get the end */ \
826    "sub  sp, %[frame_size]\n"                    /* alloc the frame */ \
827    "sub  r4, sp, #1\n"                       /* destination address */ \
828    "sub  r5, r0, #1\n"                            /* source address */ \
829    "1:\n"                                                              \
830    "ldrb r1, [r5, #1]!\n"                             /* get a byte */ \
831    "strb r1, [r4, #1]!\n"                           /* put the byte */ \
832    "cmp  r3, r4\n"                                      /* the end? */ \
833    "bne  1b\n"                                                         \
834    "add  r1, r0, %[r0_r12_size]\n"       /* get the sp in the frame */ \
835    "ldm  r1, {r3-r6}\n"                   /* recover from the frame */ \
836    "orr  r1, r6, %[psr_i]\n"  /* get the thread's psr and mask irqs */ \
837    "msr  cpsr, r1\n"                         /* switch to user mode */ \
838    "mov  sp, r3\n"                         /* set the stack pointer */ \
839    "mov  lr, r4\n"                              /* set the link reg */ \
840    "msr  cpsr, r2\n"            /* switch back to the exc's context */ \
841    "msr  spsr, r6\n"                       /* set the thread's CPSR */ \
842    "sub  sp, #4\n"                                                     \
843    "mov  lr, r5\n"                                    /* get the PC */ \
844    "str  lr, [sp]\n"                           /* save the link reg */ \
845    ASM_THUMB_MODE                                                      \
846    : ARM_SWITCH_REG_ASM                                                \
847    : [psr_i] "i" (ARM_PSR_I),                                          \
848      [r0_r12_size] "i" (13 * sizeof(uint32_t)),                        \
849      [frame_cpsr] "i" (EXCEPTION_FRAME_SIZE - sizeof(uint32_t)),       \
850      [frame_size] "i" (EXCEPTION_FRAME_SIZE),                          \
851      [frame_fpu] "i" (EXCEPTION_FRAME_FPU_OFFSET),                     \
852      [frame_fpu_size] "i" (EXCEPTION_FRAME_FPU_SIZE + 4),              \
853      [i_frame] "r" (_frame)                                            \
854    : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "memory")
855
856#define EXCEPTION_EXIT_EXC()                                            \
857  __asm__ volatile(                                                     \
858    ASM_ARM_MODE                                                        \
859    "ldr  lr, [sp]\n"                        /* recover the link reg */ \
860    "add  sp, #4\n"                                                     \
861    "ldm  sp, {r0-r12}\n"            /* restore the trhead's context */ \
862    "add  sp, %[frame_size]\n"                     /* free the frame */ \
863    "subs pc, lr, #0\n"                       /* return from the exc */ \
864    :                                                                   \
865    : [frame_size] "i" (EXCEPTION_FRAME_SIZE)                           \
866    : "memory")
867
868
869static void __attribute__((naked))
870target_exception_undefined_instruction(void)
871{
872  CPU_Exception_frame* frame;
873  ARM_SWITCH_REG;
874  EXCEPTION_ENTRY_EXC();
875  arm_debug_break_unload();
876  EXCEPTION_ENTRY_THREAD(frame);
877  frame->vector = 1;
878  target_exception(frame);
879  EXCEPTION_EXIT_THREAD(frame);
880  arm_debug_break_load();
881  EXCEPTION_EXIT_EXC();
882}
883
884static void __attribute__((naked))
885target_exception_supervisor_call(void)
886{
887  CPU_Exception_frame* frame;
888  ARM_SWITCH_REG;
889  /*
890   * The PC offset needs to be review so we move past a svc instruction. This
891   * can then used as a user breakpoint. The issue is this exception is used by
892   * the BKPT instruction in the prefetch abort handler to signal a TRAP.
893   */
894  EXCEPTION_ENTRY_EXC();
895  arm_debug_break_unload();
896  EXCEPTION_ENTRY_THREAD(frame);
897  frame->vector = 2;
898  target_exception(frame);
899  EXCEPTION_EXIT_THREAD(frame);
900  arm_debug_break_load();
901  EXCEPTION_EXIT_EXC();
902}
903
904static void __attribute__((naked))
905target_exception_prefetch_abort(void)
906{
907  CPU_Exception_frame* frame;
908  ARM_SWITCH_REG;
909  EXCEPTION_ENTRY_EXC();
910  arm_debug_break_unload();
911  EXCEPTION_ENTRY_THREAD(frame);
912#if ARM_CP15
913  if ((arm_cp15_get_instruction_fault_status() & 0x1f) == 0x02)
914    frame->vector = 2;
915  else
916    frame->vector = 3;
917#else
918  frame->vector = 3;
919#endif
920  target_exception(frame);
921  EXCEPTION_EXIT_THREAD(frame);
922  arm_debug_break_load();
923  EXCEPTION_EXIT_EXC();
924}
925
926static void __attribute__((naked))
927target_exception_data_abort(void)
928{
929  CPU_Exception_frame* frame;
930  ARM_SWITCH_REG;
931  EXCEPTION_ENTRY_EXC();
932  arm_debug_break_unload();
933  EXCEPTION_ENTRY_THREAD(frame);
934  frame->vector = 4;
935  target_exception(frame);
936  EXCEPTION_EXIT_THREAD(frame);
937  arm_debug_break_load();
938  EXCEPTION_EXIT_EXC();
939}
940
941#if ARM_CP15
942/**
943 * The init value for the text section.
944 */
945static uint32_t text_section_flags;
946
947/* Defined by linkcmds.base */
948extern char bsp_section_text_begin[];
949extern char bsp_section_text_end[];
950
951static void
952rtems_debugger_target_set_vectors(void)
953{
954  void* text_begin;
955  void* text_end;
956  text_begin = &bsp_section_text_begin[0];
957  text_end = &bsp_section_text_end[0];
958  text_section_flags =
959    arm_cp15_set_translation_table_entries(text_begin,
960                                           text_end,
961                                           ARMV7_MMU_DATA_READ_WRITE_CACHED);
962  arm_cp15_set_exception_handler(ARM_EXCEPTION_UNDEF,
963                                 target_exception_undefined_instruction);
964  arm_cp15_set_exception_handler(ARM_EXCEPTION_SWI,
965                                 target_exception_supervisor_call);
966  arm_cp15_set_exception_handler(ARM_EXCEPTION_PREF_ABORT,
967                                 target_exception_prefetch_abort);
968  arm_cp15_set_exception_handler(ARM_EXCEPTION_DATA_ABORT,
969                                 target_exception_data_abort);
970}
971#else
972static void
973rtems_debugger_target_set_vectors(void)
974{
975  /*
976   * Dummy, please add support for your ARM variant.
977   */
978  void* ui = target_exception_undefined_instruction;
979  void* sc = target_exception_supervisor_call;
980  void* pa = target_exception_prefetch_abort;
981  void* da = target_exception_data_abort;
982  (void) ui;
983  (void) sc;
984  (void) pa;
985  (void) da;
986}
987#endif
988
989int
990rtems_debugger_target_enable(void)
991{
992  rtems_interrupt_lock_context lock_context;
993  debug_session_active = true;
994  arm_debug_break_unload();
995  arm_debug_break_clear();
996  rtems_interrupt_lock_acquire(&target_lock, &lock_context);
997  rtems_debugger_target_set_vectors();
998  rtems_interrupt_lock_release(&target_lock, &lock_context);
999  return 0;
1000}
1001
1002int
1003rtems_debugger_target_disable(void)
1004{
1005  rtems_interrupt_lock_context lock_context;
1006#if DOES_NOT_WORK
1007  void*                        text_begin;
1008  void*                        text_end;
1009#endif
1010  arm_debug_break_unload();
1011  arm_debug_break_clear();
1012  rtems_interrupt_lock_acquire(&target_lock, &lock_context);
1013  debug_session_active = false;
1014#if DOES_NOT_WORK
1015  text_begin = &bsp_section_text_begin[0];
1016  text_end = &bsp_section_text_end[0];
1017  arm_cp15_set_translation_table_entries(text_begin,
1018                                         text_end,
1019                                         text_section_flags);
1020#endif
1021  rtems_interrupt_lock_release(&target_lock, &lock_context);
1022  return 0;
1023}
1024
1025int
1026rtems_debugger_target_read_regs(rtems_debugger_thread* thread)
1027{
1028  if (!rtems_debugger_thread_flag(thread,
1029                                  RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID)) {
1030    static const uint32_t good_address = (uint32_t) &good_address;
1031    uint32_t*             regs = &thread->registers[0];
1032    int                   i;
1033
1034    for (i = 0; i < RTEMS_DEBUGGER_NUMREGS; ++i)
1035      regs[i] = (uint32_t) &good_address;
1036
1037    if (thread->frame) {
1038      CPU_Exception_frame* frame = thread->frame;
1039
1040      /*
1041       * Assume interrupts are not masked and if masked set them to the saved
1042       * value.
1043       */
1044      FRAME_SR &= ~CPSR_INTS_MASK;
1045
1046      if (rtems_debugger_thread_flag(thread,
1047                                     RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED)) {
1048        FRAME_SR |=
1049          (thread->flags >> RTEMS_DEBUGGER_THREAD_FLAG_TARGET_BASE) & CPSR_INTS_MASK;
1050        thread->flags = ~RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED;
1051      }
1052
1053      regs[REG_R0]   = frame->register_r0;
1054      regs[REG_R1]   = frame->register_r1;
1055      regs[REG_R2]   = frame->register_r2;
1056      regs[REG_R3]   = frame->register_r3;
1057      regs[REG_R4]   = frame->register_r4;
1058      regs[REG_R5]   = frame->register_r5;
1059      regs[REG_R6]   = frame->register_r6;
1060      regs[REG_R7]   = frame->register_r7;
1061      regs[REG_R8]   = frame->register_r8;
1062      regs[REG_R9]   = frame->register_r9;
1063      regs[REG_R10]  = frame->register_r10;
1064      regs[REG_R11]  = frame->register_r11;
1065      regs[REG_R12]  = frame->register_r12;
1066      regs[REG_SP]   = frame->register_sp;
1067      regs[REG_LR]   = (uint32_t) frame->register_lr;
1068      regs[REG_PC]   = (uint32_t) frame->register_pc;
1069      regs[REG_CPSR] = FRAME_SR;
1070      /*
1071       * Get the signal from the frame.
1072       */
1073      thread->signal = rtems_debugger_target_exception_to_signal(frame);
1074    }
1075    else {
1076#if defined(ARM_MULTILIB_ARCH_V4)
1077      regs[REG_R4]  = thread->tcb->Registers.register_r4;
1078      regs[REG_R5]  = thread->tcb->Registers.register_r5;
1079      regs[REG_R6]  = thread->tcb->Registers.register_r6;
1080      regs[REG_R7]  = thread->tcb->Registers.register_r7;
1081      regs[REG_R8]  = thread->tcb->Registers.register_r8;
1082      regs[REG_R9]  = thread->tcb->Registers.register_r9;
1083      regs[REG_R10] = thread->tcb->Registers.register_r10;
1084      regs[REG_R11] = thread->tcb->Registers.register_fp;
1085      regs[REG_LR]  = (intptr_t) thread->tcb->Registers.register_lr;
1086      regs[REG_PC]  = (intptr_t) thread->tcb->Registers.register_lr;
1087      regs[REG_SP]  = (intptr_t) thread->tcb->Registers.register_sp;
1088#elif defined(ARM_MULTILIB_ARCH_V7M)
1089      regs[REG_R4]  = thread->tcb->Registers.register_r4;
1090      regs[REG_R5]  = thread->tcb->Registers.register_r5;
1091      regs[REG_R6]  = thread->tcb->Registers.register_r6;
1092      regs[REG_R7]  = thread->tcb->Registers.register_r7;
1093      regs[REG_R8]  = thread->tcb->Registers.register_r8;
1094      regs[REG_R9]  = thread->tcb->Registers.register_r9;
1095      regs[REG_R10] = thread->tcb->Registers.register_r10;
1096      regs[REG_R11] = thread->tcb->Registers.register_r11;
1097      regs[REG_LR]  = (intptr_t) thread->tcb->Registers.register_lr;
1098      regs[REG_PC]  = (intptr_t) thread->tcb->Registers.register_lr;
1099      regs[REG_SP]  = (intptr_t) thread->tcb->Registers.register_sp;
1100#endif
1101      /*
1102       * Blocked threads have no signal.
1103       */
1104      thread->signal = 0;
1105    }
1106
1107    thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID;
1108    thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
1109  }
1110
1111  return 0;
1112}
1113
1114int
1115rtems_debugger_target_write_regs(rtems_debugger_thread* thread)
1116{
1117  if (rtems_debugger_thread_flag(thread,
1118                                 RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY)) {
1119    uint32_t* regs = &thread->registers[0];
1120
1121    /*
1122     * Only write to debugger controlled exception threads. Do not touch the
1123     * registers for threads blocked in the context switcher.
1124     */
1125    if (rtems_debugger_thread_flag(thread,
1126                                   RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION)) {
1127      CPU_Exception_frame* frame = thread->frame;
1128      frame->register_r0  = regs[REG_R0];
1129      frame->register_r1  = regs[REG_R1];
1130      frame->register_r2  = regs[REG_R2];
1131      frame->register_r3  = regs[REG_R3];
1132      frame->register_r4  = regs[REG_R4];
1133      frame->register_r5  = regs[REG_R5];
1134      frame->register_r6  = regs[REG_R6];
1135      frame->register_r7  = regs[REG_R7];
1136      frame->register_r8  = regs[REG_R8];
1137      frame->register_r9  = regs[REG_R9];
1138      frame->register_r10 = regs[REG_R10];
1139      frame->register_r11 = regs[REG_R11];
1140      frame->register_r12 = regs[REG_R12];
1141      frame->register_sp  = regs[REG_SP];
1142      frame->register_lr  = (void*) regs[REG_LR];
1143      frame->register_pc  = (void*) regs[REG_PC];
1144      FRAME_SR            = regs[REG_CPSR];
1145    }
1146    thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
1147  }
1148  return 0;
1149}
1150
1151DB_UINT
1152rtems_debugger_target_reg_pc(rtems_debugger_thread* thread)
1153{
1154  int r;
1155  r = rtems_debugger_target_read_regs(thread);
1156  if (r >= 0) {
1157    uint32_t* regs = &thread->registers[0];
1158    return regs[REG_PC];
1159  }
1160  return 0;
1161}
1162
1163DB_UINT
1164rtems_debugger_target_frame_pc(CPU_Exception_frame* frame)
1165{
1166  return (DB_UINT) frame->register_pc;
1167}
1168
1169DB_UINT
1170rtems_debugger_target_reg_sp(rtems_debugger_thread* thread)
1171{
1172  int r;
1173  r = rtems_debugger_target_read_regs(thread);
1174  if (r >= 0) {
1175    uint32_t* regs = &thread->registers[0];
1176    return regs[REG_SP];
1177  }
1178  return 0;
1179}
1180
1181DB_UINT
1182rtems_debugger_target_tcb_sp(rtems_debugger_thread* thread)
1183{
1184  return (DB_UINT) thread->tcb->Registers.register_sp;
1185}
1186
1187int
1188rtems_debugger_target_thread_stepping(rtems_debugger_thread* thread)
1189{
1190  if (rtems_debugger_thread_flag(thread, RTEMS_DEBUGGER_THREAD_FLAG_STEP_INSTR)) {
1191    /*
1192     * Single stepping and range stepping uses hardware debug breakpoint
1193     * 0. This is reserved for single stepping.
1194     */
1195    CPU_Exception_frame* frame = thread->frame;
1196    arm_debug_hwbreak*   bp = &hw_breaks[0];
1197    target_printk("[} stepping: %s\n", bp->enabled ? "yes" : "no");
1198    if (!bp->enabled) {
1199      const uint32_t addr = (intptr_t) frame->register_pc;
1200      const bool     thumb = (FRAME_SR & (1 << 5)) != 0 ? true : false;
1201      uint32_t       bas;
1202
1203      bp->enabled = true;
1204      bp->loaded = false;
1205      bp->address = frame->register_pc;
1206      bp->frame = frame;
1207      bp->length = sizeof(uint32_t);
1208
1209      if (thumb) {
1210        uint16_t instr = *((uint16_t*) frame->register_pc);
1211        switch (instr & 0xf800) {
1212        case 0xe800:
1213        case 0xf000:
1214        case 0xf800:
1215          break;
1216        default:
1217          bp->length = sizeof(uint16_t);
1218          break;
1219        }
1220      }
1221
1222      /*
1223       * See table C3-2 Effect of byte address selection on Breakpoint
1224       * generation and "Instruction address comparision programming
1225       * examples.
1226       */
1227      if (thumb) {
1228        if ((addr & (1 << 1)) == 0) {
1229          bas = 0x3; /* b0011 */
1230        }
1231        else {
1232          bas = 0xc; /* b1100 */
1233        }
1234      }
1235      else {
1236        bas = 0xf; /* b1111 */
1237      }
1238
1239      arm_debug_break_setup(bp,
1240                            addr & ~0x3,
1241                            ARM_HW_BP_UNLINKED_INSTR_MISMATCH,
1242                            bas,
1243                            ARM_HW_BP_PRIV_PL0_SUP_SYS);
1244
1245      /*
1246       * Save the interrupt state before stepping if set.
1247       */
1248#if ARM_PSR_HAS_INT_MASK
1249      if ((FRAME_SR & CPSR_INTS_MASK) != 0) {
1250        uint32_t int_state;
1251        int_state =
1252          (frame->register_cpsr & CPSR_INTS_MASK) << RTEMS_DEBUGGER_THREAD_FLAG_TARGET_BASE;
1253        thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED | int_state;
1254      }
1255      /*
1256       * Mask the interrupt when stepping.
1257       */
1258      FRAME_SR |= CPSR_INTS_MASK;
1259#endif
1260    }
1261  }
1262  return 0;
1263}
1264
1265int
1266rtems_debugger_target_exception_to_signal(CPU_Exception_frame* frame)
1267{
1268  int sig = RTEMS_DEBUGGER_SIGNAL_HUP;
1269#if defined(ARM_MULTILIB_ARCH_V4)
1270  switch (frame->vector) {
1271  case ARM_EXCEPTION_RESET:
1272  case ARM_EXCEPTION_SWI:
1273    sig = RTEMS_DEBUGGER_SIGNAL_TRAP;
1274    break;
1275  case ARM_EXCEPTION_UNDEF:
1276    sig = RTEMS_DEBUGGER_SIGNAL_ILL;
1277    break;
1278  case ARM_EXCEPTION_FIQ:
1279    sig = RTEMS_DEBUGGER_SIGNAL_FPE;
1280    break;
1281  case ARM_EXCEPTION_PREF_ABORT:
1282  case ARM_EXCEPTION_DATA_ABORT:
1283    sig = RTEMS_DEBUGGER_SIGNAL_SEGV;
1284    break;
1285  case ARM_EXCEPTION_RESERVED:
1286  case ARM_EXCEPTION_IRQ:
1287    sig = RTEMS_DEBUGGER_SIGNAL_BUS;
1288    break;
1289  default:
1290    break;
1291  }
1292#endif
1293  return sig;
1294}
1295
1296int
1297rtems_debugger_target_hwbreak_insert(void)
1298{
1299  /*
1300   * Do nothing, load on exit of the exception handler.
1301   */
1302  return 0;
1303}
1304
1305int
1306rtems_debugger_target_hwbreak_remove(void)
1307{
1308  arm_debug_break_unload();
1309  return 0;
1310}
1311
1312int
1313rtems_debugger_target_hwbreak_control(rtems_debugger_target_watchpoint wp,
1314                                      bool                             insert,
1315                                      DB_UINT                          addr,
1316                                      DB_UINT                          kind)
1317{
1318  /*
1319   * To do.
1320   */
1321  return 0;
1322}
1323
1324int
1325rtems_debugger_target_cache_sync(rtems_debugger_target_swbreak* swbreak)
1326{
1327  /*
1328   * Flush the data cache and invalidate the instruction cache.
1329   */
1330  rtems_cache_flush_multiple_data_lines(swbreak->address,
1331                                        sizeof(breakpoint));
1332  rtems_cache_instruction_sync_after_code_change(swbreak->address,
1333                                                 sizeof(breakpoint));
1334  return 0;
1335}
Note: See TracBrowser for help on using the repository browser.