-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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: Michal 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: Jason Wessel <jason.wessel@windriver.com>
- Loading branch information
Michal Simek
committed
Aug 4, 2010
1 parent
751f160
commit 2d5973c
Showing
8 changed files
with
234 additions
and
81 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#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__ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
/* | ||
* 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/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 */ | ||
struct pvr_s pvr; | ||
|
||
void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
{ | ||
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) | ||
{ | ||
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]; | ||
} | ||
|
||
void microblaze_kgdb_break(struct pt_regs *regs) | ||
{ | ||
if (kgdb_handle_exception(1, SIGTRAP, 0, regs) != 0) | ||
return 0; | ||
|
||
/* 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) | ||
{ | ||
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; | ||
int cpu = smp_processor_id(); | ||
|
||
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 | ||
*/ | ||
struct kgdb_arch arch_kgdb_ops = { | ||
.gdb_bpt_instr = {0xba, 0x0c, 0x00, 0x18}, /* brki r16, 0x18 */ | ||
}; |
Oops, something went wrong.