xref: /openbmc/linux/arch/microblaze/kernel/kgdb.c (revision f396a4d2314bf1cb83148d9b8fc47995e6c27e1f)
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>
15*f396a4d2SMichal 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 
342d5973cbSMichal Simek /* keep pvr separately because it is unchangeble */
352d5973cbSMichal Simek struct pvr_s pvr;
362d5973cbSMichal Simek 
372d5973cbSMichal Simek void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
382d5973cbSMichal Simek {
392d5973cbSMichal Simek 	int i;
402d5973cbSMichal Simek 	unsigned long *pt_regb = (unsigned long *)regs;
412d5973cbSMichal Simek 	int temp;
422d5973cbSMichal Simek 	/* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */
432d5973cbSMichal Simek 	for (i = 0; i < (sizeof(struct pt_regs) / 4) - 1; i++)
442d5973cbSMichal Simek 		gdb_regs[i] = pt_regb[i];
452d5973cbSMichal Simek 
462d5973cbSMichal Simek 	/* Branch target register can't be changed */
472d5973cbSMichal Simek 	__asm__ __volatile__ ("mfs %0, rbtr;" : "=r"(temp) : );
482d5973cbSMichal Simek 	gdb_regs[GDB_BTR] = temp;
492d5973cbSMichal Simek 
502d5973cbSMichal Simek 	/* pvr part  - we have 11 pvr regs */
512d5973cbSMichal Simek 	for (i = 0; i < sizeof(struct pvr_s)/4; i++)
522d5973cbSMichal Simek 		gdb_regs[GDB_PVR + i] = pvr.pvr[i];
532d5973cbSMichal Simek 
542d5973cbSMichal Simek 	/* read special registers - can't be changed */
552d5973cbSMichal Simek 	__asm__ __volatile__ ("mfs %0, redr;" : "=r"(temp) : );
562d5973cbSMichal Simek 	gdb_regs[GDB_REDR] = temp;
572d5973cbSMichal Simek 	__asm__ __volatile__ ("mfs %0, rpid;" : "=r"(temp) : );
582d5973cbSMichal Simek 	gdb_regs[GDB_RPID] = temp;
592d5973cbSMichal Simek 	__asm__ __volatile__ ("mfs %0, rzpr;" : "=r"(temp) : );
602d5973cbSMichal Simek 	gdb_regs[GDB_RZPR] = temp;
612d5973cbSMichal Simek 	__asm__ __volatile__ ("mfs %0, rtlbx;" : "=r"(temp) : );
622d5973cbSMichal Simek 	gdb_regs[GDB_RTLBX] = temp;
632d5973cbSMichal Simek 	__asm__ __volatile__ ("mfs %0, rtlblo;" : "=r"(temp) : );
642d5973cbSMichal Simek 	gdb_regs[GDB_RTLBLO] = temp;
652d5973cbSMichal Simek 	__asm__ __volatile__ ("mfs %0, rtlbhi;" : "=r"(temp) : );
662d5973cbSMichal Simek 	gdb_regs[GDB_RTLBHI] = temp;
672d5973cbSMichal Simek }
682d5973cbSMichal Simek 
692d5973cbSMichal Simek void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
702d5973cbSMichal Simek {
712d5973cbSMichal Simek 	int i;
722d5973cbSMichal Simek 	unsigned long *pt_regb = (unsigned long *)regs;
732d5973cbSMichal Simek 
742d5973cbSMichal Simek 	/* pt_regs and gdb_regs have the same 37 values.
752d5973cbSMichal Simek 	 * The rest of gdb_regs are unused and can't be changed.
762d5973cbSMichal Simek 	 * r0 register value can't be changed too. */
772d5973cbSMichal Simek 	for (i = 1; i < (sizeof(struct pt_regs) / 4) - 1; i++)
782d5973cbSMichal Simek 		pt_regb[i] = gdb_regs[i];
792d5973cbSMichal Simek }
802d5973cbSMichal Simek 
81*f396a4d2SMichal Simek asmlinkage void microblaze_kgdb_break(struct pt_regs *regs)
822d5973cbSMichal Simek {
832d5973cbSMichal Simek 	if (kgdb_handle_exception(1, SIGTRAP, 0, regs) != 0)
84f859f0a2SMichal Simek 		return;
852d5973cbSMichal Simek 
862d5973cbSMichal Simek 	/* Jump over the first arch_kgdb_breakpoint which is barrier to
872d5973cbSMichal Simek 	 * get kgdb work. The same solution is used for powerpc */
882d5973cbSMichal Simek 	if (*(u32 *) (regs->pc) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr))
892d5973cbSMichal Simek 		regs->pc += BREAK_INSTR_SIZE;
902d5973cbSMichal Simek }
912d5973cbSMichal Simek 
922d5973cbSMichal Simek /* untested */
932d5973cbSMichal Simek void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
942d5973cbSMichal Simek {
952d5973cbSMichal Simek 	int i;
962d5973cbSMichal Simek 	unsigned long *pt_regb = (unsigned long *)(p->thread.regs);
972d5973cbSMichal Simek 
982d5973cbSMichal Simek 	/* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */
992d5973cbSMichal Simek 	for (i = 0; i < (sizeof(struct pt_regs) / 4) - 1; i++)
1002d5973cbSMichal Simek 		gdb_regs[i] = pt_regb[i];
1012d5973cbSMichal Simek 
1022d5973cbSMichal Simek 	/* pvr part  - we have 11 pvr regs */
1032d5973cbSMichal Simek 	for (i = 0; i < sizeof(struct pvr_s)/4; i++)
1042d5973cbSMichal Simek 		gdb_regs[GDB_PVR + i] = pvr.pvr[i];
1052d5973cbSMichal Simek }
1062d5973cbSMichal Simek 
1072d5973cbSMichal Simek void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
1082d5973cbSMichal Simek {
1092d5973cbSMichal Simek 	regs->pc = ip;
1102d5973cbSMichal Simek }
1112d5973cbSMichal Simek 
1122d5973cbSMichal Simek int kgdb_arch_handle_exception(int vector, int signo, int err_code,
1132d5973cbSMichal Simek 			       char *remcom_in_buffer, char *remcom_out_buffer,
1142d5973cbSMichal Simek 			       struct pt_regs *regs)
1152d5973cbSMichal Simek {
1162d5973cbSMichal Simek 	char *ptr;
1172d5973cbSMichal Simek 	unsigned long address;
1182d5973cbSMichal Simek 
1192d5973cbSMichal Simek 	switch (remcom_in_buffer[0]) {
1202d5973cbSMichal Simek 	case 'c':
1212d5973cbSMichal Simek 		/* handle the optional parameter */
1222d5973cbSMichal Simek 		ptr = &remcom_in_buffer[1];
1232d5973cbSMichal Simek 		if (kgdb_hex2long(&ptr, &address))
1242d5973cbSMichal Simek 			regs->pc = address;
1252d5973cbSMichal Simek 
1262d5973cbSMichal Simek 		return 0;
1272d5973cbSMichal Simek 	}
1282d5973cbSMichal Simek 	return -1; /* this means that we do not want to exit from the handler */
1292d5973cbSMichal Simek }
1302d5973cbSMichal Simek 
1312d5973cbSMichal Simek int kgdb_arch_init(void)
1322d5973cbSMichal Simek {
1332d5973cbSMichal Simek 	get_pvr(&pvr); /* Fill PVR structure */
1342d5973cbSMichal Simek 	return 0;
1352d5973cbSMichal Simek }
1362d5973cbSMichal Simek 
1372d5973cbSMichal Simek void kgdb_arch_exit(void)
1382d5973cbSMichal Simek {
1392d5973cbSMichal Simek 	/* Nothing to do */
1402d5973cbSMichal Simek }
1412d5973cbSMichal Simek 
1422d5973cbSMichal Simek /*
1432d5973cbSMichal Simek  * Global data
1442d5973cbSMichal Simek  */
145218a12f1SGraeme Smecher struct kgdb_arch arch_kgdb_ops = {
146e4f29092SMichal Simek #ifdef __MICROBLAZEEL__
147e4f29092SMichal Simek 	.gdb_bpt_instr = {0x18, 0x00, 0x0c, 0xba}, /* brki r16, 0x18 */
148e4f29092SMichal Simek #else
1492d5973cbSMichal Simek 	.gdb_bpt_instr = {0xba, 0x0c, 0x00, 0x18}, /* brki r16, 0x18 */
150e4f29092SMichal Simek #endif
1512d5973cbSMichal Simek };
152