From cc34558448eb48a70cb39f06d183a133971c79b3 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 5 Aug 2024 12:23:09 +1000 Subject: [PATCH] libdebugger/powerpc: Add PowerPC support Closes #5098 --- cpukit/libdebugger/rtems-debugger-powerpc.c | 1216 +++++++++++++++++++ cpukit/libdebugger/rtems-debugger-server.c | 9 + cpukit/libdebugger/rtems-debugger-target.h | 8 +- spec/build/cpukit/libdebugger.yml | 2 + spec/build/cpukit/objdbpowerpc.yml | 15 + spec/build/cpukit/optlibdebugger.yml | 6 + 6 files changed, 1253 insertions(+), 3 deletions(-) create mode 100644 cpukit/libdebugger/rtems-debugger-powerpc.c create mode 100644 spec/build/cpukit/objdbpowerpc.yml diff --git a/cpukit/libdebugger/rtems-debugger-powerpc.c b/cpukit/libdebugger/rtems-debugger-powerpc.c new file mode 100644 index 0000000000..5de736e6e6 --- /dev/null +++ b/cpukit/libdebugger/rtems-debugger-powerpc.c @@ -0,0 +1,1216 @@ +/* + * Copyright (c) 2024 Contemporary Software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define TARGET_DEBUG 0 + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include +#include + +#include "rtems-debugger-target.h" +#include "rtems-debugger-threads.h" + +#include + +/* + * Hardware breakpoints. Limited by hardware + */ +#define RTEMS_DEBUGGER_HWBREAK_NUM 4 + +/* + * Number of registers. + */ +#define RTEMS_DEBUGGER_NUMREGS 72 + +/* + * Debugger registers layout. + */ +#define REG_R0 0 +#define REG_R1 1 +#define REG_R2 2 +#define REG_R3 3 +#define REG_R4 4 +#define REG_R5 5 +#define REG_R6 6 +#define REG_R7 7 +#define REG_R8 8 +#define REG_R9 9 +#define REG_R10 10 +#define REG_R11 11 +#define REG_R12 12 +#define REG_R13 13 +#define REG_R14 14 +#define REG_R15 15 +#define REG_R16 16 +#define REG_R17 17 +#define REG_R18 18 +#define REG_R19 19 +#define REG_R20 20 +#define REG_R21 21 +#define REG_R22 22 +#define REG_R23 23 +#define REG_R24 24 +#define REG_R25 25 +#define REG_R26 26 +#define REG_R27 27 +#define REG_R28 28 +#define REG_R29 29 +#define REG_R30 30 +#define REG_R31 31 +#define REG_F0 32 +#define REG_F1 33 +#define REG_F2 34 +#define REG_F3 35 +#define REG_F4 36 +#define REG_F5 37 +#define REG_F6 38 +#define REG_F7 39 +#define REG_F8 40 +#define REG_F9 41 +#define REG_F10 42 +#define REG_F11 43 +#define REG_F12 44 +#define REG_F13 45 +#define REG_F14 46 +#define REG_F15 47 +#define REG_F16 48 +#define REG_F17 49 +#define REG_F18 50 +#define REG_F19 51 +#define REG_F20 52 +#define REG_F21 53 +#define REG_F22 54 +#define REG_F23 55 +#define REG_F24 56 +#define REG_F25 57 +#define REG_F26 58 +#define REG_F27 59 +#define REG_F28 60 +#define REG_F29 61 +#define REG_F30 62 +#define REG_F31 63 +#define REG_PC 64 +#define REG_MSR 65 +#define REG_CND 66 +#define REG_LR 67 +#define REG_CNT 68 +#define REG_XER 69 +#define REG_ACC 70 +#define REG_SPEFSCR 71 + +/** + * Register offset table with the total as the last entry. + * + * Check this table in gdb with the command: + * + * maint print remote-registers + * + * The important column is the Rmt Nr and g/G offset + */ + +/* + * MPC604/MPC750 + * + * From the MVME2700 executable (main print architecture): + * + * gdbarch_dump: bfd_arch_info = powerpc:common + * + */ +static const size_t ppc_common_reg_offsets[RTEMS_DEBUGGER_NUMREGS + 1] = +{ + 0, /* REG_R0 4 uint32_t */ + 4, /* REG_R1 4 uint32_t */ + 8, /* REG_R2 4 uint32_t */ + 12, /* REG_R3 4 uint32_t */ + 16, /* REG_R4 4 uint32_t */ + 20, /* REG_R5 4 uint32_t */ + 24, /* REG_R6 4 uint32_t */ + 28, /* REG_R7 4 uint32_t */ + 32, /* REG_R8 4 uint32_t */ + 36, /* REG_R9 4 uint32_t */ + 40, /* REG_R10 4 uint32_t */ + 44, /* REG_R11 4 uint32_t */ + 48, /* REG_R12 4 uint32_t */ + 52, /* REG_R13 4 uint32_t */ + 56, /* REG_R14 4 uint32_t */ + 60, /* REG_R15 4 uint32_t */ + 64, /* REG_R16 4 uint32_t */ + 68, /* REG_R17 4 uint32_t */ + 72, /* REG_R18 4 uint32_t */ + 76, /* REG_R19 4 uint32_t */ + 80, /* REG_R20 4 uint32_t */ + 84, /* REG_R21 4 uint32_t */ + 88, /* REG_R22 4 uint32_t */ + 92, /* REG_R23 4 uint32_t */ + 96, /* REG_R24 4 uint32_t */ + 100, /* REG_R25 4 uint32_t */ + 104, /* REG_R26 4 uint32_t */ + 108, /* REG_R27 4 uint32_t */ + 112, /* REG_R28 4 uint32_t */ + 116, /* REG_R29 4 uint32_t */ + 120, /* REG_R30 4 uint32_t */ + 124, /* REG_R31 4 uint32_t */ + 128, /* REG_F0 8 long */ + 136, /* REG_F1 8 long */ + 144, /* REG_F2 8 long */ + 152, /* REG_F3 8 long */ + 160, /* REG_F4 8 long */ + 168, /* REG_F5 8 long */ + 176, /* REG_F6 8 long */ + 184, /* REG_F7 8 long */ + 192, /* REG_F8 8 long */ + 200, /* REG_F9 8 long */ + 208, /* REG_F10 8 long */ + 216, /* REG_F11 8 long */ + 224, /* REG_F12 8 long */ + 232, /* REG_F13 8 long */ + 240, /* REG_F14 8 long */ + 248, /* REG_F15 8 long */ + 256, /* REG_F16 8 long */ + 264, /* REG_F17 8 long */ + 272, /* REG_F18 8 long */ + 280, /* REG_F19 8 long */ + 288, /* REG_F20 8 long */ + 296, /* REG_F21 8 long */ + 304, /* REG_F22 8 long */ + 312, /* REG_F23 8 long */ + 320, /* REG_F24 8 long */ + 328, /* REG_F25 8 long */ + 336, /* REG_F26 8 long */ + 344, /* REG_F27 8 long */ + 352, /* REG_F28 8 long */ + 360, /* REG_F29 8 long */ + 368, /* REG_F30 8 long */ + 376, /* REG_F31 8 long */ + 384, /* REG_PC 4 *1 */ + 388, /* REG_MSR 4 uint32_t */ + 392, /* REG_CND 4 uint32_t */ + 396, /* REG_LR 4 *1 */ + 400, /* REG_CNT 4 uint32_t */ + 404, /* REG_XER 4 uint32_t */ + 408, /* REG_ACC no present */ + 408, /* REG_SPEFSCR 4 long */ + 412 /* total size */ +}; + +/* + * MPC604/MPC750 + * + * From the MVME2700 executable: + * + * gdbarch_dump: bfd_arch_info = powerpc:e500 + * + * Note: + * No REG_F?? registers defined. The EV?? registers are defined + * and can be viewed in GDB with `info all-registers` however + * there is no remote protocol mapping I can see and the data being + * display in the EV?? rergisters is an alias of the normal register + * data. + */ +static const size_t ppc_e500_reg_offsets[RTEMS_DEBUGGER_NUMREGS + 1] = +{ + 0, /* REG_R0 4 uint32_t */ + 4, /* REG_R1 4 uint32_t */ + 8, /* REG_R2 4 uint32_t */ + 12, /* REG_R3 4 uint32_t */ + 16, /* REG_R4 4 uint32_t */ + 20, /* REG_R5 4 uint32_t */ + 24, /* REG_R6 4 uint32_t */ + 28, /* REG_R7 4 uint32_t */ + 32, /* REG_R8 4 uint32_t */ + 36, /* REG_R9 4 uint32_t */ + 40, /* REG_R10 4 uint32_t */ + 44, /* REG_R11 4 uint32_t */ + 48, /* REG_R12 4 uint32_t */ + 52, /* REG_R13 4 uint32_t */ + 56, /* REG_R14 4 uint32_t */ + 60, /* REG_R15 4 uint32_t */ + 64, /* REG_R16 4 uint32_t */ + 68, /* REG_R17 4 uint32_t */ + 72, /* REG_R18 4 uint32_t */ + 76, /* REG_R19 4 uint32_t */ + 80, /* REG_R20 4 uint32_t */ + 84, /* REG_R21 4 uint32_t */ + 88, /* REG_R22 4 uint32_t */ + 92, /* REG_R23 4 uint32_t */ + 96, /* REG_R24 4 uint32_t */ + 100, /* REG_R25 4 uint32_t */ + 104, /* REG_R26 4 uint32_t */ + 108, /* REG_R27 4 uint32_t */ + 112, /* REG_R28 4 uint32_t */ + 116, /* REG_R29 4 uint32_t */ + 120, /* REG_R30 4 uint32_t */ + 124, /* REG_R31 4 uint32_t */ + 128, /* REG_F0 4 long */ + 132, /* REG_F1 4 long */ + 136, /* REG_F2 4 long */ + 140, /* REG_F3 4 long */ + 144, /* REG_F4 4 long */ + 148, /* REG_F5 4 long */ + 152, /* REG_F6 4 long */ + 156, /* REG_F7 4 long */ + 160, /* REG_F8 4 long */ + 164, /* REG_F9 4 long */ + 168, /* REG_F10 4 long */ + 172, /* REG_F11 4 long */ + 176, /* REG_F12 4 long */ + 180, /* REG_F13 4 long */ + 184, /* REG_F14 4 long */ + 188, /* REG_F15 4 long */ + 192, /* REG_F16 4 long */ + 196, /* REG_F17 4 long */ + 200, /* REG_F18 4 long */ + 204, /* REG_F19 4 long */ + 208, /* REG_F20 4 long */ + 212, /* REG_F21 4 long */ + 216, /* REG_F22 4 long */ + 220, /* REG_F23 4 long */ + 224, /* REG_F24 4 long */ + 228, /* REG_F25 4 long */ + 232, /* REG_F26 4 long */ + 236, /* REG_F27 4 long */ + 240, /* REG_F28 4 long */ + 244, /* REG_F29 4 long */ + 248, /* REG_F30 4 long */ + 252, /* REG_F31 4 long */ + 256, /* REG_PC 4 *1 */ + 260, /* REG_MSR 4 uint32_t */ + 264, /* REG_CND 4 uint32_t */ + 268, /* REG_LR 4 *1 */ + 272, /* REG_CNT 4 uint32_t */ + 276, /* REG_XER 4 uint32_t */ + 280, /* REG_ACC 8 long long */ + 288, /* REG_SPEFSCR 4 long */ + 292 /* total size */ +}; + +static const size_t* ppc_reg_offsets; + +/* + * Number of bytes of registers. + */ +#define RTEMS_DEBUGGER_NUMREGBYTES ppc_reg_offsets[RTEMS_DEBUGGER_NUMREGS] + +/* + * Exception handler to hook. + */ +typedef CPU_Exception_frame BSP_Exception_frame; +typedef void (*exception_handler_t)(BSP_Exception_frame*); +extern exception_handler_t globalExceptHdl; + +/** + * The `sc` instruction + */ +#define TARGET_BKPT 0x0ce00000 +static const uint8_t breakpoint[4] = { 0x0c, 0xe0, 0x00, 0x00 }; + +/** + * Target lock. + */ +RTEMS_INTERRUPT_LOCK_DEFINE(static, target_lock, "target_lock") + +/** + * The orginal exception handler. + */ +static void (*orig_currentExcHandler)(CPU_Exception_frame* frame); + +#if TARGET_DEBUG +#include +static void target_printk(const char* format, ...) RTEMS_PRINTFLIKE(1, 2); +static void +target_printk(const char* format, ...) +{ + va_list ap; + va_start(ap, format); + vprintk(format, ap); + va_end(ap); +} +#else +#define target_printk(_fmt, ...) +#endif + +/* + * The CPU Ident code is taken from libcpu/cpuIndent.h because + * this cpukit code cannot reach over into the BSP headers. + * Adding the code here is not optimal but it solves the need. + */ +#define ASM_RESET_VECTOR 0x01 +#define ASM_MACH_VECTOR 0x02 +#define ASM_PROT_VECTOR 0x03 +#define ASM_ISI_VECTOR 0x04 +#define ASM_EXT_VECTOR 0x05 +#define ASM_ALIGN_VECTOR 0x06 +#define ASM_PROG_VECTOR 0x07 +#define ASM_FLOAT_VECTOR 0x08 +#define ASM_DEC_VECTOR 0x09 +#define ASM_SYS_VECTOR 0x0C +#define ASM_TRACE_VECTOR 0x0D + +#define ASM_60X_VEC_VECTOR 0x0A +#define ASM_60X_PERFMON_VECTOR 0x0F +#define ASM_60X_IMISS_VECTOR 0x10 +#define ASM_60X_DLMISS_VECTOR 0x11 +#define ASM_60X_DSMISS_VECTOR 0x12 +#define ASM_60X_ADDR_VECTOR 0x13 +#define ASM_60X_SYSMGMT_VECTOR 0x14 +#define ASM_60X_VEC_ASSIST_VECTOR 0x16 +#define ASM_60X_ITM_VECTOR 0x17 + +#define LAST_VALID_EXC 0x1F + +typedef enum +{ + PPC_601 = 0x1, + PPC_5XX = 0x2, + PPC_603 = 0x3, + PPC_604 = 0x4, + PPC_603e = 0x6, + PPC_603ev = 0x7, + PPC_750 = 0x8, + PPC_750_IBM = 0x7000, + PPC_604e = 0x9, + PPC_604r = 0xA, + PPC_7400 = 0xC, + PPC_405 = 0x2001, /* Xilinx Virtex-II Pro or -4 */ + PPC_405EX = 0x1291, /* + 405EXr */ + PPC_405GP = 0x4011, /* + 405CR */ + PPC_405GPr = 0x5091, + PPC_405EZ = 0x4151, + PPC_405EP = 0x5121, + PPC_440 = 0x7ff2, /* Xilinx Virtex-5*/ + PPC_7455 = 0x8001, /* Kate Feng */ + PPC_7457 = 0x8002, + PPC_620 = 0x16, + PPC_860 = 0x50, + PPC_821 = PPC_860, + PPC_823 = PPC_860, + PPC_8260 = 0x81, + PPC_8240 = PPC_8260, + PPC_8245 = 0x8081, + PPC_8540 = 0x8020, + PPC_e500v2 = 0x8021, + PPC_e6500 = 0x8040, + PPC_603le = 0x8082, /* 603le core, in MGT5100 and MPC5200 */ + PPC_e300c1 = 0x8083, /* e300c1 core, in MPC83xx*/ + PPC_e300c2 = 0x8084, /* e300c2 core */ + PPC_e300c3 = 0x8085, /* e300c3 core */ + PPC_e200z0 = 0x8170, + PPC_e200z1 = 0x8140, + PPC_e200z4 = 0x8150, + PPC_e200z6 = 0x8110, + PPC_e200z7 = 0x8160, + PPC_PSIM = 0xfffe, /* GDB PowerPC simulator -- fake version */ + PPC_UNKNOWN = 0xffff +} ppc_cpu_id; + +#define PPC_BOOKE_405 1 /* almost like booke but with some significant differences */ +#define PPC_BOOKE_STD 2 +#define PPC_BOOKE_E500 3 /* bookE with extensions */ + +typedef struct { + volatile bool type_1_complete; + volatile uint32_t msr; +} powerpc_stepping; + +static ppc_cpu_id ppc_cpu; +static int is_bookE; +static powerpc_stepping stepping_instr; + +#define xppc_read_spr(reg, val) \ + __asm__ __volatile__("mfspr %0,"#reg : "=r" (val)) +#define xppc_write_spr(reg, val) \ + __asm__ __volatile__("mtspr "#reg",%0" : : "r" (val)) +#define ppc_read_spr(reg, val) xppc_read_spr(reg, val) +#define ppc_write_spr(reg, val) xppc_write_spr(reg, val) + +static const char *ppc_get_cpu_type_name(ppc_cpu_id cpu) +{ + switch (cpu) { + case PPC_405: return "PPC405"; + case PPC_405GP: return "PPC405GP"; + case PPC_405EX: return "PPC405EX"; + case PPC_440: return "PPC440"; + case PPC_601: return "MPC601"; + case PPC_5XX: return "MPC5XX"; + case PPC_603: return "MPC603"; + case PPC_603ev: return "MPC603ev"; + case PPC_604: return "MPC604"; + case PPC_750: return "MPC750"; + case PPC_750_IBM: return "IBM PPC750"; + case PPC_7400: return "MPC7400"; + case PPC_7455: return "MPC7455"; + case PPC_7457: return "MPC7457"; + case PPC_603le: return "MPC603le"; + case PPC_604e: return "MPC604e"; + case PPC_604r: return "MPC604r"; + case PPC_620: return "MPC620"; + case PPC_860: return "MPC860"; + case PPC_8260: return "MPC8260"; + case PPC_8245: return "MPC8245"; + case PPC_8540: return "MPC8540"; + case PPC_PSIM: return "PSIM"; + case PPC_e200z0: return "e200z0"; + case PPC_e200z1: return "e200z1"; + case PPC_e200z4: return "e200z4"; + case PPC_e200z6: return "e200z6"; + case PPC_e200z7: return "e200z7"; + case PPC_e500v2: return "e500v2"; + case PPC_e6500: return "e6500"; + default: + break; + } + return "unknown"; +} + +static bool ppc_is_bookE(void) +{ + return is_bookE != 0; +} + +static bool ppc_is_bookE_405(void) +{ + return is_bookE == PPC_BOOKE_405; +} + +static int ppc_probe_cpu_type(void) +{ + /* + * cpu types listed here have the lowermost nibble as a version identifier + * we will tweak them to the standard version + */ + const uint32_t ppc_cpu_id_version_nibble[] = { + PPC_e200z0, + PPC_e200z1, + PPC_e200z4, + PPC_e200z6, + PPC_e200z7 + }; + #define NUM_CPU_ID_VERSION \ + (sizeof(ppc_cpu_id_version_nibble) / sizeof(ppc_cpu_id_version_nibble[0])) + + uint32_t pvr; + int i; + + ppc_read_spr(PPC_PVR, pvr); + pvr >>= 16; + + /* + * apply tweaks to ignore version + */ + for (i = 0; i < NUM_CPU_ID_VERSION; ++i) { + if ((pvr & 0xfff0) == (ppc_cpu_id_version_nibble[i] & 0xfff0)) { + pvr = ppc_cpu_id_version_nibble[i]; + break; + } + } + + ppc_cpu = (ppc_cpu_id) pvr; + + switch (pvr) { + case PPC_405: + case PPC_405GP: + case PPC_405EX: + case PPC_440: + case PPC_601: + case PPC_5XX: + case PPC_603: + case PPC_603ev: + case PPC_603le: + case PPC_604: + case PPC_604r: + case PPC_750: + case PPC_750_IBM: + case PPC_7400: + case PPC_7455: + case PPC_7457: + case PPC_604e: + case PPC_620: + case PPC_860: + case PPC_8260: + case PPC_8245: + case PPC_PSIM: + case PPC_8540: + case PPC_e200z0: + case PPC_e200z1: + case PPC_e200z4: + case PPC_e200z6: + case PPC_e200z7: + case PPC_e300c1: + case PPC_e300c2: + case PPC_e300c3: + case PPC_e500v2: + case PPC_e6500: + break; + default: + rtems_debugger_printf("rtems-db: powerpc: unknown CPU\n"); + return -1; + } + + switch (ppc_cpu) { + case PPC_405: + case PPC_405GP: + case PPC_405EX: + is_bookE = PPC_BOOKE_405; + break; + case PPC_440: + is_bookE = PPC_BOOKE_STD; + break; + case PPC_8540: + case PPC_e200z0: + case PPC_e200z1: + case PPC_e200z4: + case PPC_e200z6: + case PPC_e200z7: + case PPC_e500v2: + case PPC_e6500: + is_bookE = PPC_BOOKE_E500; + break; + default: + break; + } + + rtems_debugger_printf("rtems-db: powerpc: %s %s\n", + ppc_get_cpu_type_name(ppc_cpu), + ppc_is_bookE() ? "(book E)" : ""); + + return 0; +} + +static void ppc_set_dbsr(uint32_t dbsr) +{ + if (ppc_is_bookE()) { + if (ppc_is_bookE_405()) { + ppc_write_spr(0x3f0, dbsr); + } else { + ppc_write_spr(BOOKE_DBSR, dbsr); + } + } +} + +static void ppc_set_dbcr0(uint32_t dbcr) +{ + if (ppc_is_bookE()) { + if (ppc_is_bookE_405()) { + ppc_write_spr(0x3f2, dbcr); + } else { + ppc_write_spr(BOOKE_DBCR0, dbcr); + } + } +} + +static int ppc_debug_probe(rtems_debugger_target* target) +{ + if (ppc_probe_cpu_type() != 0) { + return -1; + } + ppc_set_dbsr(0xffffffffUL); + ppc_set_dbcr0(0); + return 0; +} + +static int ppc_code_writer(void* address, const void* data, size_t size) { + uint32_t current_level; + uint32_t addr; + uint32_t val; + addr = (uint32_t) (intptr_t) address; + val = *((uint32_t*) data); + target_printk("[] powerpc: code_ writer: %08x -> %p size=%zu\n", val, address, size); + if (size != 4) { + rtems_debugger_printf("rtems-db: powerpc: invalid code write size: size=%zu\n", size); + return -1; + } + /* + * Disable interrupts and MMU to work around write-protection. + * + * This hack is due to the lack of a proper MMU API for the older + * PPC hardware. Normally libdebugger makes the code section + * read/write so breakpoint insertion and removal is fast. The lack + * of a MMU API and the way some of the BSPs MMU is set up means it + * not easy to update the BSPs. + * + * The following is based on Till's `do_patch` implementation. + */ + current_level = ppc_interrupt_disable(); + asm volatile( + " mfmsr 0 \n" + " andc 7,0,%0 \n" + " mtmsr 7 \n" /* msr is exec. synchronizing; rval access complete */ + " isync \n" /* context sync.; DR off after this */ + " stw %2,0(%1) \n" + " dcbst 0,%1 \n" /* write out data cache line (addr) */ + " icbi 0,%1 \n" /* invalidate instr. cache line (addr) */ + " mtmsr 0 \n" /* msr is exec. synchr.; mem access completed */ + " sync \n" /* probably not necessary */ + " isync \n" /* context sync.; MMU on after this */ + /* add 'key' to input operands to make sure this asm is not + * moved around + */ + ::"r"(ppc_is_bookE() ? 0 : MSR_DR), "b"(addr), "r"(val), "r"(current_level) + :"r0","r7"); + ppc_interrupt_enable(current_level); + return 0; +} + +int +rtems_debugger_target_configure(rtems_debugger_target* target) +{ + if (is_bookE) { + ppc_reg_offsets = ppc_e500_reg_offsets; + } else { + ppc_reg_offsets = ppc_common_reg_offsets; + } + target->capabilities = (RTEMS_DEBUGGER_TARGET_CAP_SWBREAK); + target->reg_num = RTEMS_DEBUGGER_NUMREGS; + target->reg_offset = ppc_reg_offsets; + target->breakpoint = &breakpoint[0]; + target->breakpoint_size = sizeof(breakpoint); + target->code_writer = ppc_code_writer; + return ppc_debug_probe(target); +} + +static void powerpc_print_exception_frame(CPU_Exception_frame* frame) { + uintptr_t* gpr; + int r; + target_printk("[} frame = %08" PRIx32 " sig=%d (0x%" PRIx32 ")\n", + (uint32_t) frame, + rtems_debugger_target_exception_to_signal(frame), + frame->_EXC_number); +#ifndef __SPE__ + target_printk("[} SRR0 = %08" PRIx32 " SRR1 = %08" PRIx32 "\n", + frame->EXC_SRR0, frame->EXC_SRR1); +#else + target_printk("[} SRR0 = %08" PRIx32 " SRR1 = %08" PRIx32 \ + " SPEFSCR = %08" PRIx32 " ACC = %08" PRIx32 "\n", + frame->EXC_SRR0, frame->EXC_SRR1, + frame->EXC_SPEFSCR, frame->EXC_ACC); +#endif + target_printk("[} LR = %08" PRIx32 " CR = %08" PRIx32 \ + " XER = %08" PRIx32 " CTR = %08" PRIx32 "\n", + frame->EXC_LR, frame->EXC_CR, frame->EXC_XER, frame->EXC_CTR); + gpr = &frame->GPR0; + for (r= 0; r < 32; r += 4, gpr += 4) { + target_printk("[} R%-2d = %08" PRIx32 " R%-2d = %08" PRIx32 \ + " R%-2d = %08" PRIx32 " R%-2d = %08" PRIx32 "\n", + r, *gpr, r + 1, *(gpr + 1), r + 2, + *(gpr + 2), r + 3, *(gpr + 3)); + } +} + +/* + * NXP BOOK_EUM.PDF Programmeing Note, Chapter 9 Debug Facilities + * + * There are two classes of debug exception types: + * + * Type 1: exception before instruction + * Type 2: exception after instruction + * + * Almost all debug exceptions fall into the first category. That is, + * they all take the interrupt upon encountering an instruction having + * the exception without updating any architectural state (other than + * DBSR, CSRR0, CSRR1, MSR) for that instruction. + * + * The CSRR0 for this type of exception points to the instruction that + * encountered the exception. This includes IAC, DAC, branch taken, + * etc. + * + * The only exception which fall into the second category is the + * instruction complete debug exception. This exception is taken upon + * completing and updating one instruction and then pointing CSRR0 to + * the next instruction to execute. + */ +static bool +powerpc_stepping_exception(CPU_Exception_frame* frame) +{ + bool r = false; + frame->EXC_SRR1 &= ~MSR_SE; + switch (frame->_EXC_number) { + default: + stepping_instr.type_1_complete = false; + break; + case ASM_TRACE_VECTOR: + if (stepping_instr.type_1_complete) { + /* + * Type 2 exception after instruction + */ + stepping_instr.type_1_complete = false; + frame->EXC_SRR1 |= stepping_instr.msr; + } else { + stepping_instr.type_1_complete = true; + frame->EXC_SRR1 &= ~ppc_interrupt_get_disable_mask(); + frame->EXC_SRR1 |= MSR_SE; + r = true; + } + break; + case ASM_PROG_VECTOR: + /* + * Breakpoint. + */ + break; + } + return r; +} + +static void +powerpc_stepping_frame(CPU_Exception_frame* frame) +{ + if (ppc_is_bookE()) { + stepping_instr.type_1_complete = false; + } else { + stepping_instr.type_1_complete = true; + } + stepping_instr.msr = + frame->EXC_SRR1 & ppc_interrupt_get_disable_mask();; + frame->EXC_SRR1 &= ~ppc_interrupt_get_disable_mask(); + frame->EXC_SRR1 |= MSR_SE; +} + +static void +target_exception(BSP_Exception_frame* bsp_frame) +{ + CPU_Exception_frame* frame = bsp_frame; + + target_printk("[} powerpc target exc: entry\n"); + powerpc_print_exception_frame(frame); + + if (!powerpc_stepping_exception(bsp_frame)) { + switch (rtems_debugger_target_exception(frame)) { + case rtems_debugger_target_exc_consumed: + default: + break; + case rtems_debugger_target_exc_step: + powerpc_stepping_frame(frame); + break; + case rtems_debugger_target_exc_cascade: + if (orig_currentExcHandler != NULL) { + orig_currentExcHandler(bsp_frame); + } + break; + } + } +} + +static bool +rtems_debugger_is_int_reg(size_t reg) +{ + const size_t size = ppc_reg_offsets[reg + 1] - ppc_reg_offsets[reg]; + return size == RTEMS_DEBUGGER_NUMREGBYTES; +} + +static void +rtems_debugger_set_int_reg(rtems_debugger_thread* thread, + const uintptr_t reg, + const uint32_t value) +{ + const size_t offset = ppc_reg_offsets[reg]; + /* + * Use memcpy to avoid alignment issues. + */ + memcpy(&thread->registers[offset], &value, sizeof(uintptr_t)); +} + +static const uintptr_t +rtems_debugger_get_int_reg(rtems_debugger_thread* thread, const size_t reg) +{ + const size_t offset = ppc_reg_offsets[reg]; + uintptr_t value; + memcpy(&value, &thread->registers[offset], sizeof(uintptr_t)); + return value; +} + +static void rtems_debugger_acquire_exc(void) { + if (orig_currentExcHandler == NULL) { + orig_currentExcHandler = globalExceptHdl; + globalExceptHdl = target_exception; + } +} + +static void rtems_debugger_release_exc(void) { + if (orig_currentExcHandler != NULL) { + globalExceptHdl = orig_currentExcHandler; + } +} + +int +rtems_debugger_target_enable(void) +{ + target_printk("]] rtems-db: powerpc: %s\n", __func__); + rtems_interrupt_lock_context lock_context; + rtems_interrupt_lock_acquire(&target_lock, &lock_context); + rtems_debugger_acquire_exc(); + rtems_interrupt_lock_release(&target_lock, &lock_context); + return 0; +} + +int +rtems_debugger_target_disable(void) +{ + target_printk("]] rtems-db: powerpc: %s\n", __func__); + rtems_interrupt_lock_context lock_context; + rtems_interrupt_lock_acquire(&target_lock, &lock_context); + ppc_set_dbsr(0xffffffffUL); + ppc_set_dbcr0(0); + rtems_debugger_release_exc(); + rtems_interrupt_lock_release(&target_lock, &lock_context); + return 0; +} + +int +rtems_debugger_target_read_regs(rtems_debugger_thread* thread) +{ + target_printk("]] rtems-db: powerpc: %s\n", __func__); + if (!rtems_debugger_thread_flag(thread, + RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID)) { + static const uintptr_t good_address = (uintptr_t) &good_address; + size_t i; + + for (i = 0; i < rtems_debugger_target_reg_num(); ++i) { + if (rtems_debugger_is_int_reg(i)) { + rtems_debugger_set_int_reg(thread, i, (uintptr_t) &good_address); + } + } + + if (thread->frame) { + CPU_Exception_frame* frame = thread->frame; + rtems_debugger_set_int_reg(thread, REG_R0, frame->GPR0); + rtems_debugger_set_int_reg(thread, REG_R1, frame->GPR1); + rtems_debugger_set_int_reg(thread, REG_R2, frame->GPR2); + rtems_debugger_set_int_reg(thread, REG_R3, frame->GPR3); + rtems_debugger_set_int_reg(thread, REG_R4, frame->GPR4); + rtems_debugger_set_int_reg(thread, REG_R5, frame->GPR5); + rtems_debugger_set_int_reg(thread, REG_R6, frame->GPR6); + rtems_debugger_set_int_reg(thread, REG_R7, frame->GPR7); + rtems_debugger_set_int_reg(thread, REG_R8, frame->GPR8); + rtems_debugger_set_int_reg(thread, REG_R9, frame->GPR9); + rtems_debugger_set_int_reg(thread, REG_R10, frame->GPR10); + rtems_debugger_set_int_reg(thread, REG_R11, frame->GPR11); + rtems_debugger_set_int_reg(thread, REG_R12, frame->GPR12); + rtems_debugger_set_int_reg(thread, REG_R13, frame->GPR13); + rtems_debugger_set_int_reg(thread, REG_R14, frame->GPR14); + rtems_debugger_set_int_reg(thread, REG_R15, frame->GPR15); + rtems_debugger_set_int_reg(thread, REG_R16, frame->GPR16); + rtems_debugger_set_int_reg(thread, REG_R17, frame->GPR17); + rtems_debugger_set_int_reg(thread, REG_R18, frame->GPR18); + rtems_debugger_set_int_reg(thread, REG_R19, frame->GPR19); + rtems_debugger_set_int_reg(thread, REG_R20, frame->GPR20); + rtems_debugger_set_int_reg(thread, REG_R21, frame->GPR21); + rtems_debugger_set_int_reg(thread, REG_R22, frame->GPR22); + rtems_debugger_set_int_reg(thread, REG_R23, frame->GPR23); + rtems_debugger_set_int_reg(thread, REG_R24, frame->GPR24); + rtems_debugger_set_int_reg(thread, REG_R25, frame->GPR25); + rtems_debugger_set_int_reg(thread, REG_R26, frame->GPR26); + rtems_debugger_set_int_reg(thread, REG_R27, frame->GPR27); + rtems_debugger_set_int_reg(thread, REG_R28, frame->GPR28); + rtems_debugger_set_int_reg(thread, REG_R29, frame->GPR29); + rtems_debugger_set_int_reg(thread, REG_R30, frame->GPR30); + rtems_debugger_set_int_reg(thread, REG_R31, frame->GPR31); + + rtems_debugger_set_int_reg(thread, REG_PC, frame->EXC_SRR0); + rtems_debugger_set_int_reg(thread, REG_MSR, frame->EXC_SRR1); + rtems_debugger_set_int_reg(thread, REG_CND, frame->EXC_CR); + rtems_debugger_set_int_reg(thread, REG_LR, frame->EXC_LR); + rtems_debugger_set_int_reg(thread, REG_CNT, frame->EXC_CTR); + rtems_debugger_set_int_reg(thread, REG_XER, frame->EXC_XER); + + /* + * Get the signal from the frame. + */ + thread->signal = rtems_debugger_target_exception_to_signal(frame); + } + else { + ppc_context* thread_ctx = ppc_get_context(&thread->tcb->Registers); + rtems_debugger_set_int_reg(thread, REG_R1, thread_ctx->gpr1); + rtems_debugger_set_int_reg(thread, REG_R14, thread_ctx->gpr14); + rtems_debugger_set_int_reg(thread, REG_R15, thread_ctx->gpr15); + rtems_debugger_set_int_reg(thread, REG_R16, thread_ctx->gpr16); + rtems_debugger_set_int_reg(thread, REG_R17, thread_ctx->gpr17); + rtems_debugger_set_int_reg(thread, REG_R18, thread_ctx->gpr18); + rtems_debugger_set_int_reg(thread, REG_R19, thread_ctx->gpr19); + rtems_debugger_set_int_reg(thread, REG_R20, thread_ctx->gpr20); + rtems_debugger_set_int_reg(thread, REG_R21, thread_ctx->gpr21); + rtems_debugger_set_int_reg(thread, REG_R22, thread_ctx->gpr22); + rtems_debugger_set_int_reg(thread, REG_R23, thread_ctx->gpr23); + rtems_debugger_set_int_reg(thread, REG_R24, thread_ctx->gpr24); + rtems_debugger_set_int_reg(thread, REG_R25, thread_ctx->gpr25); + rtems_debugger_set_int_reg(thread, REG_R26, thread_ctx->gpr26); + rtems_debugger_set_int_reg(thread, REG_R27, thread_ctx->gpr27); + rtems_debugger_set_int_reg(thread, REG_R28, thread_ctx->gpr28); + rtems_debugger_set_int_reg(thread, REG_R29, thread_ctx->gpr29); + rtems_debugger_set_int_reg(thread, REG_R30, thread_ctx->gpr30); + rtems_debugger_set_int_reg(thread, REG_R31, thread_ctx->gpr31); + + rtems_debugger_set_int_reg(thread, REG_PC, thread_ctx->lr); + rtems_debugger_set_int_reg(thread, REG_MSR, thread_ctx->msr); + rtems_debugger_set_int_reg(thread, REG_CND, thread_ctx->cr); + rtems_debugger_set_int_reg(thread, REG_LR, thread_ctx->lr); + rtems_debugger_set_int_reg(thread, REG_CNT, 0); + rtems_debugger_set_int_reg(thread, REG_XER, 0); + rtems_debugger_set_int_reg(thread, REG_SPEFSCR, 0); + + /* + * Blocked threads have no signal. + */ + thread->signal = 0; + } + + thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_VALID; + thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY; + } + + return 0; +} + +int +rtems_debugger_target_write_regs(rtems_debugger_thread* thread) +{ + target_printk("]] rtems-db: powerpc: %s\n", __func__); + if (rtems_debugger_thread_flag(thread, + RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY)) { + /* + * Only write to debugger controlled threads. Do not touch the registers + * for threads blocked in the context switcher. + */ + if (rtems_debugger_thread_flag(thread, + RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION)) { + CPU_Exception_frame* frame = thread->frame; + frame->GPR0 = rtems_debugger_get_int_reg(thread, REG_R0); + frame->GPR1 = rtems_debugger_get_int_reg(thread, REG_R1); + frame->GPR2 = rtems_debugger_get_int_reg(thread, REG_R2); + frame->GPR3 = rtems_debugger_get_int_reg(thread, REG_R3); + frame->GPR4 = rtems_debugger_get_int_reg(thread, REG_R4); + frame->GPR5 = rtems_debugger_get_int_reg(thread, REG_R5); + frame->GPR6 = rtems_debugger_get_int_reg(thread, REG_R6); + frame->GPR7 = rtems_debugger_get_int_reg(thread, REG_R7); + frame->GPR8 = rtems_debugger_get_int_reg(thread, REG_R8); + frame->GPR9 = rtems_debugger_get_int_reg(thread, REG_R9); + frame->GPR10 = rtems_debugger_get_int_reg(thread, REG_R10); + frame->GPR11 = rtems_debugger_get_int_reg(thread, REG_R11); + frame->GPR12 = rtems_debugger_get_int_reg(thread, REG_R12); + frame->GPR13 = rtems_debugger_get_int_reg(thread, REG_R13); + frame->GPR14 = rtems_debugger_get_int_reg(thread, REG_R14); + frame->GPR15 = rtems_debugger_get_int_reg(thread, REG_R15); + frame->GPR16 = rtems_debugger_get_int_reg(thread, REG_R16); + frame->GPR17 = rtems_debugger_get_int_reg(thread, REG_R17); + frame->GPR18 = rtems_debugger_get_int_reg(thread, REG_R18); + frame->GPR19 = rtems_debugger_get_int_reg(thread, REG_R19); + frame->GPR20 = rtems_debugger_get_int_reg(thread, REG_R20); + frame->GPR21 = rtems_debugger_get_int_reg(thread, REG_R21); + frame->GPR22 = rtems_debugger_get_int_reg(thread, REG_R22); + frame->GPR23 = rtems_debugger_get_int_reg(thread, REG_R23); + frame->GPR24 = rtems_debugger_get_int_reg(thread, REG_R24); + frame->GPR25 = rtems_debugger_get_int_reg(thread, REG_R25); + frame->GPR26 = rtems_debugger_get_int_reg(thread, REG_R26); + frame->GPR27 = rtems_debugger_get_int_reg(thread, REG_R27); + frame->GPR28 = rtems_debugger_get_int_reg(thread, REG_R28); + frame->GPR29 = rtems_debugger_get_int_reg(thread, REG_R29); + frame->GPR30 = rtems_debugger_get_int_reg(thread, REG_R30); + frame->GPR31 = rtems_debugger_get_int_reg(thread, REG_R31); + + frame->EXC_SRR0 = rtems_debugger_get_int_reg(thread, REG_PC); + frame->EXC_SRR1 = rtems_debugger_get_int_reg(thread, REG_MSR); + frame->EXC_CR = rtems_debugger_get_int_reg(thread, REG_CND); + frame->EXC_LR = rtems_debugger_get_int_reg(thread, REG_LR); + frame->EXC_CTR = rtems_debugger_get_int_reg(thread, REG_CNT); + frame->EXC_XER = rtems_debugger_get_int_reg(thread, REG_XER); + } + thread->flags &= ~RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY; + } + return 0; +} + +uintptr_t +rtems_debugger_target_reg_pc(rtems_debugger_thread* thread) +{ + int r; + r = rtems_debugger_target_read_regs(thread); + if (r >= 0) { + return rtems_debugger_get_int_reg(thread, REG_PC); + } + return 0; +} + +uintptr_t +rtems_debugger_target_frame_pc(CPU_Exception_frame* frame) +{ + return (uintptr_t) frame->EXC_SRR0; +} + +uintptr_t +rtems_debugger_target_reg_sp(rtems_debugger_thread* thread) +{ + int r; + r = rtems_debugger_target_read_regs(thread); + if (r >= 0) { + return rtems_debugger_get_int_reg(thread, REG_R1); + } + return 0; +} + +uintptr_t +rtems_debugger_target_tcb_sp(rtems_debugger_thread* thread) +{ + ppc_context* thread_ctx = ppc_get_context(&thread->tcb->Registers); + return (DB_UINT) thread_ctx->gpr1; +} + +int +rtems_debugger_target_thread_stepping(rtems_debugger_thread* thread) +{ + target_printk("]] rtems-db: powerpc: %s\n", __func__); + if (rtems_debugger_thread_flag(thread, + RTEMS_DEBUGGER_THREAD_FLAG_STEP_INSTR)) { + CPU_Exception_frame* frame = thread->frame; + /* + * There maybe no frame, ie connect and then enter `si` + */ + if (frame != NULL) { + /* + * Single step instructions with interrupts masked to avoid + * stepping into an interrupt handler. + */ + if ((frame->EXC_SRR1 & MSR_EE) == 0) { + thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_INTS_DISABLED; + } + powerpc_stepping_frame(frame); + } + } + return 0; +} + +int +rtems_debugger_target_exception_to_signal(CPU_Exception_frame* frame) +{ + int sig = RTEMS_DEBUGGER_SIGNAL_HUP; + switch (frame->_EXC_number) { + case ASM_MACH_VECTOR: + sig = RTEMS_DEBUGGER_SIGNAL_BUS; + break; + case ASM_PROT_VECTOR: + case ASM_ISI_VECTOR: + case ASM_ALIGN_VECTOR: + case ASM_60X_IMISS_VECTOR: + case ASM_60X_DLMISS_VECTOR: + case ASM_60X_DSMISS_VECTOR: + sig = RTEMS_DEBUGGER_SIGNAL_SEGV; + break; + case ASM_PROG_VECTOR: + sig = RTEMS_DEBUGGER_SIGNAL_TRAP; + break; + case ASM_FLOAT_VECTOR: + sig = RTEMS_DEBUGGER_SIGNAL_FPE; + break; + case ASM_DEC_VECTOR: + sig = RTEMS_DEBUGGER_SIGNAL_ALRM; + break; + case ASM_SYS_VECTOR: + case ASM_TRACE_VECTOR: + sig = RTEMS_DEBUGGER_SIGNAL_TRAP; + break; + default: + break; + } + return sig; +} + +void +rtems_debugger_target_exception_print(CPU_Exception_frame* frame) +{ + uintptr_t* gpr = &frame->GPR0; + int r = 0; +#ifndef __SPE__ + rtems_debugger_printf("SRR0 = %08" PRIx32 " SRR1 = %08" PRIx32 "\n", + frame->EXC_SRR0, frame->EXC_SRR1); +#else + rtems_debugger_printf("SRR0 = %08" PRIx32 " SRR1 = %08" PRIx32 \ + " SPEFSCR = %08" PRIx32 " ACC = %08" PRIx32 "\n", + frame->EXC_SRR0, frame->EXC_SRR1, + frame->EXC_SPEFSCR, frame->EXC_ACC); +#endif + rtems_debugger_printf("LR = %08" PRIx32 " CR = %08" PRIx32 \ + " XER = %08" PRIx32 " CTR = %08" PRIx32 "\n", + frame->EXC_LR, frame->EXC_CR, + frame->EXC_XER, frame->EXC_CTR); + gpr = &frame->GPR0; + for (r= 0; r < 32; r += 4, gpr += 4) { + rtems_debugger_printf("R%-2d = %08" PRIx32 " R%-2d = %08" PRIx32 \ + " R%-2d = %08" PRIx32 " R%-2d = %08" PRIx32 "\n", + r, *gpr, r + 1, *(gpr + 1), r + 2, + *(gpr + 2), r + 3, *(gpr + 3)); + } +} + +int +rtems_debugger_target_hwbreak_insert(void) +{ + target_printk("]] rtems-db: powerpc: %s\n", __func__); + /* + * Do nothing, load on exit of the exception handler. + */ + return 0; +} + +int +rtems_debugger_target_hwbreak_remove(void) +{ + target_printk("]] rtems-db: powerpc: %s\n", __func__); + return 0; +} + +int +rtems_debugger_target_hwbreak_control(rtems_debugger_target_watchpoint wp, + bool insert, + uintptr_t addr, + DB_UINT kind) +{ + target_printk("]] rtems-db: powerpc: %s\n", __func__); + /* + * To do. + */ + return 0; +} + +int +rtems_debugger_target_cache_sync(rtems_debugger_target_swbreak* swbreak) +{ + /* + * Flush the data cache and invalidate the instruction cache. + */ + rtems_cache_flush_multiple_data_lines( + swbreak->address, + sizeof( breakpoint ) + ); + rtems_cache_instruction_sync_after_code_change( + swbreak->address, + sizeof( breakpoint ) + ); + return 0; +} diff --git a/cpukit/libdebugger/rtems-debugger-server.c b/cpukit/libdebugger/rtems-debugger-server.c index 51d165c58f..166a7bbf24 100644 --- a/cpukit/libdebugger/rtems-debugger-server.c +++ b/cpukit/libdebugger/rtems-debugger-server.c @@ -1797,7 +1797,16 @@ rtems_debugger_session(void) if (rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_RESET)) { rtems_debugger_printf("rtems-db: shutdown\n"); + /* + * Wait a moment to let any disconnection protocol a transport has + * complete. The legacy stack needs this to close the connection + * to GDB and clean up. + */ sleep(2); + /* + * No special exit code, the user will asked GDB to kill the + * target + */ rtems_fatal_error_occurred(1122); } diff --git a/cpukit/libdebugger/rtems-debugger-target.h b/cpukit/libdebugger/rtems-debugger-target.h index 47c5799bb1..55289fb1eb 100644 --- a/cpukit/libdebugger/rtems-debugger-target.h +++ b/cpukit/libdebugger/rtems-debugger-target.h @@ -92,9 +92,11 @@ typedef struct rtems_debugger_target_swbreak { } rtems_debugger_target_swbreak; /** - * Target memory update handler. If set this is called to modify - * the executable memory. It may not be possible to make it - * read/write. + * Target executable memory update handler. If set the handler is + * called to modify the executable memory. The target's executable + * memory may not be directly writable. The handler is responsible for + * making sure the code update is ready to be executed, for example + * caches are flushed. */ typedef int (*rtems_debugger_target_code_writer)(void* address, const void* data, diff --git a/spec/build/cpukit/libdebugger.yml b/spec/build/cpukit/libdebugger.yml index bc9db7b8d6..781d0042e1 100644 --- a/spec/build/cpukit/libdebugger.yml +++ b/spec/build/cpukit/libdebugger.yml @@ -20,6 +20,8 @@ links: uid: objdbgi386 - role: build-dependency uid: objdbgmicroblaze +- role: build-dependency + uid: objdbpowerpc source: - cpukit/libdebugger/rtems-debugger-block.c - cpukit/libdebugger/rtems-debugger-bsp.c diff --git a/spec/build/cpukit/objdbpowerpc.yml b/spec/build/cpukit/objdbpowerpc.yml new file mode 100644 index 0000000000..cf7e3d94ca --- /dev/null +++ b/spec/build/cpukit/objdbpowerpc.yml @@ -0,0 +1,15 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: objects +cflags: [] +copyrights: +- Copyright (C) 2023 Contemporary Software (CS) +cppflags: [] +cxxflags: [] +enabled-by: +- powerpc +includes: [] +install: [] +links: [] +source: +- cpukit/libdebugger/rtems-debugger-powerpc.c +type: build diff --git a/spec/build/cpukit/optlibdebugger.yml b/spec/build/cpukit/optlibdebugger.yml index 5ff67d6bd8..19ce1a8dd4 100644 --- a/spec/build/cpukit/optlibdebugger.yml +++ b/spec/build/cpukit/optlibdebugger.yml @@ -20,6 +20,12 @@ enabled-by: - not: bsps/arm/stm32f4 - i386 - microblaze +- and: + - powerpc + - not: bsps/powerpc/mpc55xxevb + - not: bsps/powerpc/qoriq + - not: bsps/powerpc/ss555 + - not: bsps/powerpc/t32mppc links: [] name: BUILD_LIBDEBUGGER type: build