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