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

5
Last change on this file since a0d4e99 was a0d4e99, checked in by Chris Johns <chrisj@…>, on 11/25/16 at 04:13:36

cpukit: Add libdebugger, a remote debugger agent for GDB.

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