diff options
author | Michal Simek <monstr@monstr.eu> | 2010-08-03 05:45:08 -0400 |
---|---|---|
committer | Michal Simek <monstr@monstr.eu> | 2010-08-04 04:45:17 -0400 |
commit | 2d5973cb5ac5d04662f86e19a06a4c52fa4c4ae3 (patch) | |
tree | 21ddc58eed5ccad856fc44dfb0ee794da41d5b16 /arch | |
parent | 751f1605e03533a6279ccf456e938e9595c7d888 (diff) |
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: 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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/microblaze/Kconfig | 1 | ||||
-rw-r--r-- | arch/microblaze/include/asm/exceptions.h | 16 | ||||
-rw-r--r-- | arch/microblaze/include/asm/kgdb.h | 28 | ||||
-rw-r--r-- | arch/microblaze/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/microblaze/kernel/entry.S | 106 | ||||
-rw-r--r-- | arch/microblaze/kernel/exceptions.c | 1 | ||||
-rw-r--r-- | arch/microblaze/kernel/kgdb.c | 147 | ||||
-rw-r--r-- | arch/microblaze/mm/fault.c | 15 |
8 files changed, 234 insertions, 81 deletions
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index a51742190c12..be3855250db6 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig | |||
@@ -14,6 +14,7 @@ config MICROBLAZE | |||
14 | select USB_ARCH_HAS_EHCI | 14 | select USB_ARCH_HAS_EHCI |
15 | select ARCH_WANT_OPTIONAL_GPIOLIB | 15 | select ARCH_WANT_OPTIONAL_GPIOLIB |
16 | select HAVE_OPROFILE | 16 | select HAVE_OPROFILE |
17 | select HAVE_ARCH_KGDB | ||
17 | select HAVE_DMA_ATTRS | 18 | select HAVE_DMA_ATTRS |
18 | select HAVE_DMA_API_DEBUG | 19 | select HAVE_DMA_API_DEBUG |
19 | select TRACING_SUPPORT | 20 | select TRACING_SUPPORT |
diff --git a/arch/microblaze/include/asm/exceptions.h b/arch/microblaze/include/asm/exceptions.h index fa0e36657fdd..6479097b802b 100644 --- a/arch/microblaze/include/asm/exceptions.h +++ b/arch/microblaze/include/asm/exceptions.h | |||
@@ -69,22 +69,6 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, | |||
69 | void die(const char *str, struct pt_regs *fp, long err); | 69 | void die(const char *str, struct pt_regs *fp, long err); |
70 | void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr); | 70 | void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr); |
71 | 71 | ||
72 | #if defined(CONFIG_KGDB) | ||
73 | void (*debugger)(struct pt_regs *regs); | ||
74 | int (*debugger_bpt)(struct pt_regs *regs); | ||
75 | int (*debugger_sstep)(struct pt_regs *regs); | ||
76 | int (*debugger_iabr_match)(struct pt_regs *regs); | ||
77 | int (*debugger_dabr_match)(struct pt_regs *regs); | ||
78 | void (*debugger_fault_handler)(struct pt_regs *regs); | ||
79 | #else | ||
80 | #define debugger(regs) do { } while (0) | ||
81 | #define debugger_bpt(regs) 0 | ||
82 | #define debugger_sstep(regs) 0 | ||
83 | #define debugger_iabr_match(regs) 0 | ||
84 | #define debugger_dabr_match(regs) 0 | ||
85 | #define debugger_fault_handler ((void (*)(struct pt_regs *))0) | ||
86 | #endif | ||
87 | |||
88 | #endif /*__ASSEMBLY__ */ | 72 | #endif /*__ASSEMBLY__ */ |
89 | #endif /* __KERNEL__ */ | 73 | #endif /* __KERNEL__ */ |
90 | #endif /* _ASM_MICROBLAZE_EXCEPTIONS_H */ | 74 | #endif /* _ASM_MICROBLAZE_EXCEPTIONS_H */ |
diff --git a/arch/microblaze/include/asm/kgdb.h b/arch/microblaze/include/asm/kgdb.h new file mode 100644 index 000000000000..78b17d40b235 --- /dev/null +++ b/arch/microblaze/include/asm/kgdb.h | |||
@@ -0,0 +1,28 @@ | |||
1 | #ifdef __KERNEL__ | ||
2 | #ifndef __MICROBLAZE_KGDB_H__ | ||
3 | #define __MICROBLAZE_KGDB_H__ | ||
4 | |||
5 | #ifndef __ASSEMBLY__ | ||
6 | |||
7 | #define CACHE_FLUSH_IS_SAFE 1 | ||
8 | #define BUFMAX 2048 | ||
9 | |||
10 | /* | ||
11 | * 32 32-bit general purpose registers (r0-r31) | ||
12 | * 6 32-bit special registers (pc, msr, ear, esr, fsr, btr) | ||
13 | * 12 32-bit PVR | ||
14 | * 7 32-bit MMU Regs (redr, rpid, rzpr, rtlbx, rtlbsx, rtlblo, rtlbhi) | ||
15 | * ------ | ||
16 | * 57 registers | ||
17 | */ | ||
18 | #define NUMREGBYTES (57 * 4) | ||
19 | |||
20 | #define BREAK_INSTR_SIZE 4 | ||
21 | static inline void arch_kgdb_breakpoint(void) | ||
22 | { | ||
23 | __asm__ __volatile__("brki r16, 0x18;"); | ||
24 | } | ||
25 | |||
26 | #endif /* __ASSEMBLY__ */ | ||
27 | #endif /* __MICROBLAZE_KGDB_H__ */ | ||
28 | #endif /* __KERNEL__ */ | ||
diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile index d66ddef53c07..5eecc9f1fbd9 100644 --- a/arch/microblaze/kernel/Makefile +++ b/arch/microblaze/kernel/Makefile | |||
@@ -28,5 +28,6 @@ obj-$(CONFIG_MODULES) += microblaze_ksyms.o module.o | |||
28 | obj-$(CONFIG_MMU) += misc.o | 28 | obj-$(CONFIG_MMU) += misc.o |
29 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 29 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
30 | obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o mcount.o | 30 | obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o mcount.o |
31 | obj-$(CONFIG_KGDB) += kgdb.o | ||
31 | 32 | ||
32 | obj-y += entry$(MMU).o | 33 | obj-y += entry$(MMU).o |
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 5a5cb5842938..304882e56459 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S | |||
@@ -745,11 +745,8 @@ IRQ_return: /* MS: Make global symbol for debugging */ | |||
745 | nop | 745 | nop |
746 | 746 | ||
747 | /* | 747 | /* |
748 | * `Debug' trap | 748 | * Debug trap for KGDB. Enter to _debug_exception by brki r16, 0x18 |
749 | * We enter dbtrap in "BIP" (breakpoint) mode. | 749 | * and call handling function with saved pt_regs |
750 | * So we exit the breakpoint mode with an 'rtbd' and proceed with the | ||
751 | * original dbtrap. | ||
752 | * however, wait to save state first | ||
753 | */ | 750 | */ |
754 | C_ENTRY(_debug_exception): | 751 | C_ENTRY(_debug_exception): |
755 | /* BIP bit is set on entry, no interrupts can occur */ | 752 | /* BIP bit is set on entry, no interrupts can occur */ |
@@ -759,18 +756,44 @@ C_ENTRY(_debug_exception): | |||
759 | nop | 756 | nop |
760 | andi r1, r1, MSR_UMS | 757 | andi r1, r1, MSR_UMS |
761 | bnei r1, 1f | 758 | bnei r1, 1f |
762 | /* Kernel-mode state save. */ | 759 | /* MS: Kernel-mode state save - kgdb */ |
763 | lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/ | 760 | lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/ |
764 | tophys(r1,r1); | ||
765 | 761 | ||
766 | addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ | 762 | /* BIP bit is set on entry, no interrupts can occur */ |
763 | addik r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; | ||
767 | SAVE_REGS; | 764 | SAVE_REGS; |
765 | /* save all regs to pt_reg structure */ | ||
766 | swi r0, r1, PTO+PT_R0; /* R0 must be saved too */ | ||
767 | swi r14, r1, PTO+PT_R14 /* rewrite saved R14 value */ | ||
768 | swi r16, r1, PTO+PT_R16 | ||
769 | swi r16, r1, PTO+PT_PC; /* PC and r16 are the same */ | ||
770 | swi r17, r1, PTO+PT_R17 | ||
771 | /* save special purpose registers to pt_regs */ | ||
772 | mfs r11, rear; | ||
773 | swi r11, r1, PTO+PT_EAR; | ||
774 | mfs r11, resr; | ||
775 | swi r11, r1, PTO+PT_ESR; | ||
776 | mfs r11, rfsr; | ||
777 | swi r11, r1, PTO+PT_FSR; | ||
778 | |||
779 | /* stack pointer is in physical address at it is decrease | ||
780 | * by STATE_SAVE_SIZE but we need to get correct R1 value */ | ||
781 | addik r11, r1, CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR + STATE_SAVE_SIZE; | ||
782 | swi r11, r1, PTO+PT_R1 | ||
783 | /* MS: r31 - current pointer isn't changed */ | ||
784 | tovirt(r1,r1) | ||
785 | #ifdef CONFIG_KGDB | ||
786 | addi r5, r1, PTO /* pass pt_reg address as the first arg */ | ||
787 | la r15, r0, dbtrap_call; /* return address */ | ||
788 | rtbd r0, microblaze_kgdb_break | ||
789 | nop; | ||
790 | #endif | ||
791 | /* MS: Place handler for brki from kernel space if KGDB is OFF. | ||
792 | * It is very unlikely that another brki instruction is called. */ | ||
793 | bri 0 | ||
768 | 794 | ||
769 | swi r1, r1, PTO + PT_MODE; | 795 | /* MS: User-mode state save - gdb */ |
770 | brid 2f; | 796 | 1: lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ |
771 | nop; /* Fill delay slot */ | ||
772 | 1: /* User-mode state save. */ | ||
773 | lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ | ||
774 | tophys(r1,r1); | 797 | tophys(r1,r1); |
775 | lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ | 798 | lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ |
776 | addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */ | 799 | addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */ |
@@ -781,36 +804,32 @@ C_ENTRY(_debug_exception): | |||
781 | swi r17, r1, PTO+PT_R17; | 804 | swi r17, r1, PTO+PT_R17; |
782 | swi r16, r1, PTO+PT_R16; | 805 | swi r16, r1, PTO+PT_R16; |
783 | swi r16, r1, PTO+PT_PC; /* Save LP */ | 806 | swi r16, r1, PTO+PT_PC; /* Save LP */ |
784 | |||
785 | swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */ | 807 | swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */ |
786 | lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); | 808 | lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); |
787 | swi r11, r1, PTO+PT_R1; /* Store user SP. */ | 809 | swi r11, r1, PTO+PT_R1; /* Store user SP. */ |
788 | 2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); | 810 | lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); |
789 | tovirt(r1,r1) | 811 | tovirt(r1,r1) |
790 | |||
791 | set_vms; | 812 | set_vms; |
792 | addik r5, r1, PTO; | 813 | addik r5, r1, PTO; |
793 | addik r15, r0, dbtrap_call; | 814 | addik r15, r0, dbtrap_call; |
794 | dbtrap_call: /* return point for kernel/user entry */ | 815 | dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */ |
795 | rtbd r0, sw_exception | 816 | rtbd r0, sw_exception |
796 | nop | 817 | nop |
797 | 818 | ||
798 | set_bip; /* Ints masked for state restore*/ | 819 | /* MS: The first instruction for the second part of the gdb/kgdb */ |
820 | set_bip; /* Ints masked for state restore */ | ||
799 | lwi r11, r1, PTO + PT_MODE; | 821 | lwi r11, r1, PTO + PT_MODE; |
800 | bnei r11, 2f; | 822 | bnei r11, 2f; |
801 | 823 | /* MS: Return to user space - gdb */ | |
802 | /* Get current task ptr into r11 */ | 824 | /* Get current task ptr into r11 */ |
803 | lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */ | 825 | lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */ |
804 | lwi r11, r11, TI_FLAGS; /* get flags in thread info */ | 826 | lwi r11, r11, TI_FLAGS; /* get flags in thread info */ |
805 | andi r11, r11, _TIF_NEED_RESCHED; | 827 | andi r11, r11, _TIF_NEED_RESCHED; |
806 | beqi r11, 5f; | 828 | beqi r11, 5f; |
807 | 829 | ||
808 | /* Call the scheduler before returning from a syscall/trap. */ | 830 | /* Call the scheduler before returning from a syscall/trap. */ |
809 | |||
810 | bralid r15, schedule; /* Call scheduler */ | 831 | bralid r15, schedule; /* Call scheduler */ |
811 | nop; /* delay slot */ | 832 | nop; /* delay slot */ |
812 | /* XXX Is PT_DTRACE handling needed here? */ | ||
813 | /* XXX m68knommu also checks TASK_STATE & TASK_COUNTER here. */ | ||
814 | 833 | ||
815 | /* Maybe handle a signal */ | 834 | /* Maybe handle a signal */ |
816 | 5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */ | 835 | 5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */ |
@@ -818,48 +837,37 @@ dbtrap_call: /* return point for kernel/user entry */ | |||
818 | andi r11, r11, _TIF_SIGPENDING; | 837 | andi r11, r11, _TIF_SIGPENDING; |
819 | beqi r11, 1f; /* Signals to handle, handle them */ | 838 | beqi r11, 1f; /* Signals to handle, handle them */ |
820 | 839 | ||
821 | /* Handle a signal return; Pending signals should be in r18. */ | ||
822 | /* Not all registers are saved by the normal trap/interrupt entry | ||
823 | points (for instance, call-saved registers (because the normal | ||
824 | C-compiler calling sequence in the kernel makes sure they're | ||
825 | preserved), and call-clobbered registers in the case of | ||
826 | traps), but signal handlers may want to examine or change the | ||
827 | complete register state. Here we save anything not saved by | ||
828 | the normal entry sequence, so that it may be safely restored | ||
829 | (in a possibly modified form) after do_signal returns. */ | ||
830 | |||
831 | addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ | 840 | addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ |
832 | addi r7, r0, 0; /* Arg 3: int in_syscall */ | 841 | addi r7, r0, 0; /* Arg 3: int in_syscall */ |
833 | bralid r15, do_signal; /* Handle any signals */ | 842 | bralid r15, do_signal; /* Handle any signals */ |
834 | add r6, r0, r0; /* Arg 2: sigset_t *oldset */ | 843 | add r6, r0, r0; /* Arg 2: sigset_t *oldset */ |
835 | 844 | ||
836 | |||
837 | /* Finally, return to user state. */ | 845 | /* Finally, return to user state. */ |
838 | 1: | 846 | 1: swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ |
839 | swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ | ||
840 | VM_OFF; | 847 | VM_OFF; |
841 | tophys(r1,r1); | 848 | tophys(r1,r1); |
842 | 849 | /* MS: Restore all regs */ | |
843 | RESTORE_REGS | 850 | RESTORE_REGS |
844 | lwi r17, r1, PTO+PT_R17; | 851 | lwi r17, r1, PTO+PT_R17; |
845 | lwi r16, r1, PTO+PT_R16; | 852 | lwi r16, r1, PTO+PT_R16; |
846 | addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ | 853 | addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space */ |
847 | 854 | lwi r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */ | |
848 | 855 | DBTRAP_return_user: /* MS: Make global symbol for debugging */ | |
849 | lwi r1, r1, PT_R1 - PT_SIZE; | 856 | rtbd r16, 0; /* MS: Instructions to return from a debug trap */ |
850 | /* Restore user stack pointer. */ | 857 | nop; |
851 | bri 6f; | ||
852 | 858 | ||
853 | /* Return to kernel state. */ | 859 | /* MS: Return to kernel state - kgdb */ |
854 | 2: VM_OFF; | 860 | 2: VM_OFF; |
855 | tophys(r1,r1); | 861 | tophys(r1,r1); |
862 | /* MS: Restore all regs */ | ||
856 | RESTORE_REGS | 863 | RESTORE_REGS |
857 | addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ | 864 | lwi r14, r1, PTO+PT_R14; |
858 | 865 | lwi r16, r1, PTO+PT_PC; | |
866 | lwi r17, r1, PTO+PT_R17; | ||
867 | addik r1, r1, STATE_SAVE_SIZE; /* MS: Clean up stack space */ | ||
859 | tovirt(r1,r1); | 868 | tovirt(r1,r1); |
860 | 6: | 869 | DBTRAP_return_kernel: /* MS: Make global symbol for debugging */ |
861 | DBTRAP_return: /* Make global symbol for debugging */ | 870 | rtbd r16, 0; /* MS: Instructions to return from a debug trap */ |
862 | rtbd r16, 0; /* Instructions to return from an IRQ */ | ||
863 | nop; | 871 | nop; |
864 | 872 | ||
865 | 873 | ||
diff --git a/arch/microblaze/kernel/exceptions.c b/arch/microblaze/kernel/exceptions.c index e0c6f8c2bd9d..b98ee8d0c1cd 100644 --- a/arch/microblaze/kernel/exceptions.c +++ b/arch/microblaze/kernel/exceptions.c | |||
@@ -59,7 +59,6 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) | |||
59 | siginfo_t info; | 59 | siginfo_t info; |
60 | 60 | ||
61 | if (kernel_mode(regs)) { | 61 | if (kernel_mode(regs)) { |
62 | debugger(regs); | ||
63 | die("Exception in kernel mode", regs, signr); | 62 | die("Exception in kernel mode", regs, signr); |
64 | } | 63 | } |
65 | info.si_signo = signr; | 64 | info.si_signo = signr; |
diff --git a/arch/microblaze/kernel/kgdb.c b/arch/microblaze/kernel/kgdb.c new file mode 100644 index 000000000000..bfc006b7f2d8 --- /dev/null +++ b/arch/microblaze/kernel/kgdb.c | |||
@@ -0,0 +1,147 @@ | |||
1 | /* | ||
2 | * Microblaze KGDB support | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file "COPYING" in the main directory of this archive | ||
6 | * for more details. | ||
7 | */ | ||
8 | |||
9 | #include <linux/kgdb.h> | ||
10 | #include <linux/kdebug.h> | ||
11 | #include <linux/irq.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <asm/cacheflush.h> | ||
14 | #include <asm/asm-offsets.h> | ||
15 | #include <asm/pvr.h> | ||
16 | |||
17 | #define GDB_REG 0 | ||
18 | #define GDB_PC 32 | ||
19 | #define GDB_MSR 33 | ||
20 | #define GDB_EAR 34 | ||
21 | #define GDB_ESR 35 | ||
22 | #define GDB_FSR 36 | ||
23 | #define GDB_BTR 37 | ||
24 | #define GDB_PVR 38 | ||
25 | #define GDB_REDR 50 | ||
26 | #define GDB_RPID 51 | ||
27 | #define GDB_RZPR 52 | ||
28 | #define GDB_RTLBX 53 | ||
29 | #define GDB_RTLBSX 54 /* mfs can't read it */ | ||
30 | #define GDB_RTLBLO 55 | ||
31 | #define GDB_RTLBHI 56 | ||
32 | |||
33 | /* keep pvr separately because it is unchangeble */ | ||
34 | struct pvr_s pvr; | ||
35 | |||
36 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
37 | { | ||
38 | int i; | ||
39 | unsigned long *pt_regb = (unsigned long *)regs; | ||
40 | int temp; | ||
41 | /* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */ | ||
42 | for (i = 0; i < (sizeof(struct pt_regs) / 4) - 1; i++) | ||
43 | gdb_regs[i] = pt_regb[i]; | ||
44 | |||
45 | /* Branch target register can't be changed */ | ||
46 | __asm__ __volatile__ ("mfs %0, rbtr;" : "=r"(temp) : ); | ||
47 | gdb_regs[GDB_BTR] = temp; | ||
48 | |||
49 | /* pvr part - we have 11 pvr regs */ | ||
50 | for (i = 0; i < sizeof(struct pvr_s)/4; i++) | ||
51 | gdb_regs[GDB_PVR + i] = pvr.pvr[i]; | ||
52 | |||
53 | /* read special registers - can't be changed */ | ||
54 | __asm__ __volatile__ ("mfs %0, redr;" : "=r"(temp) : ); | ||
55 | gdb_regs[GDB_REDR] = temp; | ||
56 | __asm__ __volatile__ ("mfs %0, rpid;" : "=r"(temp) : ); | ||
57 | gdb_regs[GDB_RPID] = temp; | ||
58 | __asm__ __volatile__ ("mfs %0, rzpr;" : "=r"(temp) : ); | ||
59 | gdb_regs[GDB_RZPR] = temp; | ||
60 | __asm__ __volatile__ ("mfs %0, rtlbx;" : "=r"(temp) : ); | ||
61 | gdb_regs[GDB_RTLBX] = temp; | ||
62 | __asm__ __volatile__ ("mfs %0, rtlblo;" : "=r"(temp) : ); | ||
63 | gdb_regs[GDB_RTLBLO] = temp; | ||
64 | __asm__ __volatile__ ("mfs %0, rtlbhi;" : "=r"(temp) : ); | ||
65 | gdb_regs[GDB_RTLBHI] = temp; | ||
66 | } | ||
67 | |||
68 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
69 | { | ||
70 | int i; | ||
71 | unsigned long *pt_regb = (unsigned long *)regs; | ||
72 | |||
73 | /* pt_regs and gdb_regs have the same 37 values. | ||
74 | * The rest of gdb_regs are unused and can't be changed. | ||
75 | * r0 register value can't be changed too. */ | ||
76 | for (i = 1; i < (sizeof(struct pt_regs) / 4) - 1; i++) | ||
77 | pt_regb[i] = gdb_regs[i]; | ||
78 | } | ||
79 | |||
80 | void microblaze_kgdb_break(struct pt_regs *regs) | ||
81 | { | ||
82 | if (kgdb_handle_exception(1, SIGTRAP, 0, regs) != 0) | ||
83 | return 0; | ||
84 | |||
85 | /* Jump over the first arch_kgdb_breakpoint which is barrier to | ||
86 | * get kgdb work. The same solution is used for powerpc */ | ||
87 | if (*(u32 *) (regs->pc) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr)) | ||
88 | regs->pc += BREAK_INSTR_SIZE; | ||
89 | } | ||
90 | |||
91 | /* untested */ | ||
92 | void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | ||
93 | { | ||
94 | int i; | ||
95 | unsigned long *pt_regb = (unsigned long *)(p->thread.regs); | ||
96 | |||
97 | /* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */ | ||
98 | for (i = 0; i < (sizeof(struct pt_regs) / 4) - 1; i++) | ||
99 | gdb_regs[i] = pt_regb[i]; | ||
100 | |||
101 | /* pvr part - we have 11 pvr regs */ | ||
102 | for (i = 0; i < sizeof(struct pvr_s)/4; i++) | ||
103 | gdb_regs[GDB_PVR + i] = pvr.pvr[i]; | ||
104 | } | ||
105 | |||
106 | void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip) | ||
107 | { | ||
108 | regs->pc = ip; | ||
109 | } | ||
110 | |||
111 | int kgdb_arch_handle_exception(int vector, int signo, int err_code, | ||
112 | char *remcom_in_buffer, char *remcom_out_buffer, | ||
113 | struct pt_regs *regs) | ||
114 | { | ||
115 | char *ptr; | ||
116 | unsigned long address; | ||
117 | int cpu = smp_processor_id(); | ||
118 | |||
119 | switch (remcom_in_buffer[0]) { | ||
120 | case 'c': | ||
121 | /* handle the optional parameter */ | ||
122 | ptr = &remcom_in_buffer[1]; | ||
123 | if (kgdb_hex2long(&ptr, &address)) | ||
124 | regs->pc = address; | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | return -1; /* this means that we do not want to exit from the handler */ | ||
129 | } | ||
130 | |||
131 | int kgdb_arch_init(void) | ||
132 | { | ||
133 | get_pvr(&pvr); /* Fill PVR structure */ | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | void kgdb_arch_exit(void) | ||
138 | { | ||
139 | /* Nothing to do */ | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * Global data | ||
144 | */ | ||
145 | struct kgdb_arch arch_kgdb_ops = { | ||
146 | .gdb_bpt_instr = {0xba, 0x0c, 0x00, 0x18}, /* brki r16, 0x18 */ | ||
147 | }; | ||
diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c index b224c650a18d..57bd2a09610c 100644 --- a/arch/microblaze/mm/fault.c +++ b/arch/microblaze/mm/fault.c | |||
@@ -37,10 +37,6 @@ | |||
37 | #include <linux/uaccess.h> | 37 | #include <linux/uaccess.h> |
38 | #include <asm/exceptions.h> | 38 | #include <asm/exceptions.h> |
39 | 39 | ||
40 | #if defined(CONFIG_KGDB) | ||
41 | int debugger_kernel_faults = 1; | ||
42 | #endif | ||
43 | |||
44 | static unsigned long pte_misses; /* updated by do_page_fault() */ | 40 | static unsigned long pte_misses; /* updated by do_page_fault() */ |
45 | static unsigned long pte_errors; /* updated by do_page_fault() */ | 41 | static unsigned long pte_errors; /* updated by do_page_fault() */ |
46 | 42 | ||
@@ -81,10 +77,6 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) | |||
81 | } | 77 | } |
82 | 78 | ||
83 | /* kernel has accessed a bad area */ | 79 | /* kernel has accessed a bad area */ |
84 | #if defined(CONFIG_KGDB) | ||
85 | if (debugger_kernel_faults) | ||
86 | debugger(regs); | ||
87 | #endif | ||
88 | die("kernel access of bad area", regs, sig); | 80 | die("kernel access of bad area", regs, sig); |
89 | } | 81 | } |
90 | 82 | ||
@@ -115,13 +107,6 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, | |||
115 | if ((error_code & 0x13) == 0x13 || (error_code & 0x11) == 0x11) | 107 | if ((error_code & 0x13) == 0x13 || (error_code & 0x11) == 0x11) |
116 | is_write = 0; | 108 | is_write = 0; |
117 | 109 | ||
118 | #if defined(CONFIG_KGDB) | ||
119 | if (debugger_fault_handler && regs->trap == 0x300) { | ||
120 | debugger_fault_handler(regs); | ||
121 | return; | ||
122 | } | ||
123 | #endif /* CONFIG_KGDB */ | ||
124 | |||
125 | if (unlikely(in_atomic() || !mm)) { | 110 | if (unlikely(in_atomic() || !mm)) { |
126 | if (kernel_mode(regs)) | 111 | if (kernel_mode(regs)) |
127 | goto bad_area_nosemaphore; | 112 | goto bad_area_nosemaphore; |