1 /* 2 * Microblaze KGDB support 3 * 4 * This file is subject to the terms and conditions of the GNU General Public 5 * License. See the file "COPYING" in the main directory of this archive 6 * for more details. 7 */ 8 9 #include <linux/kgdb.h> 10 #include <linux/kdebug.h> 11 #include <linux/irq.h> 12 #include <linux/io.h> 13 #include <asm/cacheflush.h> 14 #include <asm/asm-offsets.h> 15 #include <asm/kgdb.h> 16 #include <asm/pvr.h> 17 18 #define GDB_REG 0 19 #define GDB_PC 32 20 #define GDB_MSR 33 21 #define GDB_EAR 34 22 #define GDB_ESR 35 23 #define GDB_FSR 36 24 #define GDB_BTR 37 25 #define GDB_PVR 38 26 #define GDB_REDR 50 27 #define GDB_RPID 51 28 #define GDB_RZPR 52 29 #define GDB_RTLBX 53 30 #define GDB_RTLBSX 54 /* mfs can't read it */ 31 #define GDB_RTLBLO 55 32 #define GDB_RTLBHI 56 33 34 /* keep pvr separately because it is unchangeble */ 35 struct pvr_s pvr; 36 37 void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) 38 { 39 unsigned int i; 40 unsigned long *pt_regb = (unsigned long *)regs; 41 int temp; 42 43 /* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */ 44 for (i = 0; i < (sizeof(struct pt_regs) / 4) - 1; i++) 45 gdb_regs[i] = pt_regb[i]; 46 47 /* Branch target register can't be changed */ 48 __asm__ __volatile__ ("mfs %0, rbtr;" : "=r"(temp) : ); 49 gdb_regs[GDB_BTR] = temp; 50 51 /* pvr part - we have 11 pvr regs */ 52 for (i = 0; i < sizeof(struct pvr_s)/4; i++) 53 gdb_regs[GDB_PVR + i] = pvr.pvr[i]; 54 55 /* read special registers - can't be changed */ 56 __asm__ __volatile__ ("mfs %0, redr;" : "=r"(temp) : ); 57 gdb_regs[GDB_REDR] = temp; 58 __asm__ __volatile__ ("mfs %0, rpid;" : "=r"(temp) : ); 59 gdb_regs[GDB_RPID] = temp; 60 __asm__ __volatile__ ("mfs %0, rzpr;" : "=r"(temp) : ); 61 gdb_regs[GDB_RZPR] = temp; 62 __asm__ __volatile__ ("mfs %0, rtlbx;" : "=r"(temp) : ); 63 gdb_regs[GDB_RTLBX] = temp; 64 __asm__ __volatile__ ("mfs %0, rtlblo;" : "=r"(temp) : ); 65 gdb_regs[GDB_RTLBLO] = temp; 66 __asm__ __volatile__ ("mfs %0, rtlbhi;" : "=r"(temp) : ); 67 gdb_regs[GDB_RTLBHI] = temp; 68 } 69 70 void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) 71 { 72 unsigned int i; 73 unsigned long *pt_regb = (unsigned long *)regs; 74 75 /* pt_regs and gdb_regs have the same 37 values. 76 * The rest of gdb_regs are unused and can't be changed. 77 * r0 register value can't be changed too. */ 78 for (i = 1; i < (sizeof(struct pt_regs) / 4) - 1; i++) 79 pt_regb[i] = gdb_regs[i]; 80 } 81 82 asmlinkage void microblaze_kgdb_break(struct pt_regs *regs) 83 { 84 if (kgdb_handle_exception(1, SIGTRAP, 0, regs) != 0) 85 return; 86 87 /* Jump over the first arch_kgdb_breakpoint which is barrier to 88 * get kgdb work. The same solution is used for powerpc */ 89 if (*(u32 *) (regs->pc) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr)) 90 regs->pc += BREAK_INSTR_SIZE; 91 } 92 93 /* untested */ 94 void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) 95 { 96 unsigned int i; 97 unsigned long *pt_regb = (unsigned long *)(p->thread.regs); 98 99 /* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */ 100 for (i = 0; i < (sizeof(struct pt_regs) / 4) - 1; i++) 101 gdb_regs[i] = pt_regb[i]; 102 103 /* pvr part - we have 11 pvr regs */ 104 for (i = 0; i < sizeof(struct pvr_s)/4; i++) 105 gdb_regs[GDB_PVR + i] = pvr.pvr[i]; 106 } 107 108 void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip) 109 { 110 regs->pc = ip; 111 } 112 113 int kgdb_arch_handle_exception(int vector, int signo, int err_code, 114 char *remcom_in_buffer, char *remcom_out_buffer, 115 struct pt_regs *regs) 116 { 117 char *ptr; 118 unsigned long address; 119 120 switch (remcom_in_buffer[0]) { 121 case 'c': 122 /* handle the optional parameter */ 123 ptr = &remcom_in_buffer[1]; 124 if (kgdb_hex2long(&ptr, &address)) 125 regs->pc = address; 126 127 return 0; 128 } 129 return -1; /* this means that we do not want to exit from the handler */ 130 } 131 132 int kgdb_arch_init(void) 133 { 134 get_pvr(&pvr); /* Fill PVR structure */ 135 return 0; 136 } 137 138 void kgdb_arch_exit(void) 139 { 140 /* Nothing to do */ 141 } 142 143 /* 144 * Global data 145 */ 146 struct kgdb_arch arch_kgdb_ops = { 147 #ifdef __MICROBLAZEEL__ 148 .gdb_bpt_instr = {0x18, 0x00, 0x0c, 0xba}, /* brki r16, 0x18 */ 149 #else 150 .gdb_bpt_instr = {0xba, 0x0c, 0x00, 0x18}, /* brki r16, 0x18 */ 151 #endif 152 }; 153