xref: /linux/arch/microblaze/kernel/kgdb.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
12d5973cbSMichal Simek /*
22d5973cbSMichal Simek  * Microblaze KGDB support
32d5973cbSMichal Simek  *
42d5973cbSMichal Simek  * This file is subject to the terms and conditions of the GNU General Public
52d5973cbSMichal Simek  * License.  See the file "COPYING" in the main directory of this archive
62d5973cbSMichal Simek  * for more details.
72d5973cbSMichal Simek  */
82d5973cbSMichal Simek 
92d5973cbSMichal Simek #include <linux/kgdb.h>
102d5973cbSMichal Simek #include <linux/kdebug.h>
112d5973cbSMichal Simek #include <linux/irq.h>
122d5973cbSMichal Simek #include <linux/io.h>
132d5973cbSMichal Simek #include <asm/cacheflush.h>
142d5973cbSMichal Simek #include <asm/asm-offsets.h>
15f396a4d2SMichal Simek #include <asm/kgdb.h>
162d5973cbSMichal Simek #include <asm/pvr.h>
172d5973cbSMichal Simek 
182d5973cbSMichal Simek #define GDB_REG		0
192d5973cbSMichal Simek #define GDB_PC		32
202d5973cbSMichal Simek #define GDB_MSR		33
212d5973cbSMichal Simek #define GDB_EAR		34
222d5973cbSMichal Simek #define GDB_ESR		35
232d5973cbSMichal Simek #define GDB_FSR		36
242d5973cbSMichal Simek #define GDB_BTR		37
252d5973cbSMichal Simek #define GDB_PVR		38
262d5973cbSMichal Simek #define GDB_REDR	50
272d5973cbSMichal Simek #define GDB_RPID	51
282d5973cbSMichal Simek #define GDB_RZPR	52
292d5973cbSMichal Simek #define GDB_RTLBX	53
302d5973cbSMichal Simek #define GDB_RTLBSX	54 /* mfs can't read it */
312d5973cbSMichal Simek #define GDB_RTLBLO	55
322d5973cbSMichal Simek #define GDB_RTLBHI	56
332d5973cbSMichal Simek 
34*78b5f52aSJulia Lawall /* keep pvr separately because it is unchangeable */
3555ae2f3bSMichal Simek static struct pvr_s pvr;
362d5973cbSMichal Simek 
pt_regs_to_gdb_regs(unsigned long * gdb_regs,struct pt_regs * regs)372d5973cbSMichal Simek void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
382d5973cbSMichal Simek {
39e76fdb32SMichal Simek 	unsigned int i;
402d5973cbSMichal Simek 	unsigned long *pt_regb = (unsigned long *)regs;
412d5973cbSMichal Simek 	int temp;
42e76fdb32SMichal Simek 
432d5973cbSMichal Simek 	/* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */
442d5973cbSMichal Simek 	for (i = 0; i < (sizeof(struct pt_regs) / 4) - 1; i++)
452d5973cbSMichal Simek 		gdb_regs[i] = pt_regb[i];
462d5973cbSMichal Simek 
472d5973cbSMichal Simek 	/* Branch target register can't be changed */
482d5973cbSMichal Simek 	__asm__ __volatile__ ("mfs %0, rbtr;" : "=r"(temp) : );
492d5973cbSMichal Simek 	gdb_regs[GDB_BTR] = temp;
502d5973cbSMichal Simek 
512d5973cbSMichal Simek 	/* pvr part  - we have 11 pvr regs */
522d5973cbSMichal Simek 	for (i = 0; i < sizeof(struct pvr_s)/4; i++)
532d5973cbSMichal Simek 		gdb_regs[GDB_PVR + i] = pvr.pvr[i];
542d5973cbSMichal Simek 
552d5973cbSMichal Simek 	/* read special registers - can't be changed */
562d5973cbSMichal Simek 	__asm__ __volatile__ ("mfs %0, redr;" : "=r"(temp) : );
572d5973cbSMichal Simek 	gdb_regs[GDB_REDR] = temp;
582d5973cbSMichal Simek 	__asm__ __volatile__ ("mfs %0, rpid;" : "=r"(temp) : );
592d5973cbSMichal Simek 	gdb_regs[GDB_RPID] = temp;
602d5973cbSMichal Simek 	__asm__ __volatile__ ("mfs %0, rzpr;" : "=r"(temp) : );
612d5973cbSMichal Simek 	gdb_regs[GDB_RZPR] = temp;
622d5973cbSMichal Simek 	__asm__ __volatile__ ("mfs %0, rtlbx;" : "=r"(temp) : );
632d5973cbSMichal Simek 	gdb_regs[GDB_RTLBX] = temp;
642d5973cbSMichal Simek 	__asm__ __volatile__ ("mfs %0, rtlblo;" : "=r"(temp) : );
652d5973cbSMichal Simek 	gdb_regs[GDB_RTLBLO] = temp;
662d5973cbSMichal Simek 	__asm__ __volatile__ ("mfs %0, rtlbhi;" : "=r"(temp) : );
672d5973cbSMichal Simek 	gdb_regs[GDB_RTLBHI] = temp;
682d5973cbSMichal Simek }
692d5973cbSMichal Simek 
gdb_regs_to_pt_regs(unsigned long * gdb_regs,struct pt_regs * regs)702d5973cbSMichal Simek void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
712d5973cbSMichal Simek {
72e76fdb32SMichal Simek 	unsigned int i;
732d5973cbSMichal Simek 	unsigned long *pt_regb = (unsigned long *)regs;
742d5973cbSMichal Simek 
752d5973cbSMichal Simek 	/* pt_regs and gdb_regs have the same 37 values.
762d5973cbSMichal Simek 	 * The rest of gdb_regs are unused and can't be changed.
772d5973cbSMichal Simek 	 * r0 register value can't be changed too. */
782d5973cbSMichal Simek 	for (i = 1; i < (sizeof(struct pt_regs) / 4) - 1; i++)
792d5973cbSMichal Simek 		pt_regb[i] = gdb_regs[i];
802d5973cbSMichal Simek }
812d5973cbSMichal Simek 
microblaze_kgdb_break(struct pt_regs * regs)82f396a4d2SMichal Simek asmlinkage void microblaze_kgdb_break(struct pt_regs *regs)
832d5973cbSMichal Simek {
842d5973cbSMichal Simek 	if (kgdb_handle_exception(1, SIGTRAP, 0, regs) != 0)
85f859f0a2SMichal Simek 		return;
862d5973cbSMichal Simek 
872d5973cbSMichal Simek 	/* Jump over the first arch_kgdb_breakpoint which is barrier to
882d5973cbSMichal Simek 	 * get kgdb work. The same solution is used for powerpc */
892d5973cbSMichal Simek 	if (*(u32 *) (regs->pc) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr))
902d5973cbSMichal Simek 		regs->pc += BREAK_INSTR_SIZE;
912d5973cbSMichal Simek }
922d5973cbSMichal Simek 
932d5973cbSMichal Simek /* untested */
sleeping_thread_to_gdb_regs(unsigned long * gdb_regs,struct task_struct * p)942d5973cbSMichal Simek void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
952d5973cbSMichal Simek {
96e76fdb32SMichal Simek 	unsigned int i;
972d5973cbSMichal Simek 	unsigned long *pt_regb = (unsigned long *)(p->thread.regs);
982d5973cbSMichal Simek 
992d5973cbSMichal Simek 	/* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */
1002d5973cbSMichal Simek 	for (i = 0; i < (sizeof(struct pt_regs) / 4) - 1; i++)
1012d5973cbSMichal Simek 		gdb_regs[i] = pt_regb[i];
1022d5973cbSMichal Simek 
1032d5973cbSMichal Simek 	/* pvr part  - we have 11 pvr regs */
1042d5973cbSMichal Simek 	for (i = 0; i < sizeof(struct pvr_s)/4; i++)
1052d5973cbSMichal Simek 		gdb_regs[GDB_PVR + i] = pvr.pvr[i];
1062d5973cbSMichal Simek }
1072d5973cbSMichal Simek 
kgdb_arch_set_pc(struct pt_regs * regs,unsigned long ip)1082d5973cbSMichal Simek void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
1092d5973cbSMichal Simek {
1102d5973cbSMichal Simek 	regs->pc = ip;
1112d5973cbSMichal Simek }
1122d5973cbSMichal Simek 
kgdb_arch_handle_exception(int vector,int signo,int err_code,char * remcom_in_buffer,char * remcom_out_buffer,struct pt_regs * regs)1132d5973cbSMichal Simek int kgdb_arch_handle_exception(int vector, int signo, int err_code,
1142d5973cbSMichal Simek 			       char *remcom_in_buffer, char *remcom_out_buffer,
1152d5973cbSMichal Simek 			       struct pt_regs *regs)
1162d5973cbSMichal Simek {
1172d5973cbSMichal Simek 	char *ptr;
1182d5973cbSMichal Simek 	unsigned long address;
1192d5973cbSMichal Simek 
1202d5973cbSMichal Simek 	switch (remcom_in_buffer[0]) {
1212d5973cbSMichal Simek 	case 'c':
1222d5973cbSMichal Simek 		/* handle the optional parameter */
1232d5973cbSMichal Simek 		ptr = &remcom_in_buffer[1];
1242d5973cbSMichal Simek 		if (kgdb_hex2long(&ptr, &address))
1252d5973cbSMichal Simek 			regs->pc = address;
1262d5973cbSMichal Simek 
1272d5973cbSMichal Simek 		return 0;
1282d5973cbSMichal Simek 	}
1292d5973cbSMichal Simek 	return -1; /* this means that we do not want to exit from the handler */
1302d5973cbSMichal Simek }
1312d5973cbSMichal Simek 
kgdb_arch_init(void)1322d5973cbSMichal Simek int kgdb_arch_init(void)
1332d5973cbSMichal Simek {
1342d5973cbSMichal Simek 	get_pvr(&pvr); /* Fill PVR structure */
1352d5973cbSMichal Simek 	return 0;
1362d5973cbSMichal Simek }
1372d5973cbSMichal Simek 
kgdb_arch_exit(void)1382d5973cbSMichal Simek void kgdb_arch_exit(void)
1392d5973cbSMichal Simek {
1402d5973cbSMichal Simek 	/* Nothing to do */
1412d5973cbSMichal Simek }
1422d5973cbSMichal Simek 
1432d5973cbSMichal Simek /*
1442d5973cbSMichal Simek  * Global data
1452d5973cbSMichal Simek  */
146cc028297SChristophe Leroy const struct kgdb_arch arch_kgdb_ops = {
147e4f29092SMichal Simek #ifdef __MICROBLAZEEL__
148e4f29092SMichal Simek 	.gdb_bpt_instr = {0x18, 0x00, 0x0c, 0xba}, /* brki r16, 0x18 */
149e4f29092SMichal Simek #else
1502d5973cbSMichal Simek 	.gdb_bpt_instr = {0xba, 0x0c, 0x00, 0x18}, /* brki r16, 0x18 */
151e4f29092SMichal Simek #endif
1522d5973cbSMichal Simek };
153