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

Last change on this file since 18f63c0 was b53ad46, checked in by Chris Johns <chrisj@…>, on Apr 14, 2017 at 7:12:44 AM

libdebugger: Work around assert when using _Thread_Executing.

Using _Thread_Executing with RTEMS_DEBUG results in an assert if
the server accesses invalid memory.

Updates #2993.

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