123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- /*
- * CORTEXM GDB support
- * arch-specific portion of GDB stub
- *
- * File : cortexm_stub.c
- * This file is part of RT-Thread RTOS
- * COPYRIGHT (C) 2006, RT-Thread Develop Team
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rt-thread.org/license/LICENSE
- *
- * Change Logs:
- * Date Author Notes
- * 2014-07-04 Wzyy2 first version
- */
- #include <rtthread.h>
- #include <rthw.h>
- #include <gdb_stub.h>
- static Gdb_SavedRegisters *regs;
- unsigned long single_step_basepri = 0;
- void gdb_remove_all_hw_break();
- void gdb_enable_hw_debug();
- void gdb_disable_hw_debug();
- int gdb_set_hw_break(unsigned long, int, enum gdb_bptype);
- int gdb_remove_hw_break(unsigned long, int, enum gdb_bptype);
- /*struct gdb_arch - Describe architecture specific values.*/
- struct gdb_arch arch_gdb_ops = {
- /* Breakpoint instruction: */
- .gdb_bpt_instr = {0xfe, 0xde, 0xff, 0xe7}, //Little-Endian
- .flags = RT_GDB_HAVE_HWBP,
- .set_hw_breakpoint = gdb_set_hw_break,
- .remove_hw_breakpoint = gdb_remove_hw_break,
- .remove_all_hw_break = gdb_remove_all_hw_break
- };
- static struct hw_breakpoint {
- int enabled;
- unsigned long addr;
- } breakinfo[HBP_NUM];
- static struct hw_watchpoint {
- int enabled;
- unsigned long addr;
- int len;
- enum gdb_bptype type;
- } watchinfo[HWP_NUM];
- //The following table defines the memory areas that GDB is allow to touch
- static const struct {
- unsigned long start;
- unsigned long end;
- } data_access[] =
- {
- { 0x20000000, 0x40000000-1}, // On-chip ram
- { 0x60000000, 0xa0000000-1}, // External ram
- { 0x00000000, 0x20000000-1}, // On-chip flash
- { 0x60000000, 0xa0000000-1}, // External flash
- { 0xE0000000, 0x00000000-1}, // cortex-M peripheral
- { 0x40000000, 0x60000000-1}, // mcu peripheral
- };
- int gdb_permit_data_access(unsigned long addr, unsigned long count)
- {
- unsigned char i;
- for (i = 0; i < sizeof(data_access)/sizeof(data_access[0]); i++) {
- if ((addr >= data_access[i].start) && (addr + count) <= data_access[i].end) {
- return 0;
- }
- }
- return -1;
- }
- /*we need to block all pending interrupts by swtting basepri
- * before doing the steo
- */
- void gdb_single_step()
- {
- volatile unsigned long *base;
- //mask all interrupts
- single_step_basepri = regs->basepri;
- regs->basepri = GDB_CORTEXM_PRIORITY_MAX;
- //When MON_EN = 1, this steps the core
- base = (unsigned long*)(GDB_DEBUG_REG_BASE + GDB_DEBUG_REG_DEMCR);
- *base |= GDB_DEBUG_REG_DEMCR_MON_STEP;
- /* Clear any bits set in DFSR*/
- base = (unsigned long*)(GDB_NVIC_REG_BASE + GDB_NVIC_REG_DFSR);
- *base = 0xffffffff;
- }
- void gdb_clear_single_step()
- {
- volatile unsigned long *base;
- regs->basepri = single_step_basepri;
- /*clear single step*/
- base = (unsigned long*)(GDB_DEBUG_REG_BASE + GDB_DEBUG_REG_DEMCR);
- *base &= ~GDB_DEBUG_REG_DEMCR_MON_STEP;
- // Clear any bits set in DFSR
- base = (unsigned long*)(GDB_NVIC_REG_BASE + GDB_NVIC_REG_DFSR);
- *base = 0xffffffff;
- }
- /**
- * gdb_breakpoint - generate a breadk
- * It is used to sync up with a debugger and stop progarm
- */
- void gdb_breakpoint()
- {
- volatile unsigned long *base;
- // Enable the FPB-FLASH PATCH BREAKPOINT
- base = (unsigned long*)(GDB_FPB_REG_BASE + GDB_FPB_REG_CTRL);
- *base |= GDB_FPB_REG_CTRL_KEY | GDB_FPB_REG_CTRL_ENABLE ;
- base = (unsigned long*)(GDB_DEBUG_REG_BASE + GDB_DEBUG_REG_DEMCR);
- /*
- * Enable the debug monitor. When enabled, the System handler priority
- * register controls its priority level.
- * If disabled, then all debug events go
- * to Hard fault
- */
- *base |= GDB_DEBUG_REG_DEMCR_MON_EN;
- // Enable DWT
- *base |= GDB_DEBUG_REG_DEMCR_TRCENA ;
- //Fall into debug monitor
- *base |= GDB_DEBUG_REG_DEMCR_MON_PEND;
- }
- void gdb_set_register(void *hw_regs)
- {
- regs = hw_regs;
- }
- void gdb_get_register(unsigned long *gdb_regs)
- {
- int regno;
- /* Initialize all to zero. */
- for (regno = 0; regno < GDB_MAX_REGS; regno++)
- gdb_regs[regno] = 0;
- gdb_regs[GDB_R0] = regs->r0;
- gdb_regs[GDB_R1] = regs->r1;
- gdb_regs[GDB_R2] = regs->r2;
- gdb_regs[GDB_R3] = regs->r3;
- gdb_regs[GDB_R4] = regs->r4;
- gdb_regs[GDB_R5] = regs->r5;
- gdb_regs[GDB_R6] = regs->r6;
- gdb_regs[GDB_R7] = regs->r7;
- gdb_regs[GDB_R8] = regs->r8;
- gdb_regs[GDB_R9] = regs->r9;
- gdb_regs[GDB_R10] = regs->r10;
- gdb_regs[GDB_FP] = regs->r11;
- gdb_regs[GDB_IP] = regs->r12;
- gdb_regs[GDB_SPT] = regs->sp;
- gdb_regs[GDB_LR] = regs->lr;
- gdb_regs[GDB_PC] = regs->pc;
- gdb_regs[GDB_CPSR] = regs->psr;
- };
- void gdb_put_register(unsigned long *gdb_regs)
- {
- regs->r0 = gdb_regs[GDB_R0];
- regs->r1 = gdb_regs[GDB_R1];
- regs->r2 = gdb_regs[GDB_R2];
- regs->r3 = gdb_regs[GDB_R3];
- regs->r4 = gdb_regs[GDB_R4];
- regs->r5 = gdb_regs[GDB_R5];
- regs->r6 = gdb_regs[GDB_R6];
- regs->r7 = gdb_regs[GDB_R7];
- regs->r8 = gdb_regs[GDB_R8];
- regs->r9 = gdb_regs[GDB_R9];
- regs->r10 = gdb_regs[GDB_R10];
- regs->r11 = gdb_regs[GDB_FP];
- regs->r12 = gdb_regs[GDB_IP];
- regs->sp = gdb_regs[GDB_SPT];
- regs->lr = gdb_regs[GDB_LR];
- regs->pc = gdb_regs[GDB_PC];
- regs->psr = gdb_regs[GDB_CPSR];
- }
- /* It will be called during process_packet */
- int gdb_arch_handle_exception(char *remcom_in_buffer,
- char *remcom_out_buffer)
- {
- unsigned long addr;
- char *ptr;
- static int step = 0;
- if (step){
- gdb_clear_single_step();
- step = 0;
- }
- switch (remcom_in_buffer[0]) {
- case 'D':
- case 'k':
- case 'c':
- /*
- * If this was a compiled breakpoint, we need to move
- * to the next instruction or we will breakpoint
- * over and over again
- */
- ptr = &remcom_in_buffer[1];
- if (gdb_hex2long(&ptr, &addr))
- regs->pc = addr;
- return 0;
- case 's':
- ptr = &remcom_in_buffer[1];
- if (gdb_hex2long(&ptr, &addr))
- regs->pc = addr;
- gdb_single_step();
- step = 1;
- return 0;
- }
- return -1;
- }
- int gdb_set_hw_break(unsigned long addr, int len, enum gdb_bptype bptype)
- {
- int i;
- if (bptype == BP_HARDWARE_BREAKPOINT) {
- for (i = 0; i < HBP_NUM; i++)
- if (!breakinfo[i].enabled)
- break;
- if (i == HBP_NUM)
- return -1;
- breakinfo[i].addr = addr;
- breakinfo[i].enabled = 1;
- }
- else if (bptype == BP_WRITE_WATCHPOINT) {
- for (i = 0; i < HWP_NUM; i++)
- if (!watchinfo[i].enabled)
- break;
- if (i == HWP_NUM)
- return -1;
- watchinfo[i].addr = addr;
- watchinfo[i].len = len;
- watchinfo[i].type = BP_WRITE_WATCHPOINT;
- watchinfo[i].enabled = 1;
- }
- else if (bptype == BP_READ_WATCHPOINT) {
- for (i = 0; i < HWP_NUM; i++)
- if (!watchinfo[i].enabled)
- break;
- if (i == HWP_NUM)
- return -1;
- watchinfo[i].addr = addr;
- watchinfo[i].len = len;
- watchinfo[i].type = BP_READ_WATCHPOINT;
- watchinfo[i].enabled = 1;
- }
- else if (bptype == BP_ACCESS_WATCHPOINT) {
- for (i = 0; i < HWP_NUM; i++)
- if (!watchinfo[i].enabled)
- break;
- if (i == HWP_NUM)
- return -1;
- watchinfo[i].addr = addr;
- watchinfo[i].len = len;
- watchinfo[i].type = BP_ACCESS_WATCHPOINT;
- watchinfo[i].enabled = 1;
- }
- return 0;
- }
- int gdb_remove_hw_break(unsigned long addr, int len, enum gdb_bptype bptype)
- {
- int i;
- if (bptype == BP_HARDWARE_BREAKPOINT) {
- for (i = 0; i < HBP_NUM; i++)
- if (breakinfo[i].addr == addr && breakinfo[i].enabled)
- break;
- if (i == HBP_NUM)
- return -1;
- breakinfo[i].enabled = 0;
- }
- else if (bptype == BP_WRITE_WATCHPOINT) {
- for (i = 0; i < HWP_NUM; i++)
- if (watchinfo[i].addr == addr && watchinfo[i].enabled && watchinfo[i].type == bptype)
- break;
- if (i == HWP_NUM)
- return -1;
- watchinfo[i].enabled = 0;
- }
- else if (bptype == BP_READ_WATCHPOINT) {
- for (i = 0; i < HWP_NUM; i++)
- if (watchinfo[i].addr == addr && watchinfo[i].enabled && watchinfo[i].type == bptype)
- break;
- if (i == HWP_NUM)
- return -1;
- watchinfo[i].enabled = 0;
- }
- else if (bptype == BP_ACCESS_WATCHPOINT) {
- for (i = 0; i < HWP_NUM; i++)
- if (watchinfo[i].addr == addr && watchinfo[i].enabled && watchinfo[i].type == bptype)
- break;
- if (i == HWP_NUM)
- return -1;
- watchinfo[i].enabled = 0;
- }
- return 0;
- }
- void gdb_remove_all_hw_break()
- {
- int i;
- volatile unsigned long *base;
- // Disable hardware break
- for (i = 0; i < HBP_NUM; i++) {
- if (!breakinfo[i].enabled)
- break;
- base = (unsigned long*)(GDB_FPB_REG_BASE + GDB_FPB_REG_COMP + i * 4);
- *base &= ~GDB_FPB_REG_COMP_ENABLE ;
- }
-
- // Disable watchpoint
- for (i = 0; i < HWP_NUM; i++) {
- if (!watchinfo[i].enabled)
- break;
- base = (unsigned long*)(GDB_DWT_REG_BASE + GDB_DWT_REG_FUNCTION + i * 12);
- *base &= ~GDB_DWT_REG_FUNCTION_FUC ;
- }
- }
- void gdb_arch_late()
- {
- gdb_remove_all_hw_break();
- }
- void gdb_arch_exit()
- {
- volatile unsigned long *base;
- char num = 1;
- int i;
- // Install the hardware break
- for (i = 0; i < HBP_NUM; i++) {
- if (breakinfo[i].enabled) {
- base = (unsigned long*)(GDB_FPB_REG_BASE + GDB_FPB_REG_COMP + i * 4);
-
- *base = GDB_FPB_REG_COMP_ADDR & ((unsigned long)(breakinfo[i].addr));
- if (breakinfo[i].addr & 2)
- *base |= (1UL << 31); //set BKPT on upper halfword
- else
- *base |= (1UL << 30); //set BKPT on lower halfword,
- *base |= GDB_FPB_REG_COMP_ENABLE ;
- }
- }
- // Install the watchpoint
- for (i = 0; i < HWP_NUM; i++) {
- if (watchinfo[i].enabled) {
- base = (unsigned long*)(GDB_DWT_REG_BASE + GDB_DWT_REG_COMP + i * 12);
- *base = watchinfo[i].addr;
- base = (unsigned long*)(GDB_DWT_REG_BASE + GDB_DWT_REG_MASK + i * 12);
- while (watchinfo[i].len >> num) {
- num++;
- }
- *base = num - 1; //DWT matching is performed as:(ADDR & (~0 << MASK)) == COMP
- base = (unsigned long*)(GDB_DWT_REG_BASE + GDB_DWT_REG_FUNCTION + i * 12);
- if (watchinfo[i].type == BP_WRITE_WATCHPOINT)
- *base = (*base & ~GDB_DWT_REG_FUNCTION_FUC) + 0x05;
- else if (watchinfo[i].type == BP_READ_WATCHPOINT)
- *base = (*base & ~GDB_DWT_REG_FUNCTION_FUC) + 0x06;
- else if (watchinfo[i].type == BP_ACCESS_WATCHPOINT)
- *base = (*base & ~GDB_DWT_REG_FUNCTION_FUC) + 0x07;
- }
- }
- }
|