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