Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2d5973cb authored by Michal Simek's avatar Michal Simek
Browse files

microblaze: Add KGDB support



Kgdb uses brki r16, 0x18 instruction to call
low level _debug_exception function which save
current state to pt_regs and call microblaze_kgdb_break
function. _debug_exception should be called only from
the kernel space. User space calling is not supported
because user application debugging uses different handling.

pt_regs_to_gdb_regs loads additional special registers
which can't be changed

 * Enable KGDB in Kconfig
 * Remove ancient not-tested KGDB support
 * Remove ancient _debug_exception code from entry.S

Only MMU KGDB support is supported.

Signed-off-by: default avatarMichal Simek <monstr@monstr.eu>
CC: Jason Wessel <jason.wessel@windriver.com>
CC: John Williams <john.williams@petalogix.com>
CC: Edgar E. Iglesias <edgar.iglesias@petalogix.com>
CC: linux-kernel@vger.kernel.org
Acked-by: default avatarJason Wessel <jason.wessel@windriver.com>
parent 751f1605
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -14,6 +14,7 @@ config MICROBLAZE
	select USB_ARCH_HAS_EHCI
	select USB_ARCH_HAS_EHCI
	select ARCH_WANT_OPTIONAL_GPIOLIB
	select ARCH_WANT_OPTIONAL_GPIOLIB
	select HAVE_OPROFILE
	select HAVE_OPROFILE
	select HAVE_ARCH_KGDB
	select HAVE_DMA_ATTRS
	select HAVE_DMA_ATTRS
	select HAVE_DMA_API_DEBUG
	select HAVE_DMA_API_DEBUG
	select TRACING_SUPPORT
	select TRACING_SUPPORT
+0 −16
Original line number Original line Diff line number Diff line
@@ -69,22 +69,6 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
void die(const char *str, struct pt_regs *fp, long err);
void die(const char *str, struct pt_regs *fp, long err);
void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr);
void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr);


#if defined(CONFIG_KGDB)
void (*debugger)(struct pt_regs *regs);
int (*debugger_bpt)(struct pt_regs *regs);
int (*debugger_sstep)(struct pt_regs *regs);
int (*debugger_iabr_match)(struct pt_regs *regs);
int (*debugger_dabr_match)(struct pt_regs *regs);
void (*debugger_fault_handler)(struct pt_regs *regs);
#else
#define debugger(regs)			do { } while (0)
#define debugger_bpt(regs)		0
#define debugger_sstep(regs)		0
#define debugger_iabr_match(regs)	0
#define debugger_dabr_match(regs)	0
#define debugger_fault_handler		((void (*)(struct pt_regs *))0)
#endif

#endif /*__ASSEMBLY__ */
#endif /*__ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* __KERNEL__ */
#endif /* _ASM_MICROBLAZE_EXCEPTIONS_H */
#endif /* _ASM_MICROBLAZE_EXCEPTIONS_H */
+28 −0
Original line number Original line Diff line number Diff line
#ifdef __KERNEL__
#ifndef __MICROBLAZE_KGDB_H__
#define __MICROBLAZE_KGDB_H__

#ifndef __ASSEMBLY__

#define CACHE_FLUSH_IS_SAFE	1
#define BUFMAX			2048

/*
 * 32 32-bit general purpose registers (r0-r31)
 *  6 32-bit special registers (pc, msr, ear, esr, fsr, btr)
 * 12 32-bit PVR
 *   7 32-bit MMU Regs (redr, rpid, rzpr, rtlbx, rtlbsx, rtlblo, rtlbhi)
 * ------
 *  57 registers
 */
#define NUMREGBYTES	(57 * 4)

#define BREAK_INSTR_SIZE	4
static inline void arch_kgdb_breakpoint(void)
{
	__asm__ __volatile__("brki r16, 0x18;");
}

#endif /* __ASSEMBLY__ */
#endif /* __MICROBLAZE_KGDB_H__ */
#endif /* __KERNEL__ */
+1 −0
Original line number Original line Diff line number Diff line
@@ -28,5 +28,6 @@ obj-$(CONFIG_MODULES) += microblaze_ksyms.o module.o
obj-$(CONFIG_MMU)		+= misc.o
obj-$(CONFIG_MMU)		+= misc.o
obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
obj-$(CONFIG_FUNCTION_TRACER)	+= ftrace.o mcount.o
obj-$(CONFIG_FUNCTION_TRACER)	+= ftrace.o mcount.o
obj-$(CONFIG_KGDB)		+= kgdb.o


obj-y	+= entry$(MMU).o
obj-y	+= entry$(MMU).o
+57 −49
Original line number Original line Diff line number Diff line
@@ -745,11 +745,8 @@ IRQ_return: /* MS: Make global symbol for debugging */
	nop
	nop


/*
/*
 * `Debug' trap
 * Debug trap for KGDB. Enter to _debug_exception by brki r16, 0x18
 *  We enter dbtrap in "BIP" (breakpoint) mode.
 * and call handling function with saved pt_regs
 *  So we exit the breakpoint mode with an 'rtbd' and proceed with the
 *  original dbtrap.
 *  however, wait to save state first
 */
 */
C_ENTRY(_debug_exception):
C_ENTRY(_debug_exception):
	/* BIP bit is set on entry, no interrupts can occur */
	/* BIP bit is set on entry, no interrupts can occur */
@@ -759,18 +756,44 @@ C_ENTRY(_debug_exception):
	nop
	nop
	andi	r1, r1, MSR_UMS
	andi	r1, r1, MSR_UMS
	bnei	r1, 1f
	bnei	r1, 1f
	/* Kernel-mode state save.  */
/* MS: Kernel-mode state save - kgdb */
	lwi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
	lwi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
	tophys(r1,r1);


	addik	r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */
	/* BIP bit is set on entry, no interrupts can occur */
	addik   r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE;
	SAVE_REGS;
	SAVE_REGS;
	/* save all regs to pt_reg structure */
	swi	r0, r1, PTO+PT_R0;	/* R0 must be saved too */
	swi	r14, r1, PTO+PT_R14	/* rewrite saved R14 value */
	swi	r16, r1, PTO+PT_R16
	swi	r16, r1, PTO+PT_PC; /* PC and r16 are the same */
	swi	r17, r1, PTO+PT_R17
	/* save special purpose registers to pt_regs */
	mfs	r11, rear;
	swi	r11, r1, PTO+PT_EAR;
	mfs	r11, resr;
	swi	r11, r1, PTO+PT_ESR;
	mfs	r11, rfsr;
	swi	r11, r1, PTO+PT_FSR;

	/* stack pointer is in physical address at it is decrease
	 * by STATE_SAVE_SIZE but we need to get correct R1 value */
	addik   r11, r1, CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR + STATE_SAVE_SIZE;
	swi	r11, r1, PTO+PT_R1
	/* MS: r31 - current pointer isn't changed */
	tovirt(r1,r1)
#ifdef CONFIG_KGDB
	addi	r5, r1, PTO /* pass pt_reg address as the first arg */
	la	r15, r0, dbtrap_call; /* return address */
	rtbd	r0, microblaze_kgdb_break
	nop;
#endif
	/* MS: Place handler for brki from kernel space if KGDB is OFF.
	 * It is very unlikely that another brki instruction is called. */
	bri 0


	swi	r1, r1, PTO + PT_MODE;
/* MS: User-mode state save - gdb */
	brid	2f;
1:	lwi	r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
	nop;				/* Fill delay slot */
1:      /* User-mode state save.  */
	lwi	r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
	tophys(r1,r1);
	tophys(r1,r1);
	lwi	r1, r1, TS_THREAD_INFO;	/* get the thread info */
	lwi	r1, r1, TS_THREAD_INFO;	/* get the thread info */
	addik	r1, r1, THREAD_SIZE;	/* calculate kernel stack pointer */
	addik	r1, r1, THREAD_SIZE;	/* calculate kernel stack pointer */
@@ -781,24 +804,23 @@ C_ENTRY(_debug_exception):
	swi	r17, r1, PTO+PT_R17;
	swi	r17, r1, PTO+PT_R17;
	swi	r16, r1, PTO+PT_R16;
	swi	r16, r1, PTO+PT_R16;
	swi	r16, r1, PTO+PT_PC;	/* Save LP */
	swi	r16, r1, PTO+PT_PC;	/* Save LP */

	swi	r0, r1, PTO + PT_MODE; /* Was in user-mode.  */
	swi	r0, r1, PTO + PT_MODE; /* Was in user-mode.  */
	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
	swi	r11, r1, PTO+PT_R1; /* Store user SP.  */
	swi	r11, r1, PTO+PT_R1; /* Store user SP.  */
2:	lwi	CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
	lwi	CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
	tovirt(r1,r1)
	tovirt(r1,r1)

	set_vms;
	set_vms;
	addik	r5, r1, PTO;
	addik	r5, r1, PTO;
	addik	r15, r0, dbtrap_call;
	addik	r15, r0, dbtrap_call;
dbtrap_call: /* return point for kernel/user entry */
dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
	rtbd	r0, sw_exception
	rtbd	r0, sw_exception
	nop
	nop


	/* MS: The first instruction for the second part of the gdb/kgdb */
	set_bip; /* Ints masked for state restore */
	set_bip; /* Ints masked for state restore */
	lwi	r11, r1, PTO + PT_MODE;
	lwi	r11, r1, PTO + PT_MODE;
	bnei	r11, 2f;
	bnei	r11, 2f;

/* MS: Return to user space - gdb */
	/* Get current task ptr into r11 */
	/* Get current task ptr into r11 */
	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
@@ -806,11 +828,8 @@ dbtrap_call: /* return point for kernel/user entry */
	beqi	r11, 5f;
	beqi	r11, 5f;


	/* Call the scheduler before returning from a syscall/trap. */
	/* Call the scheduler before returning from a syscall/trap. */

	bralid	r15, schedule;	/* Call scheduler */
	bralid	r15, schedule;	/* Call scheduler */
	nop;				/* delay slot */
	nop;				/* delay slot */
	/* XXX Is PT_DTRACE handling needed here? */
	/* XXX m68knommu also checks TASK_STATE & TASK_COUNTER here.  */


	/* Maybe handle a signal */
	/* Maybe handle a signal */
5:	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
5:	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
@@ -818,48 +837,37 @@ dbtrap_call: /* return point for kernel/user entry */
	andi	r11, r11, _TIF_SIGPENDING;
	andi	r11, r11, _TIF_SIGPENDING;
	beqi	r11, 1f;		/* Signals to handle, handle them */
	beqi	r11, 1f;		/* Signals to handle, handle them */


/* Handle a signal return; Pending signals should be in r18.  */
	/* Not all registers are saved by the normal trap/interrupt entry
	   points (for instance, call-saved registers (because the normal
	   C-compiler calling sequence in the kernel makes sure they're
	   preserved), and call-clobbered registers in the case of
	   traps), but signal handlers may want to examine or change the
	   complete register state.  Here we save anything not saved by
	   the normal entry sequence, so that it may be safely restored
	   (in a possibly modified form) after do_signal returns.  */

	addik	r5, r1, PTO;		/* Arg 1: struct pt_regs *regs */
	addik	r5, r1, PTO;		/* Arg 1: struct pt_regs *regs */
	addi  r7, r0, 0;	/* Arg 3: int in_syscall */
	addi  r7, r0, 0;	/* Arg 3: int in_syscall */
	bralid	r15, do_signal;	/* Handle any signals */
	bralid	r15, do_signal;	/* Handle any signals */
	add	r6, r0, r0;		/* Arg 2: sigset_t *oldset */
	add	r6, r0, r0;		/* Arg 2: sigset_t *oldset */



/* Finally, return to user state.  */
/* Finally, return to user state.  */
1:
1:	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
	VM_OFF;
	VM_OFF;
	tophys(r1,r1);
	tophys(r1,r1);

	/* MS: Restore all regs */
	RESTORE_REGS
	RESTORE_REGS
	lwi	r17, r1, PTO+PT_R17;
	lwi	r17, r1, PTO+PT_R17;
	lwi	r16, r1, PTO+PT_R16;
	lwi	r16, r1, PTO+PT_R16;
	addik	r1, r1, STATE_SAVE_SIZE		/* Clean up stack space.  */
	addik	r1, r1, STATE_SAVE_SIZE	 /* Clean up stack space */

	lwi	r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */

DBTRAP_return_user: /* MS: Make global symbol for debugging */
	lwi	r1, r1, PT_R1 - PT_SIZE;
	rtbd	r16, 0; /* MS: Instructions to return from a debug trap */
					/* Restore user stack pointer. */
	nop;
	bri	6f;


/* Return to kernel state.  */
/* MS: Return to kernel state - kgdb */
2:	VM_OFF;
2:	VM_OFF;
	tophys(r1,r1);
	tophys(r1,r1);
	/* MS: Restore all regs */
	RESTORE_REGS
	RESTORE_REGS
	addik	r1, r1, STATE_SAVE_SIZE		/* Clean up stack space.  */
	lwi	r14, r1, PTO+PT_R14;

	lwi	r16, r1, PTO+PT_PC;
	lwi	r17, r1, PTO+PT_R17;
	addik	r1, r1, STATE_SAVE_SIZE; /* MS: Clean up stack space */
	tovirt(r1,r1);
	tovirt(r1,r1);
6:
DBTRAP_return_kernel: /* MS: Make global symbol for debugging */
DBTRAP_return:		/* Make global symbol for debugging */
	rtbd	r16, 0; /* MS: Instructions to return from a debug trap */
	rtbd	r16, 0;	/* Instructions to return from an IRQ */
	nop;
	nop;




Loading