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

5
Last change on this file since e629076 was e629076, checked in by Chris Johns <chrisj@…>, on 11/29/16 at 22:19:05

libdebugger: Build for ARM's without a CP15.

  • Property mode set to 100644
File size: 41.2 KB
RevLine 
[a0d4e99]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
[e629076]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
[a0d4e99]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
[e629076]168 static const uint8_t breakpoint[4] = { 0x75, 0xe0, 0x20, 0xe1 };
[a0d4e99]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 {                                                     \
[e629076]276    ARM_SWITCH_REG;                                        \
[a0d4e99]277    asm volatile(                                          \
[e629076]278      ASM_ARM_MODE                                         \
[a0d4e99]279      ARM_CP14_INSTR(mcr, val, _CRn, _CRm, _opc2)          \
[e629076]280      ASM_THUMB_MODE                                       \
281      : ARM_SWITCH_REG_ASM                                 \
282      : [val] "r" (_val));                                 \
[a0d4e99]283  } while (0)
284
285#define ARM_CP14_READ(_val, _CRn, _CRm, _opc2)             \
286  do {                                                     \
[e629076]287    ARM_SWITCH_REG;                                        \
[a0d4e99]288    asm volatile(                                          \
[e629076]289      ASM_ARM_MODE                                         \
[a0d4e99]290      ARM_CP14_INSTR(mrc, val, _CRn, _CRm, _opc2)          \
[e629076]291      ASM_THUMB_MODE                                       \
292      : ARM_SWITCH_REG_ASM,                                \
293        [val] "=&r" (_val));                               \
[a0d4e99]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                                                      \
[e629076]647    : ARM_SWITCH_REG_ASM                                                \
[a0d4e99]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    "msr  cpsr, r1\n"                        /* restore the irq mask */ \
721    ASM_THUMB_MODE                                                      \
[e629076]722    : ARM_SWITCH_REG_ASM,                                               \
[a0d4e99]723      [o_frame] "=r" (_frame)                                           \
724    : [psr_t] "i" (ARM_PSR_T),                                          \
725      [psr_i] "i" (ARM_PSR_I),                                          \
726      [r0_r12_size] "i" (13 * sizeof(uint32_t)),                        \
727      [frame_cpsr] "i" (EXCEPTION_FRAME_SIZE - sizeof(uint32_t)),       \
728      [frame_size] "i" (EXCEPTION_FRAME_SIZE),                          \
729      [o_frame_fpu] "i" (EXCEPTION_FRAME_FPU_OFFSET),                   \
730      [frame_fpu_size] "i" (EXCEPTION_FRAME_FPU_SIZE + 4)               \
731    : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "memory")
732
733/*
734 * FPU exit. Conditionally D16 or D32 support.
735 */
736#ifdef ARM_MULTILIB_VFP
737#ifdef ARM_MULTILIB_VFP_D32
738#define FPU_EXIT_VFP_D32                                                \
739    "vldmia r0, {d16-d31}\n"
740#else  /* ARM_MULTILIB_VFP_D32 */
741#define FPU_EXIT_VFP_D32
742#endif /* ARM_MULTILIB_VFP_D32 */
743#define EXCEPTION_EXIT_FPU(frame_fpu_size)                              \
744    "ldmia  r0!, {r1-r2}\n"                                             \
745    "vldmia r0!, {d0-d15}\n"                                            \
746    FPU_EXIT_VFP_D32                                                    \
747    "vmsr   FPEXC, r1\n"                                                \
748    "vmsr   FPSCR, r2\n"                                                \
749    "add    sp, %[frame_fpu_size]\n" /* size includes alignment size */
750#else  /* ARM_MULTILIB_VFP */
751#define EXCEPTION_EXIT_FPU(frame_fpu_size)
752#endif /* ARM_MULTILIB_VFP */
753
754/**
755 * Exception exit.
756 *
757 * The thread is to be resumed so we are still in the thread's mode. Copy the
758 * exception frame from the thread's stack back to the exception's stack and
759 * restore the thread's context before returning from the exception to the
760 * thread.
761 *
762 * Note, the code currently assumes cp15 has been set up to match the
763 *       instruction set being used.
764 */
765#define EXCEPTION_EXIT_THREAD(_frame)                                   \
766  __asm__ volatile(                                                     \
767    ASM_ARM_MODE                                                        \
768    "mov  r0, %[i_frame]\n"                         /* get the frame */ \
769    "ldr  r0, [r0, %[frame_fpu]]\n"     /* recover FPU frame pointer */ \
770    EXCEPTION_EXIT_FPU(frame_fpu_size)                                  \
771    "ldr  r2, [sp, %[frame_cpsr]]\n" /* recover exc CPSR from thread */ \
772    "mov  r0, sp\n"                  /* get the thread frame pointer */ \
773    "msr  cpsr, r2\n"            /* switch back to the exc's context */ \
774    "add  r3, sp, #1\n"                               /* get the end */ \
775    "sub  sp, %[frame_size]\n"                    /* alloc the frame */ \
776    "sub  r4, sp, #1\n"                       /* destination address */ \
777    "sub  r5, r0, #1\n"                            /* source address */ \
778    "1:\n"                                                              \
779    "ldrb r1, [r5, #1]!\n"                             /* get a byte */ \
780    "strb r1, [r4, #1]!\n"                           /* put the byte */ \
781    "cmp  r3, r4\n"                                      /* the end? */ \
782    "bne  1b\n"                                                         \
783    "add  r1, r0, %[r0_r12_size]\n"       /* get the sp in the frame */ \
784    "ldm  r1, {r3-r6}\n"                   /* recover from the frame */ \
785    "orr  r1, r6, %[psr_i]\n"  /* get the thread's psr and mask irqs */ \
786    "msr  cpsr, r1\n"                         /* switch to user mode */ \
787    "mov  sp, r3\n"                         /* set the stack pointer */ \
788    "mov  lr, r4\n"                              /* set the link reg */ \
789    "msr  cpsr, r2\n"            /* switch back to the exc's context */ \
790    "msr  spsr, r6\n"                       /* set the thread's CPSR */ \
791    "sub  sp, #4\n"                                                     \
792    "mov  lr, r5\n"                                    /* get the PC */ \
793    "str  lr, [sp]\n"                           /* save the link reg */ \
794    ASM_THUMB_MODE                                                      \
[e629076]795    : ARM_SWITCH_REG_ASM                                                \
[a0d4e99]796    : [psr_i] "i" (ARM_PSR_I),                                          \
797      [r0_r12_size] "i" (13 * sizeof(uint32_t)),                        \
798      [frame_cpsr] "i" (EXCEPTION_FRAME_SIZE - sizeof(uint32_t)),       \
799      [frame_size] "i" (EXCEPTION_FRAME_SIZE),                          \
800      [frame_fpu] "i" (EXCEPTION_FRAME_FPU_OFFSET),                     \
801      [frame_fpu_size] "i" (EXCEPTION_FRAME_FPU_SIZE + 4),              \
802      [i_frame] "r" (_frame)                                            \
803    : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "memory")
804
805#define EXCEPTION_EXIT_EXC()                                            \
806  __asm__ volatile(                                                     \
807    ASM_ARM_MODE                                                        \
808    "ldr  lr, [sp]\n"                        /* recover the link reg */ \
809    "add  sp, #4\n"                                                     \
810    "ldm  sp, {r0-r12}\n"            /* restore the trhead's context */ \
811    "add  sp, %[frame_size]\n"                     /* free the frame */ \
812    "subs pc, lr, #0\n"                       /* return from the exc */ \
813    :                                                                   \
814    : [frame_size] "i" (EXCEPTION_FRAME_SIZE)                           \
815    : "memory")
816
817
818static void __attribute__((naked))
819target_exception_undefined_instruction(void)
820{
821  CPU_Exception_frame* frame;
822  ARM_SWITCH_REG;
823  EXCEPTION_ENTRY_EXC();
824  arm_debug_break_unload();
825  EXCEPTION_ENTRY_THREAD(frame);
826  frame->vector = 1;
827  target_exception(frame);
828  EXCEPTION_EXIT_THREAD(frame);
829  arm_debug_break_load();
830  EXCEPTION_EXIT_EXC();
831}
832
833static void __attribute__((naked))
834target_exception_supervisor_call(void)
835{
836  CPU_Exception_frame* frame;
837  ARM_SWITCH_REG;
838  /*
839   * The PC offset needs to be review so we move past a svc instruction. This
840   * can then used as a user breakpoint. The issue is this exception is used by
841   * the BKPT instruction in the prefetch abort handler to signal a TRAP.
842   */
843  EXCEPTION_ENTRY_EXC();
844  arm_debug_break_unload();
845  EXCEPTION_ENTRY_THREAD(frame);
846  frame->vector = 2;
847  target_exception(frame);
848  EXCEPTION_EXIT_THREAD(frame);
849  arm_debug_break_load();
850  EXCEPTION_EXIT_EXC();
851}
852
853static void __attribute__((naked))
854target_exception_prefetch_abort(void)
855{
856  CPU_Exception_frame* frame;
857  ARM_SWITCH_REG;
858  EXCEPTION_ENTRY_EXC();
859  arm_debug_break_unload();
860  EXCEPTION_ENTRY_THREAD(frame);
[e629076]861#if ARM_CP15
[a0d4e99]862  if ((arm_cp15_get_instruction_fault_status() & 0x1f) == 0x02)
863    frame->vector = 2;
864  else
865    frame->vector = 3;
[e629076]866#else
867  frame->vector = 3;
868#endif
[a0d4e99]869  target_exception(frame);
870  EXCEPTION_EXIT_THREAD(frame);
871  arm_debug_break_load();
872  EXCEPTION_EXIT_EXC();
873}
874
875static void __attribute__((naked))
876target_exception_data_abort(void)
877{
878  CPU_Exception_frame* frame;
879  ARM_SWITCH_REG;
880  EXCEPTION_ENTRY_EXC();
881  arm_debug_break_unload();
882  EXCEPTION_ENTRY_THREAD(frame);
883  frame->vector = 4;
884  target_exception(frame);
885  EXCEPTION_EXIT_THREAD(frame);
886  arm_debug_break_load();
887  EXCEPTION_EXIT_EXC();
888}
889
[e629076]890#if ARM_CP15
891/**
892 * The init value for the text section.
893 */
894static uint32_t text_section_flags;
895
896static void
897rtems_debugger_target_set_vectors(void)
[a0d4e99]898{
[e629076]899  void* text_begin;
900  void* text_end;
[a0d4e99]901  text_begin = &bsp_section_text_begin[0];
902  text_end = &bsp_section_text_end[0];
903  text_section_flags =
904    arm_cp15_set_translation_table_entries(text_begin,
905                                           text_end,
906                                           ARMV7_MMU_DATA_READ_WRITE_CACHED);
907  arm_cp15_set_exception_handler(ARM_EXCEPTION_UNDEF,
908                                 target_exception_undefined_instruction);
909  arm_cp15_set_exception_handler(ARM_EXCEPTION_SWI,
910                                 target_exception_supervisor_call);
911  arm_cp15_set_exception_handler(ARM_EXCEPTION_PREF_ABORT,
912                                 target_exception_prefetch_abort);
913  arm_cp15_set_exception_handler(ARM_EXCEPTION_DATA_ABORT,
914                                 target_exception_data_abort);
[e629076]915}
916#else
917static void
918rtems_debugger_target_set_vectors(void)
919{
920  /*
921   * Dummy, please add support for your ARM variant.
922   */
923  void* ui = target_exception_undefined_instruction;
924  void* sc = target_exception_supervisor_call;
925  void* pa = target_exception_prefetch_abort;
926  void* da = target_exception_data_abort;
927  (void) ui;
928  (void) sc;
929  (void) pa;
930  (void) da;
931}
932#endif
933
934int
935rtems_debugger_target_enable(void)
936{
937  rtems_interrupt_lock_context lock_context;
938  debug_session_active = true;
939  rtems_interrupt_lock_acquire(&target_lock, &lock_context);
940  arm_debug_break_unload();
941  arm_debug_break_clear();
942  rtems_debugger_target_set_vectors();
[a0d4e99]943  rtems_interrupt_lock_release(&target_lock, &lock_context);
944  return 0;
945}
946
947int
948rtems_debugger_target_disable(void)
949{
950  rtems_interrupt_lock_context lock_context;
951#if DOES_NOT_WORK
952  void*                        text_begin;
953  void*                        text_end;
954#endif
955  rtems_interrupt_lock_acquire(&target_lock, &lock_context);
956  debug_session_active = false;
957#if DOES_NOT_WORK
958  text_begin = &bsp_section_text_begin[0];
959  text_end = &bsp_section_text_end[0];
960  arm_cp15_set_translation_table_entries(text_begin,
961                                         text_end,
962                                         text_section_flags);
963#endif
964  rtems_interrupt_lock_release(&target_lock, &lock_context);
965  return 0;
966}
967
968int
969rtems_debugger_target_read_regs(rtems_debugger_thread* thread)
970{
971  if (!rtems_debugger_thread_flag(thread,
972                                  RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID)) {
973    static const uint32_t good_address = (uint32_t) &good_address;
974    uint32_t*             regs = &thread->registers[0];
975    int                   i;
976
977    for (i = 0; i < RTEMS_DEBUGGER_NUMREGS; ++i)
978      regs[i] = (uint32_t) &good_address;
979
980    if (thread->frame) {
981      CPU_Exception_frame* frame = thread->frame;
982
983      /*
984       * Assume interrupts are not masked and if masked set them to the saved
985       * value.
986       */
987      FRAME_SR &= ~CPSR_INTS_MASK;
988
989      if (rtems_debugger_thread_flag(thread,
990                                     RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED)) {
991        FRAME_SR |=
992          (thread->flags >> RTEMS_DEBUGGER_THREAD_FLAG_TARGET_BASE) & CPSR_INTS_MASK;
993        thread->flags = ~RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED;
994      }
995
996      regs[REG_R0]   = frame->register_r0;
997      regs[REG_R1]   = frame->register_r1;
998      regs[REG_R2]   = frame->register_r2;
999      regs[REG_R3]   = frame->register_r3;
1000      regs[REG_R4]   = frame->register_r4;
1001      regs[REG_R5]   = frame->register_r5;
1002      regs[REG_R6]   = frame->register_r6;
1003      regs[REG_R7]   = frame->register_r7;
1004      regs[REG_R8]   = frame->register_r8;
1005      regs[REG_R9]   = frame->register_r9;
1006      regs[REG_R10]  = frame->register_r10;
1007      regs[REG_R11]  = frame->register_r11;
1008      regs[REG_R12]  = frame->register_r12;
1009      regs[REG_SP]   = frame->register_sp;
1010      regs[REG_LR]   = (uint32_t) frame->register_lr;
1011      regs[REG_PC]   = (uint32_t) frame->register_pc;
1012      regs[REG_CPSR] = FRAME_SR;
1013      /*
1014       * Get the signal from the frame.
1015       */
1016      thread->signal = rtems_debugger_target_exception_to_signal(frame);
1017    }
1018    else {
1019#if defined(ARM_MULTILIB_ARCH_V4)
1020      regs[REG_R4]  = thread->tcb->Registers.register_r4;
1021      regs[REG_R5]  = thread->tcb->Registers.register_r5;
1022      regs[REG_R6]  = thread->tcb->Registers.register_r6;
1023      regs[REG_R7]  = thread->tcb->Registers.register_r7;
1024      regs[REG_R8]  = thread->tcb->Registers.register_r8;
1025      regs[REG_R9]  = thread->tcb->Registers.register_r9;
1026      regs[REG_R10] = thread->tcb->Registers.register_r10;
1027      regs[REG_R11] = thread->tcb->Registers.register_fp;
1028      regs[REG_LR]  = (intptr_t) thread->tcb->Registers.register_lr;
1029      regs[REG_PC]  = (intptr_t) thread->tcb->Registers.register_lr;
1030      regs[REG_SP]  = (intptr_t) thread->tcb->Registers.register_sp;
1031#elif defined(ARM_MULTILIB_ARCH_V7M)
1032      regs[REG_R4]  = thread->tcb->Registers.register_r4;
1033      regs[REG_R5]  = thread->tcb->Registers.register_r5;
1034      regs[REG_R6]  = thread->tcb->Registers.register_r6;
1035      regs[REG_R7]  = thread->tcb->Registers.register_r7;
1036      regs[REG_R8]  = thread->tcb->Registers.register_r8;
1037      regs[REG_R9]  = thread->tcb->Registers.register_r9;
1038      regs[REG_R10] = thread->tcb->Registers.register_r10;
1039      regs[REG_R11] = thread->tcb->Registers.register_r11;
1040      regs[REG_LR]  = (intptr_t) thread->tcb->Registers.register_lr;
1041      regs[REG_PC]  = (intptr_t) thread->tcb->Registers.register_lr;
1042      regs[REG_SP]  = (intptr_t) thread->tcb->Registers.register_sp;
1043#endif
1044      /*
1045       * Blocked threads have no signal.
1046       */
1047      thread->signal = 0;
1048    }
1049
1050    thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID;
1051    thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
1052  }
1053
1054  return 0;
1055}
1056
1057int
1058rtems_debugger_target_write_regs(rtems_debugger_thread* thread)
1059{
1060  if (rtems_debugger_thread_flag(thread,
1061                                 RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY)) {
1062    uint32_t* regs = &thread->registers[0];
1063
1064    /*
1065     * Only write to debugger controlled threads. Do not touch the registers
1066     * for threads blocked in the context switcher.
1067     */
1068    if (rtems_debugger_thread_flag(thread,
1069                                   RTEMS_DEBUGGER_THREAD_FLAG_DEBUGGING)) {
1070      CPU_Exception_frame* frame = thread->frame;
1071      frame->register_r0  = regs[REG_R0];
1072      frame->register_r1  = regs[REG_R1];
1073      frame->register_r2  = regs[REG_R2];
1074      frame->register_r3  = regs[REG_R3];
1075      frame->register_r4  = regs[REG_R4];
1076      frame->register_r5  = regs[REG_R5];
1077      frame->register_r6  = regs[REG_R6];
1078      frame->register_r7  = regs[REG_R7];
1079      frame->register_r8  = regs[REG_R8];
1080      frame->register_r9  = regs[REG_R9];
1081      frame->register_r10 = regs[REG_R10];
1082      frame->register_r11 = regs[REG_R11];
1083      frame->register_r12 = regs[REG_R12];
1084      frame->register_sp  = regs[REG_SP];
1085      frame->register_lr  = (void*) regs[REG_LR];
1086      frame->register_pc  = (void*) regs[REG_PC];
1087      FRAME_SR            = regs[REG_CPSR];
1088    }
1089    thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
1090  }
1091  return 0;
1092}
1093
1094DB_UINT
1095rtems_debugger_target_reg_pc(rtems_debugger_thread* thread)
1096{
1097  int r;
1098  r = rtems_debugger_target_read_regs(thread);
1099  if (r >= 0) {
1100    uint32_t* regs = &thread->registers[0];
1101    return regs[REG_PC];
1102  }
1103  return 0;
1104}
1105
1106DB_UINT
1107rtems_debugger_target_frame_pc(CPU_Exception_frame* frame)
1108{
1109  return (DB_UINT) frame->register_pc;
1110}
1111
1112DB_UINT
1113rtems_debugger_target_reg_sp(rtems_debugger_thread* thread)
1114{
1115  int r;
1116  r = rtems_debugger_target_read_regs(thread);
1117  if (r >= 0) {
1118    uint32_t* regs = &thread->registers[0];
1119    return regs[REG_SP];
1120  }
1121  return 0;
1122}
1123
1124DB_UINT
1125rtems_debugger_target_tcb_sp(rtems_debugger_thread* thread)
1126{
1127  return (DB_UINT) thread->tcb->Registers.register_sp;
1128}
1129
1130int
1131rtems_debugger_target_thread_stepping(rtems_debugger_thread* thread)
1132{
1133  if (rtems_debugger_thread_flag(thread,
1134                                 (RTEMS_DEBUGGER_THREAD_FLAG_STEP |
1135                                  RTEMS_DEBUGGER_THREAD_FLAG_STEPPING))) {
1136    /*
1137     * Single stepping and range stepping uses hardware debug breakpoint
1138     * 0. This is reserved for single stepping.
1139     */
1140    CPU_Exception_frame* frame = thread->frame;
1141    arm_debug_hwbreak*   bp = &hw_breaks[0];
1142    int                  i;
1143    for (i = 0; i < hw_breakpoints; ++i, ++bp) {
1144      if (!bp->enabled) {
1145        const uint32_t addr = (intptr_t) frame->register_pc;
1146        const bool     thumb = (FRAME_SR & (1 << 5)) != 0 ? true : false;
1147        uint32_t       bas;
1148
1149        bp->enabled = true;
1150        bp->loaded = false;
1151        bp->address = frame->register_pc;
1152        bp->frame = frame;
1153        bp->length = sizeof(uint32_t);
1154
1155        if (thumb) {
1156          uint16_t instr = *((uint16_t*) frame->register_pc);
1157          switch (instr & 0xf800) {
1158          case 0xe800:
1159          case 0xf000:
1160          case 0xf800:
1161            break;
1162          default:
1163            bp->length = sizeof(uint16_t);
1164            break;
1165          }
1166        }
1167
1168        /*
1169         * See table C3-2 Effect of byte address selection on Breakpoint
1170         * generation and "Instruction address comparisoin programming
1171         * examples.
1172         */
1173        if (thumb) {
1174          if ((addr & (1 << 1)) == 0) {
1175            bas = 0x3; /* b0011 */
1176          }
1177          else {
1178            bas = 0xc; /* b1100 */
1179          }
1180        }
1181        else {
1182          bas = 0xf; /* b1111 */
1183        }
1184
1185        arm_debug_break_setup(bp,
1186                              addr & ~0x3,
1187                              ARM_HW_BP_UNLINKED_INSTR_MISMATCH,
1188                              bas,
1189                              ARM_HW_BP_PRIV_PL0_SUP_SYS);
1190
1191        /*
1192         * Save the interrupt state before stepping if set.
1193         */
[e629076]1194#if ARM_PSR_HAS_INT_MASK
[a0d4e99]1195        if ((FRAME_SR & CPSR_INTS_MASK) != 0) {
1196          uint32_t int_state;
1197          int_state =
1198            (frame->register_cpsr & CPSR_INTS_MASK) << RTEMS_DEBUGGER_THREAD_FLAG_TARGET_BASE;
1199          thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED | int_state;
1200        }
1201        /*
1202         * Mask the interrupt when stepping.
1203         */
1204        FRAME_SR |= CPSR_INTS_MASK;
[e629076]1205#endif
[a0d4e99]1206        break;
1207      }
1208    }
1209  }
1210  return 0;
1211}
1212
1213int
1214rtems_debugger_target_exception_to_signal(CPU_Exception_frame* frame)
1215{
1216  int sig = RTEMS_DEBUGGER_SIGNAL_HUP;
[e629076]1217#if defined(ARM_EXCEPTION_RESET)
[a0d4e99]1218  switch (frame->vector) {
1219  case ARM_EXCEPTION_RESET:
1220  case ARM_EXCEPTION_SWI:
1221    sig = RTEMS_DEBUGGER_SIGNAL_TRAP;
1222    break;
1223  case ARM_EXCEPTION_UNDEF:
1224    sig = RTEMS_DEBUGGER_SIGNAL_ILL;
1225    break;
1226  case ARM_EXCEPTION_FIQ:
1227    sig = RTEMS_DEBUGGER_SIGNAL_FPE;
1228    break;
1229  case ARM_EXCEPTION_PREF_ABORT:
1230  case ARM_EXCEPTION_DATA_ABORT:
1231    sig = RTEMS_DEBUGGER_SIGNAL_SEGV;
1232    break;
1233  case ARM_EXCEPTION_RESERVED:
1234  case ARM_EXCEPTION_IRQ:
1235    sig = RTEMS_DEBUGGER_SIGNAL_BUS;
1236    break;
1237  default:
1238    break;
1239  }
[e629076]1240#endif
[a0d4e99]1241  return sig;
1242}
1243
1244int
1245rtems_debugger_target_hwbreak_control(rtems_debugger_target_watchpoint wp,
1246                                      bool                             insert,
1247                                      DB_UINT                          addr,
1248                                      DB_UINT                          kind)
1249{
1250  /*
1251   * To do.
1252   */
1253  return 0;
1254}
1255
1256int
1257rtems_debugger_target_cache_sync(rtems_debugger_target_swbreak* swbreak)
1258{
1259  /*
1260   * Flush the data cache and invalidate the instruction cache.
1261   */
1262  rtems_cache_flush_multiple_data_lines(swbreak->address,
1263                                        sizeof(breakpoint));
1264  rtems_cache_invalidate_multiple_instruction_lines(swbreak->address,
1265                                                    sizeof(breakpoint));
1266  return 0;
1267}
Note: See TracBrowser for help on using the repository browser.