diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-24 13:07:50 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-24 13:07:50 -0400 |
| commit | 3dab04e6978e358ad2307bca563fabd6c5d2c58b (patch) | |
| tree | 893e9bc5041e7f722722fe13a3b145396f2554d8 | |
| parent | 6d1e9a42e7176bbce9348274784b2e5f69223936 (diff) | |
| parent | 5a4b65ab506398ba5a35c37e06edddd387cc0add (diff) | |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-2.6-mn10300
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-2.6-mn10300:
MN10300: gcc 4.6 vs am33 inline assembly
MN10300: Deprecate gdbstub
MN10300: Allow KGDB to use the MN10300 serial ports
MN10300: Emulate single stepping in KGDB on MN10300
MN10300: Generalise kernel debugger kernel halt, reboot or power off hook
KGDB: Notify GDB of machine halt, reboot or power off
MN10300: Use KGDB
MN10300: Create generic kernel debugger hooks
MN10300: Create general kernel debugger cache flushing
MN10300: Introduce a general config option for kernel debugger hooks
MN10300: The icache invalidate functions should disable the icache first
MN10300: gdbstub: Restrict single-stepping to non-preemptable non-SMP configs
39 files changed, 1924 insertions, 502 deletions
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig index 10971be43061..d8ab97a73db2 100644 --- a/arch/mn10300/Kconfig +++ b/arch/mn10300/Kconfig | |||
| @@ -3,6 +3,8 @@ config MN10300 | |||
| 3 | select HAVE_OPROFILE | 3 | select HAVE_OPROFILE |
| 4 | select HAVE_GENERIC_HARDIRQS | 4 | select HAVE_GENERIC_HARDIRQS |
| 5 | select GENERIC_HARDIRQS_NO_DEPRECATED | 5 | select GENERIC_HARDIRQS_NO_DEPRECATED |
| 6 | select HAVE_ARCH_TRACEHOOK | ||
| 7 | select HAVE_ARCH_KGDB | ||
| 6 | 8 | ||
| 7 | config AM33_2 | 9 | config AM33_2 |
| 8 | def_bool n | 10 | def_bool n |
| @@ -401,9 +403,9 @@ comment "[!] NOTE: A lower number/level indicates a higher priority (0 is highes | |||
| 401 | comment "____Non-maskable interrupt levels____" | 403 | comment "____Non-maskable interrupt levels____" |
| 402 | comment "The following must be set to a higher priority than local_irq_disable() and on-chip serial" | 404 | comment "The following must be set to a higher priority than local_irq_disable() and on-chip serial" |
| 403 | 405 | ||
| 404 | config GDBSTUB_IRQ_LEVEL | 406 | config DEBUGGER_IRQ_LEVEL |
| 405 | int "GDBSTUB interrupt priority" | 407 | int "DEBUGGER interrupt priority" |
| 406 | depends on GDBSTUB | 408 | depends on KERNEL_DEBUGGER |
| 407 | range 0 1 if LINUX_CLI_LEVEL = 2 | 409 | range 0 1 if LINUX_CLI_LEVEL = 2 |
| 408 | range 0 2 if LINUX_CLI_LEVEL = 3 | 410 | range 0 2 if LINUX_CLI_LEVEL = 3 |
| 409 | range 0 3 if LINUX_CLI_LEVEL = 4 | 411 | range 0 3 if LINUX_CLI_LEVEL = 4 |
| @@ -437,7 +439,7 @@ config LINUX_CLI_LEVEL | |||
| 437 | EPSW.IM from 7. Any interrupt is permitted for which the level is | 439 | EPSW.IM from 7. Any interrupt is permitted for which the level is |
| 438 | lower than EPSW.IM. | 440 | lower than EPSW.IM. |
| 439 | 441 | ||
| 440 | Certain interrupts, such as GDBSTUB and virtual MN10300 on-chip | 442 | Certain interrupts, such as DEBUGGER and virtual MN10300 on-chip |
| 441 | serial DMA interrupts are allowed to interrupt normal disabled | 443 | serial DMA interrupts are allowed to interrupt normal disabled |
| 442 | sections. | 444 | sections. |
| 443 | 445 | ||
diff --git a/arch/mn10300/Kconfig.debug b/arch/mn10300/Kconfig.debug index ce83c74b3fd7..bdbfd444a9ff 100644 --- a/arch/mn10300/Kconfig.debug +++ b/arch/mn10300/Kconfig.debug | |||
| @@ -36,7 +36,7 @@ config KPROBES | |||
| 36 | 36 | ||
| 37 | config GDBSTUB | 37 | config GDBSTUB |
| 38 | bool "Remote GDB kernel debugging" | 38 | bool "Remote GDB kernel debugging" |
| 39 | depends on DEBUG_KERNEL | 39 | depends on DEBUG_KERNEL && DEPRECATED |
| 40 | select DEBUG_INFO | 40 | select DEBUG_INFO |
| 41 | select FRAME_POINTER | 41 | select FRAME_POINTER |
| 42 | help | 42 | help |
| @@ -46,6 +46,9 @@ config GDBSTUB | |||
| 46 | RAM to avoid excessive linking time. This is only useful for kernel | 46 | RAM to avoid excessive linking time. This is only useful for kernel |
| 47 | hackers. If unsure, say N. | 47 | hackers. If unsure, say N. |
| 48 | 48 | ||
| 49 | This is deprecated in favour of KGDB and will be removed in a later | ||
| 50 | version. | ||
| 51 | |||
| 49 | config GDBSTUB_IMMEDIATE | 52 | config GDBSTUB_IMMEDIATE |
| 50 | bool "Break into GDB stub immediately" | 53 | bool "Break into GDB stub immediately" |
| 51 | depends on GDBSTUB | 54 | depends on GDBSTUB |
| @@ -54,6 +57,14 @@ config GDBSTUB_IMMEDIATE | |||
| 54 | possible, leaving the program counter at the beginning of | 57 | possible, leaving the program counter at the beginning of |
| 55 | start_kernel() in init/main.c. | 58 | start_kernel() in init/main.c. |
| 56 | 59 | ||
| 60 | config GDBSTUB_ALLOW_SINGLE_STEP | ||
| 61 | bool "Allow software single-stepping in GDB stub" | ||
| 62 | depends on GDBSTUB && !SMP && !PREEMPT | ||
| 63 | help | ||
| 64 | Allow GDB stub to perform software single-stepping through the | ||
| 65 | kernel. This doesn't work very well on SMP or preemptible kernels as | ||
| 66 | it uses temporary breakpoints to emulate single-stepping. | ||
| 67 | |||
| 57 | config GDB_CONSOLE | 68 | config GDB_CONSOLE |
| 58 | bool "Console output to GDB" | 69 | bool "Console output to GDB" |
| 59 | depends on GDBSTUB | 70 | depends on GDBSTUB |
| @@ -142,3 +153,7 @@ config GDBSTUB_ON_TTYSx | |||
| 142 | default y | 153 | default y |
| 143 | 154 | ||
| 144 | endmenu | 155 | endmenu |
| 156 | |||
| 157 | config KERNEL_DEBUGGER | ||
| 158 | def_bool y | ||
| 159 | depends on GDBSTUB || KGDB | ||
diff --git a/arch/mn10300/include/asm/debugger.h b/arch/mn10300/include/asm/debugger.h new file mode 100644 index 000000000000..e1d3b083696c --- /dev/null +++ b/arch/mn10300/include/asm/debugger.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | /* Kernel debugger for MN10300 | ||
| 2 | * | ||
| 3 | * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef _ASM_DEBUGGER_H | ||
| 13 | #define _ASM_DEBUGGER_H | ||
| 14 | |||
| 15 | #if defined(CONFIG_KERNEL_DEBUGGER) | ||
| 16 | |||
| 17 | extern int debugger_intercept(enum exception_code, int, int, struct pt_regs *); | ||
| 18 | extern int at_debugger_breakpoint(struct pt_regs *); | ||
| 19 | |||
| 20 | #ifndef CONFIG_MN10300_DEBUGGER_CACHE_NO_FLUSH | ||
| 21 | extern void debugger_local_cache_flushinv(void); | ||
| 22 | extern void debugger_local_cache_flushinv_one(u8 *); | ||
| 23 | #else | ||
| 24 | static inline void debugger_local_cache_flushinv(void) {} | ||
| 25 | static inline void debugger_local_cache_flushinv_one(u8 *addr) {} | ||
| 26 | #endif | ||
| 27 | |||
| 28 | #else /* CONFIG_KERNEL_DEBUGGER */ | ||
| 29 | |||
| 30 | static inline int debugger_intercept(enum exception_code excep, | ||
| 31 | int signo, int si_code, | ||
| 32 | struct pt_regs *regs) | ||
| 33 | { | ||
| 34 | return 0; | ||
| 35 | } | ||
| 36 | |||
| 37 | static inline int at_debugger_breakpoint(struct pt_regs *regs) | ||
| 38 | { | ||
| 39 | return 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | #endif /* CONFIG_KERNEL_DEBUGGER */ | ||
| 43 | #endif /* _ASM_DEBUGGER_H */ | ||
diff --git a/arch/mn10300/include/asm/div64.h b/arch/mn10300/include/asm/div64.h index 34dcb8e68309..503efab2a516 100644 --- a/arch/mn10300/include/asm/div64.h +++ b/arch/mn10300/include/asm/div64.h | |||
| @@ -16,6 +16,19 @@ | |||
| 16 | extern void ____unhandled_size_in_do_div___(void); | 16 | extern void ____unhandled_size_in_do_div___(void); |
| 17 | 17 | ||
| 18 | /* | 18 | /* |
| 19 | * Beginning with gcc 4.6, the MDR register is represented explicitly. We | ||
| 20 | * must, therefore, at least explicitly clobber the register when we make | ||
| 21 | * changes to it. The following assembly fragments *could* be rearranged in | ||
| 22 | * order to leave the moves to/from the MDR register to the compiler, but the | ||
| 23 | * gains would be minimal at best. | ||
| 24 | */ | ||
| 25 | #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) | ||
| 26 | # define CLOBBER_MDR_CC "mdr", "cc" | ||
| 27 | #else | ||
| 28 | # define CLOBBER_MDR_CC "cc" | ||
| 29 | #endif | ||
| 30 | |||
| 31 | /* | ||
| 19 | * divide n by base, leaving the result in n and returning the remainder | 32 | * divide n by base, leaving the result in n and returning the remainder |
| 20 | * - we can do this quite efficiently on the MN10300 by cascading the divides | 33 | * - we can do this quite efficiently on the MN10300 by cascading the divides |
| 21 | * through the MDR register | 34 | * through the MDR register |
| @@ -29,7 +42,7 @@ extern void ____unhandled_size_in_do_div___(void); | |||
| 29 | "mov mdr,%1 \n" \ | 42 | "mov mdr,%1 \n" \ |
| 30 | : "+r"(n), "=d"(__rem) \ | 43 | : "+r"(n), "=d"(__rem) \ |
| 31 | : "r"(base), "1"(__rem) \ | 44 | : "r"(base), "1"(__rem) \ |
| 32 | : "cc" \ | 45 | : CLOBBER_MDR_CC \ |
| 33 | ); \ | 46 | ); \ |
| 34 | } else if (sizeof(n) <= 8) { \ | 47 | } else if (sizeof(n) <= 8) { \ |
| 35 | union { \ | 48 | union { \ |
| @@ -48,7 +61,7 @@ extern void ____unhandled_size_in_do_div___(void); | |||
| 48 | : "=d"(__rem), "=r"(__quot.w[1]), "=r"(__quot.w[0]) \ | 61 | : "=d"(__rem), "=r"(__quot.w[1]), "=r"(__quot.w[0]) \ |
| 49 | : "r"(base), "0"(__rem), "1"(__quot.w[1]), \ | 62 | : "r"(base), "0"(__rem), "1"(__quot.w[1]), \ |
| 50 | "2"(__quot.w[0]) \ | 63 | "2"(__quot.w[0]) \ |
| 51 | : "cc" \ | 64 | : CLOBBER_MDR_CC \ |
| 52 | ); \ | 65 | ); \ |
| 53 | n = __quot.l; \ | 66 | n = __quot.l; \ |
| 54 | } else { \ | 67 | } else { \ |
| @@ -72,7 +85,7 @@ unsigned __muldiv64u(unsigned val, unsigned mult, unsigned div) | |||
| 72 | * MDR = MDR:val%div */ | 85 | * MDR = MDR:val%div */ |
| 73 | : "=r"(result) | 86 | : "=r"(result) |
| 74 | : "0"(val), "ir"(mult), "r"(div) | 87 | : "0"(val), "ir"(mult), "r"(div) |
| 75 | : "cc" | 88 | : CLOBBER_MDR_CC |
| 76 | ); | 89 | ); |
| 77 | 90 | ||
| 78 | return result; | 91 | return result; |
| @@ -93,7 +106,7 @@ signed __muldiv64s(signed val, signed mult, signed div) | |||
| 93 | * MDR = MDR:val%div */ | 106 | * MDR = MDR:val%div */ |
| 94 | : "=r"(result) | 107 | : "=r"(result) |
| 95 | : "0"(val), "ir"(mult), "r"(div) | 108 | : "0"(val), "ir"(mult), "r"(div) |
| 96 | : "cc" | 109 | : CLOBBER_MDR_CC |
| 97 | ); | 110 | ); |
| 98 | 111 | ||
| 99 | return result; | 112 | return result; |
diff --git a/arch/mn10300/include/asm/fpu.h b/arch/mn10300/include/asm/fpu.h index b7625de8eade..738ff72659d5 100644 --- a/arch/mn10300/include/asm/fpu.h +++ b/arch/mn10300/include/asm/fpu.h | |||
| @@ -55,7 +55,6 @@ static inline void clear_using_fpu(struct task_struct *tsk) | |||
| 55 | 55 | ||
| 56 | extern asmlinkage void fpu_kill_state(struct task_struct *); | 56 | extern asmlinkage void fpu_kill_state(struct task_struct *); |
| 57 | extern asmlinkage void fpu_exception(struct pt_regs *, enum exception_code); | 57 | extern asmlinkage void fpu_exception(struct pt_regs *, enum exception_code); |
| 58 | extern asmlinkage void fpu_invalid_op(struct pt_regs *, enum exception_code); | ||
| 59 | extern asmlinkage void fpu_init_state(void); | 58 | extern asmlinkage void fpu_init_state(void); |
| 60 | extern asmlinkage void fpu_save(struct fpu_state_struct *); | 59 | extern asmlinkage void fpu_save(struct fpu_state_struct *); |
| 61 | extern int fpu_setup_sigcontext(struct fpucontext *buf); | 60 | extern int fpu_setup_sigcontext(struct fpucontext *buf); |
| @@ -113,7 +112,6 @@ static inline void flush_fpu(void) | |||
| 113 | 112 | ||
| 114 | extern asmlinkage | 113 | extern asmlinkage |
| 115 | void unexpected_fpu_exception(struct pt_regs *, enum exception_code); | 114 | void unexpected_fpu_exception(struct pt_regs *, enum exception_code); |
| 116 | #define fpu_invalid_op unexpected_fpu_exception | ||
| 117 | #define fpu_exception unexpected_fpu_exception | 115 | #define fpu_exception unexpected_fpu_exception |
| 118 | 116 | ||
| 119 | struct task_struct; | 117 | struct task_struct; |
diff --git a/arch/mn10300/include/asm/irqflags.h b/arch/mn10300/include/asm/irqflags.h index 7a7ae12c7119..678f68d5f37b 100644 --- a/arch/mn10300/include/asm/irqflags.h +++ b/arch/mn10300/include/asm/irqflags.h | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | /* | 20 | /* |
| 21 | * interrupt control | 21 | * interrupt control |
| 22 | * - "disabled": run in IM1/2 | 22 | * - "disabled": run in IM1/2 |
| 23 | * - level 0 - GDB stub | 23 | * - level 0 - kernel debugger |
| 24 | * - level 1 - virtual serial DMA (if present) | 24 | * - level 1 - virtual serial DMA (if present) |
| 25 | * - level 5 - normal interrupt priority | 25 | * - level 5 - normal interrupt priority |
| 26 | * - level 6 - timer interrupt | 26 | * - level 6 - timer interrupt |
diff --git a/arch/mn10300/include/asm/kgdb.h b/arch/mn10300/include/asm/kgdb.h new file mode 100644 index 000000000000..eb245f18a708 --- /dev/null +++ b/arch/mn10300/include/asm/kgdb.h | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | /* Kernel debugger for MN10300 | ||
| 2 | * | ||
| 3 | * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef _ASM_KGDB_H | ||
| 13 | #define _ASM_KGDB_H | ||
| 14 | |||
| 15 | /* | ||
| 16 | * BUFMAX defines the maximum number of characters in inbound/outbound | ||
| 17 | * buffers at least NUMREGBYTES*2 are needed for register packets | ||
| 18 | * Longer buffer is needed to list all threads | ||
| 19 | */ | ||
| 20 | #define BUFMAX 1024 | ||
| 21 | |||
| 22 | /* | ||
| 23 | * Note that this register image is in a different order than the register | ||
| 24 | * image that Linux produces at interrupt time. | ||
| 25 | */ | ||
| 26 | enum regnames { | ||
| 27 | GDB_FR_D0 = 0, | ||
| 28 | GDB_FR_D1 = 1, | ||
| 29 | GDB_FR_D2 = 2, | ||
| 30 | GDB_FR_D3 = 3, | ||
| 31 | GDB_FR_A0 = 4, | ||
| 32 | GDB_FR_A1 = 5, | ||
| 33 | GDB_FR_A2 = 6, | ||
| 34 | GDB_FR_A3 = 7, | ||
| 35 | |||
| 36 | GDB_FR_SP = 8, | ||
| 37 | GDB_FR_PC = 9, | ||
| 38 | GDB_FR_MDR = 10, | ||
| 39 | GDB_FR_EPSW = 11, | ||
| 40 | GDB_FR_LIR = 12, | ||
| 41 | GDB_FR_LAR = 13, | ||
| 42 | GDB_FR_MDRQ = 14, | ||
| 43 | |||
| 44 | GDB_FR_E0 = 15, | ||
| 45 | GDB_FR_E1 = 16, | ||
| 46 | GDB_FR_E2 = 17, | ||
| 47 | GDB_FR_E3 = 18, | ||
| 48 | GDB_FR_E4 = 19, | ||
| 49 | GDB_FR_E5 = 20, | ||
| 50 | GDB_FR_E6 = 21, | ||
| 51 | GDB_FR_E7 = 22, | ||
| 52 | |||
| 53 | GDB_FR_SSP = 23, | ||
| 54 | GDB_FR_MSP = 24, | ||
| 55 | GDB_FR_USP = 25, | ||
| 56 | GDB_FR_MCRH = 26, | ||
| 57 | GDB_FR_MCRL = 27, | ||
| 58 | GDB_FR_MCVF = 28, | ||
| 59 | |||
| 60 | GDB_FR_FPCR = 29, | ||
| 61 | GDB_FR_DUMMY0 = 30, | ||
| 62 | GDB_FR_DUMMY1 = 31, | ||
| 63 | |||
| 64 | GDB_FR_FS0 = 32, | ||
| 65 | |||
| 66 | GDB_FR_SIZE = 64, | ||
| 67 | }; | ||
| 68 | |||
| 69 | #define GDB_ORIG_D0 41 | ||
| 70 | #define NUMREGBYTES (GDB_FR_SIZE*4) | ||
| 71 | |||
| 72 | static inline void arch_kgdb_breakpoint(void) | ||
| 73 | { | ||
| 74 | asm(".globl __arch_kgdb_breakpoint; __arch_kgdb_breakpoint: break"); | ||
| 75 | } | ||
| 76 | extern u8 __arch_kgdb_breakpoint; | ||
| 77 | |||
| 78 | #define BREAK_INSTR_SIZE 1 | ||
| 79 | #define CACHE_FLUSH_IS_SAFE 1 | ||
| 80 | |||
| 81 | #endif /* _ASM_KGDB_H */ | ||
diff --git a/arch/mn10300/include/asm/smp.h b/arch/mn10300/include/asm/smp.h index a3930e43a958..6745dbe64944 100644 --- a/arch/mn10300/include/asm/smp.h +++ b/arch/mn10300/include/asm/smp.h | |||
| @@ -34,7 +34,7 @@ | |||
| 34 | #define LOCAL_TIMER_IPI 193 | 34 | #define LOCAL_TIMER_IPI 193 |
| 35 | #define FLUSH_CACHE_IPI 194 | 35 | #define FLUSH_CACHE_IPI 194 |
| 36 | #define CALL_FUNCTION_NMI_IPI 195 | 36 | #define CALL_FUNCTION_NMI_IPI 195 |
| 37 | #define GDB_NMI_IPI 196 | 37 | #define DEBUGGER_NMI_IPI 196 |
| 38 | 38 | ||
| 39 | #define SMP_BOOT_IRQ 195 | 39 | #define SMP_BOOT_IRQ 195 |
| 40 | 40 | ||
| @@ -43,6 +43,7 @@ | |||
| 43 | #define LOCAL_TIMER_GxICR_LV GxICR_LEVEL_4 | 43 | #define LOCAL_TIMER_GxICR_LV GxICR_LEVEL_4 |
| 44 | #define FLUSH_CACHE_GxICR_LV GxICR_LEVEL_0 | 44 | #define FLUSH_CACHE_GxICR_LV GxICR_LEVEL_0 |
| 45 | #define SMP_BOOT_GxICR_LV GxICR_LEVEL_0 | 45 | #define SMP_BOOT_GxICR_LV GxICR_LEVEL_0 |
| 46 | #define DEBUGGER_GxICR_LV CONFIG_DEBUGGER_IRQ_LEVEL | ||
| 46 | 47 | ||
| 47 | #define TIME_OUT_COUNT_BOOT_IPI 100 | 48 | #define TIME_OUT_COUNT_BOOT_IPI 100 |
| 48 | #define DELAY_TIME_BOOT_IPI 75000 | 49 | #define DELAY_TIME_BOOT_IPI 75000 |
| @@ -61,8 +62,9 @@ | |||
| 61 | * An alternate way of dealing with this could be to use the EPSW.S bits to | 62 | * An alternate way of dealing with this could be to use the EPSW.S bits to |
| 62 | * cache this information for systems with up to four CPUs. | 63 | * cache this information for systems with up to four CPUs. |
| 63 | */ | 64 | */ |
| 65 | #define arch_smp_processor_id() (CPUID) | ||
| 64 | #if 0 | 66 | #if 0 |
| 65 | #define raw_smp_processor_id() (CPUID) | 67 | #define raw_smp_processor_id() (arch_smp_processor_id()) |
| 66 | #else | 68 | #else |
| 67 | #define raw_smp_processor_id() (current_thread_info()->cpu) | 69 | #define raw_smp_processor_id() (current_thread_info()->cpu) |
| 68 | #endif | 70 | #endif |
diff --git a/arch/mn10300/include/asm/thread_info.h b/arch/mn10300/include/asm/thread_info.h index 8d53f09c878d..87c213002d4c 100644 --- a/arch/mn10300/include/asm/thread_info.h +++ b/arch/mn10300/include/asm/thread_info.h | |||
| @@ -131,7 +131,11 @@ static inline unsigned long current_stack_pointer(void) | |||
| 131 | kmalloc_node(THREAD_SIZE, GFP_KERNEL, node) | 131 | kmalloc_node(THREAD_SIZE, GFP_KERNEL, node) |
| 132 | #endif | 132 | #endif |
| 133 | 133 | ||
| 134 | #ifndef CONFIG_KGDB | ||
| 134 | #define free_thread_info(ti) kfree((ti)) | 135 | #define free_thread_info(ti) kfree((ti)) |
| 136 | #else | ||
| 137 | extern void free_thread_info(struct thread_info *); | ||
| 138 | #endif | ||
| 135 | #define get_thread_info(ti) get_task_struct((ti)->task) | 139 | #define get_thread_info(ti) get_task_struct((ti)->task) |
| 136 | #define put_thread_info(ti) put_task_struct((ti)->task) | 140 | #define put_thread_info(ti) put_task_struct((ti)->task) |
| 137 | 141 | ||
diff --git a/arch/mn10300/kernel/Makefile b/arch/mn10300/kernel/Makefile index a06a2e10051d..47ed30fe8178 100644 --- a/arch/mn10300/kernel/Makefile +++ b/arch/mn10300/kernel/Makefile | |||
| @@ -21,11 +21,8 @@ obj-$(CONFIG_GDBSTUB) += gdb-stub.o gdb-low.o | |||
| 21 | obj-$(CONFIG_GDBSTUB_ON_TTYSx) += gdb-io-serial.o gdb-io-serial-low.o | 21 | obj-$(CONFIG_GDBSTUB_ON_TTYSx) += gdb-io-serial.o gdb-io-serial-low.o |
| 22 | obj-$(CONFIG_GDBSTUB_ON_TTYSMx) += gdb-io-ttysm.o gdb-io-ttysm-low.o | 22 | obj-$(CONFIG_GDBSTUB_ON_TTYSMx) += gdb-io-ttysm.o gdb-io-ttysm-low.o |
| 23 | 23 | ||
| 24 | ifeq ($(CONFIG_MN10300_CACHE_ENABLED),y) | ||
| 25 | obj-$(CONFIG_GDBSTUB) += gdb-cache.o | ||
| 26 | endif | ||
| 27 | |||
| 28 | obj-$(CONFIG_MN10300_RTC) += rtc.o | 24 | obj-$(CONFIG_MN10300_RTC) += rtc.o |
| 29 | obj-$(CONFIG_PROFILE) += profile.o profile-low.o | 25 | obj-$(CONFIG_PROFILE) += profile.o profile-low.o |
| 30 | obj-$(CONFIG_MODULES) += module.o | 26 | obj-$(CONFIG_MODULES) += module.o |
| 31 | obj-$(CONFIG_KPROBES) += kprobes.o | 27 | obj-$(CONFIG_KPROBES) += kprobes.o |
| 28 | obj-$(CONFIG_KGDB) += kgdb.o | ||
diff --git a/arch/mn10300/kernel/entry.S b/arch/mn10300/kernel/entry.S index f00b9bafcd3e..fb93ad720b82 100644 --- a/arch/mn10300/kernel/entry.S +++ b/arch/mn10300/kernel/entry.S | |||
| @@ -266,7 +266,11 @@ ENTRY(raw_bus_error) | |||
| 266 | 266 | ||
| 267 | ############################################################################### | 267 | ############################################################################### |
| 268 | # | 268 | # |
| 269 | # Miscellaneous exception entry points | 269 | # NMI exception entry points |
| 270 | # | ||
| 271 | # This is used by ordinary interrupt channels that have the GxICR_NMI bit set | ||
| 272 | # in addition to the main NMI and Watchdog channels. SMP NMI IPIs use this | ||
| 273 | # facility. | ||
| 270 | # | 274 | # |
| 271 | ############################################################################### | 275 | ############################################################################### |
| 272 | ENTRY(nmi_handler) | 276 | ENTRY(nmi_handler) |
| @@ -281,7 +285,7 @@ ENTRY(nmi_handler) | |||
| 281 | and NMIAGR_GN,d0 | 285 | and NMIAGR_GN,d0 |
| 282 | lsr 0x2,d0 | 286 | lsr 0x2,d0 |
| 283 | cmp CALL_FUNCTION_NMI_IPI,d0 | 287 | cmp CALL_FUNCTION_NMI_IPI,d0 |
| 284 | bne 5f # if not call function, jump | 288 | bne nmi_not_smp_callfunc # if not call function, jump |
| 285 | 289 | ||
| 286 | # function call nmi ipi | 290 | # function call nmi ipi |
| 287 | add 4,sp # no need to store TBR | 291 | add 4,sp # no need to store TBR |
| @@ -295,59 +299,38 @@ ENTRY(nmi_handler) | |||
| 295 | call smp_nmi_call_function_interrupt[],0 | 299 | call smp_nmi_call_function_interrupt[],0 |
| 296 | RESTORE_ALL | 300 | RESTORE_ALL |
| 297 | 301 | ||
| 298 | 5: | 302 | nmi_not_smp_callfunc: |
| 299 | #ifdef CONFIG_GDBSTUB | 303 | #ifdef CONFIG_KERNEL_DEBUGGER |
| 300 | cmp GDB_NMI_IPI,d0 | 304 | cmp DEBUGGER_NMI_IPI,d0 |
| 301 | bne 3f # if not gdb nmi ipi, jump | 305 | bne nmi_not_debugger # if not kernel debugger NMI IPI, jump |
| 302 | 306 | ||
| 303 | # gdb nmi ipi | 307 | # kernel debugger NMI IPI |
| 304 | add 4,sp # no need to store TBR | 308 | add 4,sp # no need to store TBR |
| 305 | mov GxICR_DETECT,d0 # clear NMI | 309 | mov GxICR_DETECT,d0 # clear NMI |
| 306 | movbu d0,(GxICR(GDB_NMI_IPI)) | 310 | movbu d0,(GxICR(DEBUGGER_NMI_IPI)) |
| 307 | movhu (GxICR(GDB_NMI_IPI)),d0 | 311 | movhu (GxICR(DEBUGGER_NMI_IPI)),d0 |
| 308 | and ~EPSW_NMID,epsw # enable NMI | 312 | and ~EPSW_NMID,epsw # enable NMI |
| 309 | #ifdef CONFIG_MN10300_CACHE_ENABLED | 313 | |
| 310 | mov (gdbstub_nmi_opr_type),d0 | ||
| 311 | cmp GDBSTUB_NMI_CACHE_PURGE,d0 | ||
| 312 | bne 4f # if not gdb cache purge, jump | ||
| 313 | |||
| 314 | # gdb cache purge nmi ipi | ||
| 315 | add -20,sp | ||
| 316 | mov d1,(4,sp) | ||
| 317 | mov a0,(8,sp) | ||
| 318 | mov a1,(12,sp) | ||
| 319 | mov mdr,d0 | ||
| 320 | mov d0,(16,sp) | ||
| 321 | call gdbstub_local_purge_cache[],0 | ||
| 322 | mov 0x1,d0 | ||
| 323 | mov (CPUID),d1 | ||
| 324 | asl d1,d0 | ||
| 325 | mov gdbstub_nmi_cpumask,a0 | ||
| 326 | bclr d0,(a0) | ||
| 327 | mov (4,sp),d1 | ||
| 328 | mov (8,sp),a0 | ||
| 329 | mov (12,sp),a1 | ||
| 330 | mov (16,sp),d0 | ||
| 331 | mov d0,mdr | ||
| 332 | add 20,sp | ||
| 333 | mov (sp),d0 | ||
| 334 | add 4,sp | ||
| 335 | rti | ||
| 336 | 4: | ||
| 337 | #endif /* CONFIG_MN10300_CACHE_ENABLED */ | ||
| 338 | # gdb wait nmi ipi | ||
| 339 | mov (sp),d0 | 314 | mov (sp),d0 |
| 340 | SAVE_ALL | 315 | SAVE_ALL |
| 341 | call gdbstub_nmi_wait[],0 | 316 | mov fp,d0 # arg 0: stacked register file |
| 317 | mov a2,d1 # arg 1: exception number | ||
| 318 | call debugger_nmi_interrupt[],0 | ||
| 342 | RESTORE_ALL | 319 | RESTORE_ALL |
| 343 | 3: | 320 | |
| 344 | #endif /* CONFIG_GDBSTUB */ | 321 | nmi_not_debugger: |
| 322 | #endif /* CONFIG_KERNEL_DEBUGGER */ | ||
| 345 | mov (sp),d0 # restore TBR to d0 | 323 | mov (sp),d0 # restore TBR to d0 |
| 346 | add 4,sp | 324 | add 4,sp |
| 347 | #endif /* CONFIG_SMP */ | 325 | #endif /* CONFIG_SMP */ |
| 348 | 326 | ||
| 349 | bra __common_exception_nonmi | 327 | bra __common_exception_nonmi |
| 350 | 328 | ||
| 329 | ############################################################################### | ||
| 330 | # | ||
| 331 | # General exception entry point | ||
| 332 | # | ||
| 333 | ############################################################################### | ||
| 351 | ENTRY(__common_exception) | 334 | ENTRY(__common_exception) |
| 352 | add -4,sp | 335 | add -4,sp |
| 353 | mov d0,(sp) | 336 | mov d0,(sp) |
diff --git a/arch/mn10300/kernel/fpu.c b/arch/mn10300/kernel/fpu.c index 5f9c3fa19a85..bb5fa7df6c44 100644 --- a/arch/mn10300/kernel/fpu.c +++ b/arch/mn10300/kernel/fpu.c | |||
| @@ -70,24 +70,6 @@ asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code) | |||
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | /* | 72 | /* |
| 73 | * handle an FPU invalid_op exception | ||
| 74 | * - Derived from DO_EINFO() macro in arch/mn10300/kernel/traps.c | ||
| 75 | */ | ||
| 76 | asmlinkage void fpu_invalid_op(struct pt_regs *regs, enum exception_code code) | ||
| 77 | { | ||
| 78 | siginfo_t info; | ||
| 79 | |||
| 80 | if (!user_mode(regs)) | ||
| 81 | die_if_no_fixup("FPU invalid opcode", regs, code); | ||
| 82 | |||
| 83 | info.si_signo = SIGILL; | ||
| 84 | info.si_errno = 0; | ||
| 85 | info.si_code = ILL_COPROC; | ||
| 86 | info.si_addr = (void *) regs->pc; | ||
| 87 | force_sig_info(info.si_signo, &info, current); | ||
| 88 | } | ||
| 89 | |||
| 90 | /* | ||
| 91 | * save the FPU state to a signal context | 73 | * save the FPU state to a signal context |
| 92 | */ | 74 | */ |
| 93 | int fpu_setup_sigcontext(struct fpucontext *fpucontext) | 75 | int fpu_setup_sigcontext(struct fpucontext *fpucontext) |
diff --git a/arch/mn10300/kernel/gdb-cache.S b/arch/mn10300/kernel/gdb-cache.S deleted file mode 100644 index 1108badc3d32..000000000000 --- a/arch/mn10300/kernel/gdb-cache.S +++ /dev/null | |||
| @@ -1,105 +0,0 @@ | |||
| 1 | ############################################################################### | ||
| 2 | # | ||
| 3 | # MN10300 Low-level cache purging routines for gdbstub | ||
| 4 | # | ||
| 5 | # Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | ||
| 6 | # Written by David Howells (dhowells@redhat.com) | ||
| 7 | # | ||
| 8 | # This program is free software; you can redistribute it and/or | ||
| 9 | # modify it under the terms of the GNU General Public Licence | ||
| 10 | # as published by the Free Software Foundation; either version | ||
| 11 | # 2 of the Licence, or (at your option) any later version. | ||
| 12 | # | ||
| 13 | ############################################################################### | ||
| 14 | #include <linux/sys.h> | ||
| 15 | #include <linux/linkage.h> | ||
| 16 | #include <asm/smp.h> | ||
| 17 | #include <asm/cache.h> | ||
| 18 | #include <asm/cpu-regs.h> | ||
| 19 | #include <asm/exceptions.h> | ||
| 20 | #include <asm/frame.inc> | ||
| 21 | #include <asm/serial-regs.h> | ||
| 22 | |||
| 23 | .text | ||
| 24 | |||
| 25 | ############################################################################### | ||
| 26 | # | ||
| 27 | # GDB stub cache purge | ||
| 28 | # | ||
| 29 | ############################################################################### | ||
| 30 | .type gdbstub_purge_cache,@function | ||
| 31 | ENTRY(gdbstub_purge_cache) | ||
| 32 | ####################################################################### | ||
| 33 | # read the addresses tagged in the cache's tag RAM and attempt to flush | ||
| 34 | # those addresses specifically | ||
| 35 | # - we rely on the hardware to filter out invalid tag entry addresses | ||
| 36 | mov DCACHE_TAG(0,0),a0 # dcache tag RAM access address | ||
| 37 | mov DCACHE_PURGE(0,0),a1 # dcache purge request address | ||
| 38 | mov L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1 # total number of entries | ||
| 39 | |||
| 40 | mn10300_dcache_flush_loop: | ||
| 41 | mov (a0),d0 | ||
| 42 | and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 | ||
| 43 | or L1_CACHE_TAG_VALID,d0 # retain valid entries in the | ||
| 44 | # cache | ||
| 45 | mov d0,(a1) # conditional purge | ||
| 46 | |||
| 47 | mn10300_dcache_flush_skip: | ||
| 48 | add L1_CACHE_BYTES,a0 | ||
| 49 | add L1_CACHE_BYTES,a1 | ||
| 50 | add -1,d1 | ||
| 51 | bne mn10300_dcache_flush_loop | ||
| 52 | |||
| 53 | ;; # unconditionally flush and invalidate the dcache | ||
| 54 | ;; mov DCACHE_PURGE(0,0),a1 # dcache purge request address | ||
| 55 | ;; mov L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1 # total number of | ||
| 56 | ;; # entries | ||
| 57 | ;; | ||
| 58 | ;; gdbstub_purge_cache__dcache_loop: | ||
| 59 | ;; mov (a1),d0 # unconditional purge | ||
| 60 | ;; | ||
| 61 | ;; add L1_CACHE_BYTES,a1 | ||
| 62 | ;; add -1,d1 | ||
| 63 | ;; bne gdbstub_purge_cache__dcache_loop | ||
| 64 | |||
| 65 | ####################################################################### | ||
| 66 | # now invalidate the icache | ||
| 67 | mov CHCTR,a0 | ||
| 68 | movhu (a0),a1 | ||
| 69 | |||
| 70 | mov epsw,d1 | ||
| 71 | and ~EPSW_IE,epsw | ||
| 72 | nop | ||
| 73 | nop | ||
| 74 | |||
| 75 | # disable the icache | ||
| 76 | and ~CHCTR_ICEN,d0 | ||
| 77 | movhu d0,(a0) | ||
| 78 | |||
| 79 | # and wait for it to calm down | ||
| 80 | setlb | ||
| 81 | movhu (a0),d0 | ||
| 82 | btst CHCTR_ICBUSY,d0 | ||
| 83 | lne | ||
| 84 | |||
| 85 | # invalidate | ||
| 86 | or CHCTR_ICINV,d0 | ||
| 87 | movhu d0,(a0) | ||
| 88 | |||
| 89 | # wait for the cache to finish | ||
| 90 | mov CHCTR,a0 | ||
| 91 | setlb | ||
| 92 | movhu (a0),d0 | ||
| 93 | btst CHCTR_ICBUSY,d0 | ||
| 94 | lne | ||
| 95 | |||
| 96 | # and reenable it | ||
| 97 | movhu a1,(a0) | ||
| 98 | movhu (a0),d0 # read back to flush | ||
| 99 | # (SIGILLs all over without this) | ||
| 100 | |||
| 101 | mov d1,epsw | ||
| 102 | |||
| 103 | ret [],0 | ||
| 104 | |||
| 105 | .size gdbstub_purge_cache,.-gdbstub_purge_cache | ||
diff --git a/arch/mn10300/kernel/gdb-io-ttysm.c b/arch/mn10300/kernel/gdb-io-ttysm.c index abdeea153c89..c859cacbb9c3 100644 --- a/arch/mn10300/kernel/gdb-io-ttysm.c +++ b/arch/mn10300/kernel/gdb-io-ttysm.c | |||
| @@ -59,10 +59,10 @@ void __init gdbstub_io_init(void) | |||
| 59 | 59 | ||
| 60 | /* we want to get serial receive interrupts */ | 60 | /* we want to get serial receive interrupts */ |
| 61 | set_intr_level(gdbstub_port->rx_irq, | 61 | set_intr_level(gdbstub_port->rx_irq, |
| 62 | NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL)); | 62 | NUM2GxICR_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL)); |
| 63 | set_intr_level(gdbstub_port->tx_irq, | 63 | set_intr_level(gdbstub_port->tx_irq, |
| 64 | NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL)); | 64 | NUM2GxICR_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL)); |
| 65 | set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL), | 65 | set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL), |
| 66 | gdbstub_io_rx_handler); | 66 | gdbstub_io_rx_handler); |
| 67 | 67 | ||
| 68 | *gdbstub_port->rx_icr |= GxICR_ENABLE; | 68 | *gdbstub_port->rx_icr |= GxICR_ENABLE; |
| @@ -88,7 +88,7 @@ void __init gdbstub_io_init(void) | |||
| 88 | 88 | ||
| 89 | /* permit level 0 IRQs only */ | 89 | /* permit level 0 IRQs only */ |
| 90 | arch_local_change_intr_mask_level( | 90 | arch_local_change_intr_mask_level( |
| 91 | NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1)); | 91 | NUM2EPSW_IM(CONFIG_DEBUGGER_IRQ_LEVEL + 1)); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | /* | 94 | /* |
diff --git a/arch/mn10300/kernel/gdb-stub.c b/arch/mn10300/kernel/gdb-stub.c index b169d99d9f20..538266b2c9bc 100644 --- a/arch/mn10300/kernel/gdb-stub.c +++ b/arch/mn10300/kernel/gdb-stub.c | |||
| @@ -133,7 +133,7 @@ | |||
| 133 | #include <asm/system.h> | 133 | #include <asm/system.h> |
| 134 | #include <asm/gdb-stub.h> | 134 | #include <asm/gdb-stub.h> |
| 135 | #include <asm/exceptions.h> | 135 | #include <asm/exceptions.h> |
| 136 | #include <asm/cacheflush.h> | 136 | #include <asm/debugger.h> |
| 137 | #include <asm/serial-regs.h> | 137 | #include <asm/serial-regs.h> |
| 138 | #include <asm/busctl-regs.h> | 138 | #include <asm/busctl-regs.h> |
| 139 | #include <unit/leds.h> | 139 | #include <unit/leds.h> |
| @@ -405,6 +405,7 @@ static int hexToInt(char **ptr, int *intValue) | |||
| 405 | return (numChars); | 405 | return (numChars); |
| 406 | } | 406 | } |
| 407 | 407 | ||
| 408 | #ifdef CONFIG_GDBSTUB_ALLOW_SINGLE_STEP | ||
| 408 | /* | 409 | /* |
| 409 | * We single-step by setting breakpoints. When an exception | 410 | * We single-step by setting breakpoints. When an exception |
| 410 | * is handled, we need to restore the instructions hoisted | 411 | * is handled, we need to restore the instructions hoisted |
| @@ -729,6 +730,7 @@ static int gdbstub_single_step(struct pt_regs *regs) | |||
| 729 | __gdbstub_restore_bp(); | 730 | __gdbstub_restore_bp(); |
| 730 | return -EFAULT; | 731 | return -EFAULT; |
| 731 | } | 732 | } |
| 733 | #endif /* CONFIG_GDBSTUB_ALLOW_SINGLE_STEP */ | ||
| 732 | 734 | ||
| 733 | #ifdef CONFIG_GDBSTUB_CONSOLE | 735 | #ifdef CONFIG_GDBSTUB_CONSOLE |
| 734 | 736 | ||
| @@ -1171,7 +1173,7 @@ int gdbstub_clear_breakpoint(u8 *addr, int len) | |||
| 1171 | 1173 | ||
| 1172 | /* | 1174 | /* |
| 1173 | * This function does all command processing for interfacing to gdb | 1175 | * This function does all command processing for interfacing to gdb |
| 1174 | * - returns 1 if the exception should be skipped, 0 otherwise. | 1176 | * - returns 0 if the exception should be skipped, -ERROR otherwise. |
| 1175 | */ | 1177 | */ |
| 1176 | static int gdbstub(struct pt_regs *regs, enum exception_code excep) | 1178 | static int gdbstub(struct pt_regs *regs, enum exception_code excep) |
| 1177 | { | 1179 | { |
| @@ -1186,7 +1188,7 @@ static int gdbstub(struct pt_regs *regs, enum exception_code excep) | |||
| 1186 | int loop; | 1188 | int loop; |
| 1187 | 1189 | ||
| 1188 | if (excep == EXCEP_FPU_DISABLED) | 1190 | if (excep == EXCEP_FPU_DISABLED) |
| 1189 | return 0; | 1191 | return -ENOTSUPP; |
| 1190 | 1192 | ||
| 1191 | gdbstub_flush_caches = 0; | 1193 | gdbstub_flush_caches = 0; |
| 1192 | 1194 | ||
| @@ -1195,7 +1197,7 @@ static int gdbstub(struct pt_regs *regs, enum exception_code excep) | |||
| 1195 | asm volatile("mov mdr,%0" : "=d"(mdr)); | 1197 | asm volatile("mov mdr,%0" : "=d"(mdr)); |
| 1196 | local_save_flags(epsw); | 1198 | local_save_flags(epsw); |
| 1197 | arch_local_change_intr_mask_level( | 1199 | arch_local_change_intr_mask_level( |
| 1198 | NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1)); | 1200 | NUM2EPSW_IM(CONFIG_DEBUGGER_IRQ_LEVEL + 1)); |
| 1199 | 1201 | ||
| 1200 | gdbstub_store_fpu(); | 1202 | gdbstub_store_fpu(); |
| 1201 | 1203 | ||
| @@ -1208,11 +1210,13 @@ static int gdbstub(struct pt_regs *regs, enum exception_code excep) | |||
| 1208 | /* if we were single stepping, restore the opcodes hoisted for the | 1210 | /* if we were single stepping, restore the opcodes hoisted for the |
| 1209 | * breakpoint[s] */ | 1211 | * breakpoint[s] */ |
| 1210 | broke = 0; | 1212 | broke = 0; |
| 1213 | #ifdef CONFIG_GDBSTUB_ALLOW_SINGLE_STEP | ||
| 1211 | if ((step_bp[0].addr && step_bp[0].addr == (u8 *) regs->pc) || | 1214 | if ((step_bp[0].addr && step_bp[0].addr == (u8 *) regs->pc) || |
| 1212 | (step_bp[1].addr && step_bp[1].addr == (u8 *) regs->pc)) | 1215 | (step_bp[1].addr && step_bp[1].addr == (u8 *) regs->pc)) |
| 1213 | broke = 1; | 1216 | broke = 1; |
| 1214 | 1217 | ||
| 1215 | __gdbstub_restore_bp(); | 1218 | __gdbstub_restore_bp(); |
| 1219 | #endif | ||
| 1216 | 1220 | ||
| 1217 | if (gdbstub_rx_unget) { | 1221 | if (gdbstub_rx_unget) { |
| 1218 | sigval = SIGINT; | 1222 | sigval = SIGINT; |
| @@ -1548,17 +1552,21 @@ packet_waiting: | |||
| 1548 | * Step to next instruction | 1552 | * Step to next instruction |
| 1549 | */ | 1553 | */ |
| 1550 | case 's': | 1554 | case 's': |
| 1551 | /* | 1555 | /* Using the T flag doesn't seem to perform single |
| 1552 | * using the T flag doesn't seem to perform single | ||
| 1553 | * stepping (it seems to wind up being caught by the | 1556 | * stepping (it seems to wind up being caught by the |
| 1554 | * JTAG unit), so we have to use breakpoints and | 1557 | * JTAG unit), so we have to use breakpoints and |
| 1555 | * continue instead. | 1558 | * continue instead. |
| 1556 | */ | 1559 | */ |
| 1560 | #ifdef CONFIG_GDBSTUB_ALLOW_SINGLE_STEP | ||
| 1557 | if (gdbstub_single_step(regs) < 0) | 1561 | if (gdbstub_single_step(regs) < 0) |
| 1558 | /* ignore any fault error for now */ | 1562 | /* ignore any fault error for now */ |
| 1559 | gdbstub_printk("unable to set single-step" | 1563 | gdbstub_printk("unable to set single-step" |
| 1560 | " bp\n"); | 1564 | " bp\n"); |
| 1561 | goto done; | 1565 | goto done; |
| 1566 | #else | ||
| 1567 | gdbstub_strcpy(output_buffer, "E01"); | ||
| 1568 | break; | ||
| 1569 | #endif | ||
| 1562 | 1570 | ||
| 1563 | /* | 1571 | /* |
| 1564 | * Set baud rate (bBB) | 1572 | * Set baud rate (bBB) |
| @@ -1657,7 +1665,7 @@ done: | |||
| 1657 | * NB: We flush both caches, just to be sure... | 1665 | * NB: We flush both caches, just to be sure... |
| 1658 | */ | 1666 | */ |
| 1659 | if (gdbstub_flush_caches) | 1667 | if (gdbstub_flush_caches) |
| 1660 | gdbstub_purge_cache(); | 1668 | debugger_local_cache_flushinv(); |
| 1661 | 1669 | ||
| 1662 | gdbstub_load_fpu(); | 1670 | gdbstub_load_fpu(); |
| 1663 | mn10300_set_gdbleds(0); | 1671 | mn10300_set_gdbleds(0); |
| @@ -1667,14 +1675,23 @@ done: | |||
| 1667 | touch_softlockup_watchdog(); | 1675 | touch_softlockup_watchdog(); |
| 1668 | 1676 | ||
| 1669 | local_irq_restore(epsw); | 1677 | local_irq_restore(epsw); |
| 1670 | return 1; | 1678 | return 0; |
| 1679 | } | ||
| 1680 | |||
| 1681 | /* | ||
| 1682 | * Determine if we hit a debugger special breakpoint that needs skipping over | ||
| 1683 | * automatically. | ||
| 1684 | */ | ||
| 1685 | int at_debugger_breakpoint(struct pt_regs *regs) | ||
| 1686 | { | ||
| 1687 | return 0; | ||
| 1671 | } | 1688 | } |
| 1672 | 1689 | ||
| 1673 | /* | 1690 | /* |
| 1674 | * handle event interception | 1691 | * handle event interception |
| 1675 | */ | 1692 | */ |
| 1676 | asmlinkage int gdbstub_intercept(struct pt_regs *regs, | 1693 | asmlinkage int debugger_intercept(enum exception_code excep, |
| 1677 | enum exception_code excep) | 1694 | int signo, int si_code, struct pt_regs *regs) |
| 1678 | { | 1695 | { |
| 1679 | static u8 notfirst = 1; | 1696 | static u8 notfirst = 1; |
| 1680 | int ret; | 1697 | int ret; |
| @@ -1688,7 +1705,7 @@ asmlinkage int gdbstub_intercept(struct pt_regs *regs, | |||
| 1688 | asm("mov mdr,%0" : "=d"(mdr)); | 1705 | asm("mov mdr,%0" : "=d"(mdr)); |
| 1689 | 1706 | ||
| 1690 | gdbstub_entry( | 1707 | gdbstub_entry( |
| 1691 | "--> gdbstub_intercept(%p,%04x) [MDR=%lx PC=%lx]\n", | 1708 | "--> debugger_intercept(%p,%04x) [MDR=%lx PC=%lx]\n", |
| 1692 | regs, excep, mdr, regs->pc); | 1709 | regs, excep, mdr, regs->pc); |
| 1693 | 1710 | ||
| 1694 | gdbstub_entry( | 1711 | gdbstub_entry( |
| @@ -1722,7 +1739,7 @@ asmlinkage int gdbstub_intercept(struct pt_regs *regs, | |||
| 1722 | 1739 | ||
| 1723 | ret = gdbstub(regs, excep); | 1740 | ret = gdbstub(regs, excep); |
| 1724 | 1741 | ||
| 1725 | gdbstub_entry("<-- gdbstub_intercept()\n"); | 1742 | gdbstub_entry("<-- debugger_intercept()\n"); |
| 1726 | gdbstub_busy = 0; | 1743 | gdbstub_busy = 0; |
| 1727 | return ret; | 1744 | return ret; |
| 1728 | } | 1745 | } |
diff --git a/arch/mn10300/kernel/internal.h b/arch/mn10300/kernel/internal.h index ea946613f46d..a5ac755dd69f 100644 --- a/arch/mn10300/kernel/internal.h +++ b/arch/mn10300/kernel/internal.h | |||
| @@ -30,6 +30,13 @@ extern void mn10300_low_ipi_handler(void); | |||
| 30 | #endif | 30 | #endif |
| 31 | 31 | ||
| 32 | /* | 32 | /* |
| 33 | * smp.c | ||
| 34 | */ | ||
| 35 | #ifdef CONFIG_SMP | ||
| 36 | extern void smp_jump_to_debugger(void); | ||
| 37 | #endif | ||
| 38 | |||
| 39 | /* | ||
| 33 | * time.c | 40 | * time.c |
| 34 | */ | 41 | */ |
| 35 | extern irqreturn_t local_timer_interrupt(void); | 42 | extern irqreturn_t local_timer_interrupt(void); |
diff --git a/arch/mn10300/kernel/irq.c b/arch/mn10300/kernel/irq.c index f09fed5e6afc..5f7fc3eb45e6 100644 --- a/arch/mn10300/kernel/irq.c +++ b/arch/mn10300/kernel/irq.c | |||
| @@ -153,7 +153,7 @@ mn10300_cpupic_setaffinity(struct irq_data *d, const struct cpumask *mask, | |||
| 153 | case LOCAL_TIMER_IPI: | 153 | case LOCAL_TIMER_IPI: |
| 154 | case FLUSH_CACHE_IPI: | 154 | case FLUSH_CACHE_IPI: |
| 155 | case CALL_FUNCTION_NMI_IPI: | 155 | case CALL_FUNCTION_NMI_IPI: |
| 156 | case GDB_NMI_IPI: | 156 | case DEBUGGER_NMI_IPI: |
| 157 | #ifdef CONFIG_MN10300_TTYSM0 | 157 | #ifdef CONFIG_MN10300_TTYSM0 |
| 158 | case SC0RXIRQ: | 158 | case SC0RXIRQ: |
| 159 | case SC0TXIRQ: | 159 | case SC0TXIRQ: |
diff --git a/arch/mn10300/kernel/kgdb.c b/arch/mn10300/kernel/kgdb.c new file mode 100644 index 000000000000..f6c981db2a36 --- /dev/null +++ b/arch/mn10300/kernel/kgdb.c | |||
| @@ -0,0 +1,502 @@ | |||
| 1 | /* kgdb support for MN10300 | ||
| 2 | * | ||
| 3 | * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/ptrace.h> | ||
| 14 | #include <linux/kgdb.h> | ||
| 15 | #include <linux/uaccess.h> | ||
| 16 | #include <unit/leds.h> | ||
| 17 | #include <unit/serial.h> | ||
| 18 | #include <asm/debugger.h> | ||
| 19 | #include <asm/serial-regs.h> | ||
| 20 | #include "internal.h" | ||
| 21 | |||
| 22 | /* | ||
| 23 | * Software single-stepping breakpoint save (used by __switch_to()) | ||
| 24 | */ | ||
| 25 | static struct thread_info *kgdb_sstep_thread; | ||
| 26 | u8 *kgdb_sstep_bp_addr[2]; | ||
| 27 | u8 kgdb_sstep_bp[2]; | ||
| 28 | |||
| 29 | /* | ||
| 30 | * Copy kernel exception frame registers to the GDB register file | ||
| 31 | */ | ||
| 32 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
| 33 | { | ||
| 34 | unsigned long ssp = (unsigned long) (regs + 1); | ||
| 35 | |||
| 36 | gdb_regs[GDB_FR_D0] = regs->d0; | ||
| 37 | gdb_regs[GDB_FR_D1] = regs->d1; | ||
| 38 | gdb_regs[GDB_FR_D2] = regs->d2; | ||
| 39 | gdb_regs[GDB_FR_D3] = regs->d3; | ||
| 40 | gdb_regs[GDB_FR_A0] = regs->a0; | ||
| 41 | gdb_regs[GDB_FR_A1] = regs->a1; | ||
| 42 | gdb_regs[GDB_FR_A2] = regs->a2; | ||
| 43 | gdb_regs[GDB_FR_A3] = regs->a3; | ||
| 44 | gdb_regs[GDB_FR_SP] = (regs->epsw & EPSW_nSL) ? regs->sp : ssp; | ||
| 45 | gdb_regs[GDB_FR_PC] = regs->pc; | ||
| 46 | gdb_regs[GDB_FR_MDR] = regs->mdr; | ||
| 47 | gdb_regs[GDB_FR_EPSW] = regs->epsw; | ||
| 48 | gdb_regs[GDB_FR_LIR] = regs->lir; | ||
| 49 | gdb_regs[GDB_FR_LAR] = regs->lar; | ||
| 50 | gdb_regs[GDB_FR_MDRQ] = regs->mdrq; | ||
| 51 | gdb_regs[GDB_FR_E0] = regs->e0; | ||
| 52 | gdb_regs[GDB_FR_E1] = regs->e1; | ||
| 53 | gdb_regs[GDB_FR_E2] = regs->e2; | ||
| 54 | gdb_regs[GDB_FR_E3] = regs->e3; | ||
| 55 | gdb_regs[GDB_FR_E4] = regs->e4; | ||
| 56 | gdb_regs[GDB_FR_E5] = regs->e5; | ||
| 57 | gdb_regs[GDB_FR_E6] = regs->e6; | ||
| 58 | gdb_regs[GDB_FR_E7] = regs->e7; | ||
| 59 | gdb_regs[GDB_FR_SSP] = ssp; | ||
| 60 | gdb_regs[GDB_FR_MSP] = 0; | ||
| 61 | gdb_regs[GDB_FR_USP] = regs->sp; | ||
| 62 | gdb_regs[GDB_FR_MCRH] = regs->mcrh; | ||
| 63 | gdb_regs[GDB_FR_MCRL] = regs->mcrl; | ||
| 64 | gdb_regs[GDB_FR_MCVF] = regs->mcvf; | ||
| 65 | gdb_regs[GDB_FR_DUMMY0] = 0; | ||
| 66 | gdb_regs[GDB_FR_DUMMY1] = 0; | ||
| 67 | gdb_regs[GDB_FR_FS0] = 0; | ||
| 68 | } | ||
| 69 | |||
| 70 | /* | ||
| 71 | * Extracts kernel SP/PC values understandable by gdb from the values | ||
| 72 | * saved by switch_to(). | ||
| 73 | */ | ||
| 74 | void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | ||
| 75 | { | ||
| 76 | gdb_regs[GDB_FR_SSP] = p->thread.sp; | ||
| 77 | gdb_regs[GDB_FR_PC] = p->thread.pc; | ||
| 78 | gdb_regs[GDB_FR_A3] = p->thread.a3; | ||
| 79 | gdb_regs[GDB_FR_USP] = p->thread.usp; | ||
| 80 | gdb_regs[GDB_FR_FPCR] = p->thread.fpu_state.fpcr; | ||
| 81 | } | ||
| 82 | |||
| 83 | /* | ||
| 84 | * Fill kernel exception frame registers from the GDB register file | ||
| 85 | */ | ||
| 86 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
| 87 | { | ||
| 88 | regs->d0 = gdb_regs[GDB_FR_D0]; | ||
| 89 | regs->d1 = gdb_regs[GDB_FR_D1]; | ||
| 90 | regs->d2 = gdb_regs[GDB_FR_D2]; | ||
| 91 | regs->d3 = gdb_regs[GDB_FR_D3]; | ||
| 92 | regs->a0 = gdb_regs[GDB_FR_A0]; | ||
| 93 | regs->a1 = gdb_regs[GDB_FR_A1]; | ||
| 94 | regs->a2 = gdb_regs[GDB_FR_A2]; | ||
| 95 | regs->a3 = gdb_regs[GDB_FR_A3]; | ||
| 96 | regs->sp = gdb_regs[GDB_FR_SP]; | ||
| 97 | regs->pc = gdb_regs[GDB_FR_PC]; | ||
| 98 | regs->mdr = gdb_regs[GDB_FR_MDR]; | ||
| 99 | regs->epsw = gdb_regs[GDB_FR_EPSW]; | ||
| 100 | regs->lir = gdb_regs[GDB_FR_LIR]; | ||
| 101 | regs->lar = gdb_regs[GDB_FR_LAR]; | ||
| 102 | regs->mdrq = gdb_regs[GDB_FR_MDRQ]; | ||
| 103 | regs->e0 = gdb_regs[GDB_FR_E0]; | ||
| 104 | regs->e1 = gdb_regs[GDB_FR_E1]; | ||
| 105 | regs->e2 = gdb_regs[GDB_FR_E2]; | ||
| 106 | regs->e3 = gdb_regs[GDB_FR_E3]; | ||
| 107 | regs->e4 = gdb_regs[GDB_FR_E4]; | ||
| 108 | regs->e5 = gdb_regs[GDB_FR_E5]; | ||
| 109 | regs->e6 = gdb_regs[GDB_FR_E6]; | ||
| 110 | regs->e7 = gdb_regs[GDB_FR_E7]; | ||
| 111 | regs->sp = gdb_regs[GDB_FR_SSP]; | ||
| 112 | /* gdb_regs[GDB_FR_MSP]; */ | ||
| 113 | // regs->usp = gdb_regs[GDB_FR_USP]; | ||
| 114 | regs->mcrh = gdb_regs[GDB_FR_MCRH]; | ||
| 115 | regs->mcrl = gdb_regs[GDB_FR_MCRL]; | ||
| 116 | regs->mcvf = gdb_regs[GDB_FR_MCVF]; | ||
| 117 | /* gdb_regs[GDB_FR_DUMMY0]; */ | ||
| 118 | /* gdb_regs[GDB_FR_DUMMY1]; */ | ||
| 119 | |||
| 120 | // regs->fpcr = gdb_regs[GDB_FR_FPCR]; | ||
| 121 | // regs->fs0 = gdb_regs[GDB_FR_FS0]; | ||
| 122 | } | ||
| 123 | |||
| 124 | struct kgdb_arch arch_kgdb_ops = { | ||
| 125 | .gdb_bpt_instr = { 0xff }, | ||
| 126 | .flags = KGDB_HW_BREAKPOINT, | ||
| 127 | }; | ||
| 128 | |||
| 129 | static const unsigned char mn10300_kgdb_insn_sizes[256] = | ||
| 130 | { | ||
| 131 | /* 1 2 3 4 5 6 7 8 9 a b c d e f */ | ||
| 132 | 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, /* 0 */ | ||
| 133 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 1 */ | ||
| 134 | 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, /* 2 */ | ||
| 135 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, /* 3 */ | ||
| 136 | 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, /* 4 */ | ||
| 137 | 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, /* 5 */ | ||
| 138 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */ | ||
| 139 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */ | ||
| 140 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 8 */ | ||
| 141 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 9 */ | ||
| 142 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* a */ | ||
| 143 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* b */ | ||
| 144 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, /* c */ | ||
| 145 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */ | ||
| 146 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */ | ||
| 147 | 0, 2, 2, 2, 2, 2, 2, 4, 0, 3, 0, 4, 0, 6, 7, 1 /* f */ | ||
| 148 | }; | ||
| 149 | |||
| 150 | /* | ||
| 151 | * Attempt to emulate single stepping by means of breakpoint instructions. | ||
| 152 | * Although there is a single-step trace flag in EPSW, its use is not | ||
| 153 | * sufficiently documented and is only intended for use with the JTAG debugger. | ||
| 154 | */ | ||
| 155 | static int kgdb_arch_do_singlestep(struct pt_regs *regs) | ||
| 156 | { | ||
| 157 | unsigned long arg; | ||
| 158 | unsigned size; | ||
| 159 | u8 *pc = (u8 *)regs->pc, *sp = (u8 *)(regs + 1), cur; | ||
| 160 | u8 *x = NULL, *y = NULL; | ||
| 161 | int ret; | ||
| 162 | |||
| 163 | ret = probe_kernel_read(&cur, pc, 1); | ||
| 164 | if (ret < 0) | ||
| 165 | return ret; | ||
| 166 | |||
| 167 | size = mn10300_kgdb_insn_sizes[cur]; | ||
| 168 | if (size > 0) { | ||
| 169 | x = pc + size; | ||
| 170 | goto set_x; | ||
| 171 | } | ||
| 172 | |||
| 173 | switch (cur) { | ||
| 174 | /* Bxx (d8,PC) */ | ||
| 175 | case 0xc0 ... 0xca: | ||
| 176 | ret = probe_kernel_read(&arg, pc + 1, 1); | ||
| 177 | if (ret < 0) | ||
| 178 | return ret; | ||
| 179 | x = pc + 2; | ||
| 180 | if (arg >= 0 && arg <= 2) | ||
| 181 | goto set_x; | ||
| 182 | y = pc + (s8)arg; | ||
| 183 | goto set_x_and_y; | ||
| 184 | |||
| 185 | /* LXX (d8,PC) */ | ||
| 186 | case 0xd0 ... 0xda: | ||
| 187 | x = pc + 1; | ||
| 188 | if (regs->pc == regs->lar) | ||
| 189 | goto set_x; | ||
| 190 | y = (u8 *)regs->lar; | ||
| 191 | goto set_x_and_y; | ||
| 192 | |||
| 193 | /* SETLB - loads the next four bytes into the LIR register | ||
| 194 | * (which mustn't include a breakpoint instruction) */ | ||
| 195 | case 0xdb: | ||
| 196 | x = pc + 5; | ||
| 197 | goto set_x; | ||
| 198 | |||
| 199 | /* JMP (d16,PC) or CALL (d16,PC) */ | ||
| 200 | case 0xcc: | ||
| 201 | case 0xcd: | ||
| 202 | ret = probe_kernel_read(&arg, pc + 1, 2); | ||
| 203 | if (ret < 0) | ||
| 204 | return ret; | ||
| 205 | x = pc + (s16)arg; | ||
| 206 | goto set_x; | ||
| 207 | |||
| 208 | /* JMP (d32,PC) or CALL (d32,PC) */ | ||
| 209 | case 0xdc: | ||
| 210 | case 0xdd: | ||
| 211 | ret = probe_kernel_read(&arg, pc + 1, 4); | ||
| 212 | if (ret < 0) | ||
| 213 | return ret; | ||
| 214 | x = pc + (s32)arg; | ||
| 215 | goto set_x; | ||
| 216 | |||
| 217 | /* RETF */ | ||
| 218 | case 0xde: | ||
| 219 | x = (u8 *)regs->mdr; | ||
| 220 | goto set_x; | ||
| 221 | |||
| 222 | /* RET */ | ||
| 223 | case 0xdf: | ||
| 224 | ret = probe_kernel_read(&arg, pc + 2, 1); | ||
| 225 | if (ret < 0) | ||
| 226 | return ret; | ||
| 227 | ret = probe_kernel_read(&x, sp + (s8)arg, 4); | ||
| 228 | if (ret < 0) | ||
| 229 | return ret; | ||
| 230 | goto set_x; | ||
| 231 | |||
| 232 | case 0xf0: | ||
| 233 | ret = probe_kernel_read(&cur, pc + 1, 1); | ||
| 234 | if (ret < 0) | ||
| 235 | return ret; | ||
| 236 | |||
| 237 | if (cur >= 0xf0 && cur <= 0xf7) { | ||
| 238 | /* JMP (An) / CALLS (An) */ | ||
| 239 | switch (cur & 3) { | ||
| 240 | case 0: x = (u8 *)regs->a0; break; | ||
| 241 | case 1: x = (u8 *)regs->a1; break; | ||
| 242 | case 2: x = (u8 *)regs->a2; break; | ||
| 243 | case 3: x = (u8 *)regs->a3; break; | ||
| 244 | } | ||
| 245 | goto set_x; | ||
| 246 | } else if (cur == 0xfc) { | ||
| 247 | /* RETS */ | ||
| 248 | ret = probe_kernel_read(&x, sp, 4); | ||
| 249 | if (ret < 0) | ||
| 250 | return ret; | ||
| 251 | goto set_x; | ||
| 252 | } else if (cur == 0xfd) { | ||
| 253 | /* RTI */ | ||
| 254 | ret = probe_kernel_read(&x, sp + 4, 4); | ||
| 255 | if (ret < 0) | ||
| 256 | return ret; | ||
| 257 | goto set_x; | ||
| 258 | } else { | ||
| 259 | x = pc + 2; | ||
| 260 | goto set_x; | ||
| 261 | } | ||
| 262 | break; | ||
| 263 | |||
| 264 | /* potential 3-byte conditional branches */ | ||
| 265 | case 0xf8: | ||
| 266 | ret = probe_kernel_read(&cur, pc + 1, 1); | ||
| 267 | if (ret < 0) | ||
| 268 | return ret; | ||
| 269 | x = pc + 3; | ||
| 270 | |||
| 271 | if (cur >= 0xe8 && cur <= 0xeb) { | ||
| 272 | ret = probe_kernel_read(&arg, pc + 2, 1); | ||
| 273 | if (ret < 0) | ||
| 274 | return ret; | ||
| 275 | if (arg >= 0 && arg <= 3) | ||
| 276 | goto set_x; | ||
| 277 | y = pc + (s8)arg; | ||
| 278 | goto set_x_and_y; | ||
| 279 | } | ||
| 280 | goto set_x; | ||
| 281 | |||
| 282 | case 0xfa: | ||
| 283 | ret = probe_kernel_read(&cur, pc + 1, 1); | ||
| 284 | if (ret < 0) | ||
| 285 | return ret; | ||
| 286 | |||
| 287 | if (cur == 0xff) { | ||
| 288 | /* CALLS (d16,PC) */ | ||
| 289 | ret = probe_kernel_read(&arg, pc + 2, 2); | ||
| 290 | if (ret < 0) | ||
| 291 | return ret; | ||
| 292 | x = pc + (s16)arg; | ||
| 293 | goto set_x; | ||
| 294 | } | ||
| 295 | |||
| 296 | x = pc + 4; | ||
| 297 | goto set_x; | ||
| 298 | |||
| 299 | case 0xfc: | ||
| 300 | ret = probe_kernel_read(&cur, pc + 1, 1); | ||
| 301 | if (ret < 0) | ||
| 302 | return ret; | ||
| 303 | |||
| 304 | if (cur == 0xff) { | ||
| 305 | /* CALLS (d32,PC) */ | ||
| 306 | ret = probe_kernel_read(&arg, pc + 2, 4); | ||
| 307 | if (ret < 0) | ||
| 308 | return ret; | ||
| 309 | x = pc + (s32)arg; | ||
| 310 | goto set_x; | ||
| 311 | } | ||
| 312 | |||
| 313 | x = pc + 6; | ||
| 314 | goto set_x; | ||
| 315 | } | ||
| 316 | |||
| 317 | return 0; | ||
| 318 | |||
| 319 | set_x: | ||
| 320 | kgdb_sstep_bp_addr[0] = x; | ||
| 321 | kgdb_sstep_bp_addr[1] = NULL; | ||
| 322 | ret = probe_kernel_read(&kgdb_sstep_bp[0], x, 1); | ||
| 323 | if (ret < 0) | ||
| 324 | return ret; | ||
| 325 | ret = probe_kernel_write(x, &arch_kgdb_ops.gdb_bpt_instr, 1); | ||
| 326 | if (ret < 0) | ||
| 327 | return ret; | ||
| 328 | kgdb_sstep_thread = current_thread_info(); | ||
| 329 | debugger_local_cache_flushinv_one(x); | ||
| 330 | return ret; | ||
| 331 | |||
| 332 | set_x_and_y: | ||
| 333 | kgdb_sstep_bp_addr[0] = x; | ||
| 334 | kgdb_sstep_bp_addr[1] = y; | ||
| 335 | ret = probe_kernel_read(&kgdb_sstep_bp[0], x, 1); | ||
| 336 | if (ret < 0) | ||
| 337 | return ret; | ||
| 338 | ret = probe_kernel_read(&kgdb_sstep_bp[1], y, 1); | ||
| 339 | if (ret < 0) | ||
| 340 | return ret; | ||
| 341 | ret = probe_kernel_write(x, &arch_kgdb_ops.gdb_bpt_instr, 1); | ||
| 342 | if (ret < 0) | ||
| 343 | return ret; | ||
| 344 | ret = probe_kernel_write(y, &arch_kgdb_ops.gdb_bpt_instr, 1); | ||
| 345 | if (ret < 0) { | ||
| 346 | probe_kernel_write(kgdb_sstep_bp_addr[0], | ||
| 347 | &kgdb_sstep_bp[0], 1); | ||
| 348 | } else { | ||
| 349 | kgdb_sstep_thread = current_thread_info(); | ||
| 350 | } | ||
| 351 | debugger_local_cache_flushinv_one(x); | ||
| 352 | debugger_local_cache_flushinv_one(y); | ||
| 353 | return ret; | ||
| 354 | } | ||
| 355 | |||
| 356 | /* | ||
| 357 | * Remove emplaced single-step breakpoints, returning true if we hit one of | ||
| 358 | * them. | ||
| 359 | */ | ||
| 360 | static bool kgdb_arch_undo_singlestep(struct pt_regs *regs) | ||
| 361 | { | ||
| 362 | bool hit = false; | ||
| 363 | u8 *x = kgdb_sstep_bp_addr[0], *y = kgdb_sstep_bp_addr[1]; | ||
| 364 | u8 opcode; | ||
| 365 | |||
| 366 | if (kgdb_sstep_thread == current_thread_info()) { | ||
| 367 | if (x) { | ||
| 368 | if (x == (u8 *)regs->pc) | ||
| 369 | hit = true; | ||
| 370 | if (probe_kernel_read(&opcode, x, | ||
| 371 | 1) < 0 || | ||
| 372 | opcode != 0xff) | ||
| 373 | BUG(); | ||
| 374 | probe_kernel_write(x, &kgdb_sstep_bp[0], 1); | ||
| 375 | debugger_local_cache_flushinv_one(x); | ||
| 376 | } | ||
| 377 | if (y) { | ||
| 378 | if (y == (u8 *)regs->pc) | ||
| 379 | hit = true; | ||
| 380 | if (probe_kernel_read(&opcode, y, | ||
| 381 | 1) < 0 || | ||
| 382 | opcode != 0xff) | ||
| 383 | BUG(); | ||
| 384 | probe_kernel_write(y, &kgdb_sstep_bp[1], 1); | ||
| 385 | debugger_local_cache_flushinv_one(y); | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | kgdb_sstep_bp_addr[0] = NULL; | ||
| 390 | kgdb_sstep_bp_addr[1] = NULL; | ||
| 391 | kgdb_sstep_thread = NULL; | ||
| 392 | return hit; | ||
| 393 | } | ||
| 394 | |||
| 395 | /* | ||
| 396 | * Catch a single-step-pending thread being deleted and make sure the global | ||
| 397 | * single-step state is cleared. At this point the breakpoints should have | ||
| 398 | * been removed by __switch_to(). | ||
| 399 | */ | ||
| 400 | void free_thread_info(struct thread_info *ti) | ||
| 401 | { | ||
| 402 | if (kgdb_sstep_thread == ti) { | ||
| 403 | kgdb_sstep_thread = NULL; | ||
| 404 | |||
| 405 | /* However, we may now be running in degraded mode, with most | ||
| 406 | * of the CPUs disabled until such a time as KGDB is reentered, | ||
| 407 | * so force immediate reentry */ | ||
| 408 | kgdb_breakpoint(); | ||
| 409 | } | ||
| 410 | kfree(ti); | ||
| 411 | } | ||
| 412 | |||
| 413 | /* | ||
| 414 | * Handle unknown packets and [CcsDk] packets | ||
| 415 | * - at this point breakpoints have been installed | ||
| 416 | */ | ||
| 417 | int kgdb_arch_handle_exception(int vector, int signo, int err_code, | ||
| 418 | char *remcom_in_buffer, char *remcom_out_buffer, | ||
| 419 | struct pt_regs *regs) | ||
| 420 | { | ||
| 421 | long addr; | ||
| 422 | char *ptr; | ||
| 423 | |||
| 424 | switch (remcom_in_buffer[0]) { | ||
| 425 | case 'c': | ||
| 426 | case 's': | ||
| 427 | /* try to read optional parameter, pc unchanged if no parm */ | ||
| 428 | ptr = &remcom_in_buffer[1]; | ||
| 429 | if (kgdb_hex2long(&ptr, &addr)) | ||
| 430 | regs->pc = addr; | ||
| 431 | case 'D': | ||
| 432 | case 'k': | ||
| 433 | atomic_set(&kgdb_cpu_doing_single_step, -1); | ||
| 434 | |||
| 435 | if (remcom_in_buffer[0] == 's') { | ||
| 436 | kgdb_arch_do_singlestep(regs); | ||
| 437 | kgdb_single_step = 1; | ||
| 438 | atomic_set(&kgdb_cpu_doing_single_step, | ||
| 439 | raw_smp_processor_id()); | ||
| 440 | } | ||
| 441 | return 0; | ||
| 442 | } | ||
| 443 | return -1; /* this means that we do not want to exit from the handler */ | ||
| 444 | } | ||
| 445 | |||
| 446 | /* | ||
| 447 | * Handle event interception | ||
| 448 | * - returns 0 if the exception should be skipped, -ERROR otherwise. | ||
| 449 | */ | ||
| 450 | int debugger_intercept(enum exception_code excep, int signo, int si_code, | ||
| 451 | struct pt_regs *regs) | ||
| 452 | { | ||
| 453 | int ret; | ||
| 454 | |||
| 455 | if (kgdb_arch_undo_singlestep(regs)) { | ||
| 456 | excep = EXCEP_TRAP; | ||
| 457 | signo = SIGTRAP; | ||
| 458 | si_code = TRAP_TRACE; | ||
| 459 | } | ||
| 460 | |||
| 461 | ret = kgdb_handle_exception(excep, signo, si_code, regs); | ||
| 462 | |||
| 463 | debugger_local_cache_flushinv(); | ||
| 464 | |||
| 465 | return ret; | ||
| 466 | } | ||
| 467 | |||
| 468 | /* | ||
| 469 | * Determine if we've hit a debugger special breakpoint | ||
| 470 | */ | ||
| 471 | int at_debugger_breakpoint(struct pt_regs *regs) | ||
| 472 | { | ||
| 473 | return regs->pc == (unsigned long)&__arch_kgdb_breakpoint; | ||
| 474 | } | ||
| 475 | |||
| 476 | /* | ||
| 477 | * Initialise kgdb | ||
| 478 | */ | ||
| 479 | int kgdb_arch_init(void) | ||
| 480 | { | ||
| 481 | return 0; | ||
| 482 | } | ||
| 483 | |||
| 484 | /* | ||
| 485 | * Do something, perhaps, but don't know what. | ||
| 486 | */ | ||
| 487 | void kgdb_arch_exit(void) | ||
| 488 | { | ||
| 489 | } | ||
| 490 | |||
| 491 | #ifdef CONFIG_SMP | ||
| 492 | void debugger_nmi_interrupt(struct pt_regs *regs, enum exception_code code) | ||
| 493 | { | ||
| 494 | kgdb_nmicallback(arch_smp_processor_id(), regs); | ||
| 495 | debugger_local_cache_flushinv(); | ||
| 496 | } | ||
| 497 | |||
| 498 | void kgdb_roundup_cpus(unsigned long flags) | ||
| 499 | { | ||
| 500 | smp_jump_to_debugger(); | ||
| 501 | } | ||
| 502 | #endif | ||
diff --git a/arch/mn10300/kernel/mn10300-serial.c b/arch/mn10300/kernel/mn10300-serial.c index 93c53739cfc9..efca426a2ed4 100644 --- a/arch/mn10300/kernel/mn10300-serial.c +++ b/arch/mn10300/kernel/mn10300-serial.c | |||
| @@ -119,6 +119,10 @@ static int mn10300_serial_request_port(struct uart_port *); | |||
| 119 | static void mn10300_serial_config_port(struct uart_port *, int); | 119 | static void mn10300_serial_config_port(struct uart_port *, int); |
| 120 | static int mn10300_serial_verify_port(struct uart_port *, | 120 | static int mn10300_serial_verify_port(struct uart_port *, |
| 121 | struct serial_struct *); | 121 | struct serial_struct *); |
| 122 | #ifdef CONFIG_CONSOLE_POLL | ||
| 123 | static void mn10300_serial_poll_put_char(struct uart_port *, unsigned char); | ||
| 124 | static int mn10300_serial_poll_get_char(struct uart_port *); | ||
| 125 | #endif | ||
| 122 | 126 | ||
| 123 | static const struct uart_ops mn10300_serial_ops = { | 127 | static const struct uart_ops mn10300_serial_ops = { |
| 124 | .tx_empty = mn10300_serial_tx_empty, | 128 | .tx_empty = mn10300_serial_tx_empty, |
| @@ -138,6 +142,10 @@ static const struct uart_ops mn10300_serial_ops = { | |||
| 138 | .request_port = mn10300_serial_request_port, | 142 | .request_port = mn10300_serial_request_port, |
| 139 | .config_port = mn10300_serial_config_port, | 143 | .config_port = mn10300_serial_config_port, |
| 140 | .verify_port = mn10300_serial_verify_port, | 144 | .verify_port = mn10300_serial_verify_port, |
| 145 | #ifdef CONFIG_CONSOLE_POLL | ||
| 146 | .poll_put_char = mn10300_serial_poll_put_char, | ||
| 147 | .poll_get_char = mn10300_serial_poll_get_char, | ||
| 148 | #endif | ||
| 141 | }; | 149 | }; |
| 142 | 150 | ||
| 143 | static irqreturn_t mn10300_serial_interrupt(int irq, void *dev_id); | 151 | static irqreturn_t mn10300_serial_interrupt(int irq, void *dev_id); |
| @@ -1634,3 +1642,70 @@ static int __init mn10300_serial_console_init(void) | |||
| 1634 | 1642 | ||
| 1635 | console_initcall(mn10300_serial_console_init); | 1643 | console_initcall(mn10300_serial_console_init); |
| 1636 | #endif | 1644 | #endif |
| 1645 | |||
| 1646 | #ifdef CONFIG_CONSOLE_POLL | ||
| 1647 | /* | ||
| 1648 | * Polled character reception for the kernel debugger | ||
| 1649 | */ | ||
| 1650 | static int mn10300_serial_poll_get_char(struct uart_port *_port) | ||
| 1651 | { | ||
| 1652 | struct mn10300_serial_port *port = | ||
| 1653 | container_of(_port, struct mn10300_serial_port, uart); | ||
| 1654 | unsigned ix; | ||
| 1655 | u8 st, ch; | ||
| 1656 | |||
| 1657 | _enter("%s", port->name); | ||
| 1658 | |||
| 1659 | do { | ||
| 1660 | /* pull chars out of the hat */ | ||
| 1661 | ix = port->rx_outp; | ||
| 1662 | if (ix == port->rx_inp) | ||
| 1663 | return NO_POLL_CHAR; | ||
| 1664 | |||
| 1665 | ch = port->rx_buffer[ix++]; | ||
| 1666 | st = port->rx_buffer[ix++]; | ||
| 1667 | smp_rmb(); | ||
| 1668 | port->rx_outp = ix & (MNSC_BUFFER_SIZE - 1); | ||
| 1669 | |||
| 1670 | } while (st & (SC01STR_FEF | SC01STR_PEF | SC01STR_OEF)); | ||
| 1671 | |||
| 1672 | return ch; | ||
| 1673 | } | ||
| 1674 | |||
| 1675 | |||
| 1676 | /* | ||
| 1677 | * Polled character transmission for the kernel debugger | ||
| 1678 | */ | ||
| 1679 | static void mn10300_serial_poll_put_char(struct uart_port *_port, | ||
| 1680 | unsigned char ch) | ||
| 1681 | { | ||
| 1682 | struct mn10300_serial_port *port = | ||
| 1683 | container_of(_port, struct mn10300_serial_port, uart); | ||
| 1684 | u8 intr, tmp; | ||
| 1685 | |||
| 1686 | /* wait for the transmitter to finish anything it might be doing (and | ||
| 1687 | * this includes the virtual DMA handler, so it might take a while) */ | ||
| 1688 | while (*port->_status & (SC01STR_TBF | SC01STR_TXF)) | ||
| 1689 | continue; | ||
| 1690 | |||
| 1691 | /* disable the Tx ready interrupt */ | ||
| 1692 | intr = *port->_intr; | ||
| 1693 | *port->_intr = intr & ~SC01ICR_TI; | ||
| 1694 | tmp = *port->_intr; | ||
| 1695 | |||
| 1696 | if (ch == 0x0a) { | ||
| 1697 | *(u8 *) port->_txb = 0x0d; | ||
| 1698 | while (*port->_status & SC01STR_TBF) | ||
| 1699 | continue; | ||
| 1700 | } | ||
| 1701 | |||
| 1702 | *(u8 *) port->_txb = ch; | ||
| 1703 | while (*port->_status & SC01STR_TBF) | ||
| 1704 | continue; | ||
| 1705 | |||
| 1706 | /* restore the Tx interrupt flag */ | ||
| 1707 | *port->_intr = intr; | ||
| 1708 | tmp = *port->_intr; | ||
| 1709 | } | ||
| 1710 | |||
| 1711 | #endif /* CONFIG_CONSOLE_POLL */ | ||
diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c index e1b14a6ed544..28eec3102535 100644 --- a/arch/mn10300/kernel/process.c +++ b/arch/mn10300/kernel/process.c | |||
| @@ -135,7 +135,7 @@ void release_segments(struct mm_struct *mm) | |||
| 135 | 135 | ||
| 136 | void machine_restart(char *cmd) | 136 | void machine_restart(char *cmd) |
| 137 | { | 137 | { |
| 138 | #ifdef CONFIG_GDBSTUB | 138 | #ifdef CONFIG_KERNEL_DEBUGGER |
| 139 | gdbstub_exit(0); | 139 | gdbstub_exit(0); |
| 140 | #endif | 140 | #endif |
| 141 | 141 | ||
| @@ -148,14 +148,14 @@ void machine_restart(char *cmd) | |||
| 148 | 148 | ||
| 149 | void machine_halt(void) | 149 | void machine_halt(void) |
| 150 | { | 150 | { |
| 151 | #ifdef CONFIG_GDBSTUB | 151 | #ifdef CONFIG_KERNEL_DEBUGGER |
| 152 | gdbstub_exit(0); | 152 | gdbstub_exit(0); |
| 153 | #endif | 153 | #endif |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | void machine_power_off(void) | 156 | void machine_power_off(void) |
| 157 | { | 157 | { |
| 158 | #ifdef CONFIG_GDBSTUB | 158 | #ifdef CONFIG_KERNEL_DEBUGGER |
| 159 | gdbstub_exit(0); | 159 | gdbstub_exit(0); |
| 160 | #endif | 160 | #endif |
| 161 | } | 161 | } |
diff --git a/arch/mn10300/kernel/smp.c b/arch/mn10300/kernel/smp.c index 1ebb79f1650d..51c02f97dcea 100644 --- a/arch/mn10300/kernel/smp.c +++ b/arch/mn10300/kernel/smp.c | |||
| @@ -440,6 +440,22 @@ int smp_nmi_call_function(smp_call_func_t func, void *info, int wait) | |||
| 440 | } | 440 | } |
| 441 | 441 | ||
| 442 | /** | 442 | /** |
| 443 | * smp_jump_to_debugger - Make other CPUs enter the debugger by sending an IPI | ||
| 444 | * | ||
| 445 | * Send a non-maskable request to all other CPUs in the system, instructing | ||
| 446 | * them to jump into the debugger. The caller is responsible for checking that | ||
| 447 | * the other CPUs responded to the instruction. | ||
| 448 | * | ||
| 449 | * The caller should make sure that this CPU's debugger IPI is disabled. | ||
| 450 | */ | ||
| 451 | void smp_jump_to_debugger(void) | ||
| 452 | { | ||
| 453 | if (num_online_cpus() > 1) | ||
| 454 | /* Send a message to all other CPUs */ | ||
| 455 | send_IPI_allbutself(DEBUGGER_NMI_IPI); | ||
| 456 | } | ||
| 457 | |||
| 458 | /** | ||
| 443 | * stop_this_cpu - Callback to stop a CPU. | 459 | * stop_this_cpu - Callback to stop a CPU. |
| 444 | * @unused: Callback context (ignored). | 460 | * @unused: Callback context (ignored). |
| 445 | */ | 461 | */ |
| @@ -603,7 +619,7 @@ static void __init smp_cpu_init(void) | |||
| 603 | /** | 619 | /** |
| 604 | * smp_prepare_cpu_init - Initialise CPU in startup_secondary | 620 | * smp_prepare_cpu_init - Initialise CPU in startup_secondary |
| 605 | * | 621 | * |
| 606 | * Set interrupt level 0-6 setting and init ICR of gdbstub. | 622 | * Set interrupt level 0-6 setting and init ICR of the kernel debugger. |
| 607 | */ | 623 | */ |
| 608 | void smp_prepare_cpu_init(void) | 624 | void smp_prepare_cpu_init(void) |
| 609 | { | 625 | { |
| @@ -622,15 +638,15 @@ void smp_prepare_cpu_init(void) | |||
| 622 | for (loop = 0; loop < GxICR_NUM_IRQS; loop++) | 638 | for (loop = 0; loop < GxICR_NUM_IRQS; loop++) |
| 623 | GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT; | 639 | GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT; |
| 624 | 640 | ||
| 625 | #ifdef CONFIG_GDBSTUB | 641 | #ifdef CONFIG_KERNEL_DEBUGGER |
| 626 | /* initialise GDB-stub */ | 642 | /* initialise the kernel debugger interrupt */ |
| 627 | do { | 643 | do { |
| 628 | unsigned long flags; | 644 | unsigned long flags; |
| 629 | u16 tmp16; | 645 | u16 tmp16; |
| 630 | 646 | ||
| 631 | flags = arch_local_cli_save(); | 647 | flags = arch_local_cli_save(); |
| 632 | GxICR(GDB_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT; | 648 | GxICR(DEBUGGER_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT; |
| 633 | tmp16 = GxICR(GDB_NMI_IPI); | 649 | tmp16 = GxICR(DEBUGGER_NMI_IPI); |
| 634 | arch_local_irq_restore(flags); | 650 | arch_local_irq_restore(flags); |
| 635 | } while (0); | 651 | } while (0); |
| 636 | #endif | 652 | #endif |
diff --git a/arch/mn10300/kernel/switch_to.S b/arch/mn10300/kernel/switch_to.S index 9074d0fb8788..de3e74fc9ea0 100644 --- a/arch/mn10300/kernel/switch_to.S +++ b/arch/mn10300/kernel/switch_to.S | |||
| @@ -39,11 +39,17 @@ ENTRY(__switch_to) | |||
| 39 | 39 | ||
| 40 | # save prev context | 40 | # save prev context |
| 41 | mov __switch_back,d0 | 41 | mov __switch_back,d0 |
| 42 | mov d0,(THREAD_PC,a0) | ||
| 43 | mov sp,a2 | 42 | mov sp,a2 |
| 44 | mov a2,(THREAD_SP,a0) | 43 | mov a2,(THREAD_SP,a0) |
| 45 | mov a3,(THREAD_A3,a0) | 44 | mov a3,(THREAD_A3,a0) |
| 46 | 45 | ||
| 46 | #ifdef CONFIG_KGDB | ||
| 47 | btst 0xff,(kgdb_single_step) | ||
| 48 | bne __switch_to__lift_sstep_bp | ||
| 49 | __switch_to__continue: | ||
| 50 | #endif | ||
| 51 | mov d0,(THREAD_PC,a0) | ||
| 52 | |||
| 47 | mov (THREAD_A3,a1),a3 | 53 | mov (THREAD_A3,a1),a3 |
| 48 | mov (THREAD_SP,a1),a2 | 54 | mov (THREAD_SP,a1),a2 |
| 49 | 55 | ||
| @@ -68,3 +74,106 @@ ENTRY(__switch_to) | |||
| 68 | __switch_back: | 74 | __switch_back: |
| 69 | and ~EPSW_NMID,epsw | 75 | and ~EPSW_NMID,epsw |
| 70 | ret [d2,d3,a2,a3,exreg1],32 | 76 | ret [d2,d3,a2,a3,exreg1],32 |
| 77 | |||
| 78 | #ifdef CONFIG_KGDB | ||
| 79 | ############################################################################### | ||
| 80 | # | ||
| 81 | # Lift the single-step breakpoints when the task being traced is switched out | ||
| 82 | # A0 = prev | ||
| 83 | # A1 = next | ||
| 84 | # | ||
| 85 | ############################################################################### | ||
| 86 | __switch_to__lift_sstep_bp: | ||
| 87 | add -12,sp | ||
| 88 | mov a0,e4 | ||
| 89 | mov a1,e5 | ||
| 90 | |||
| 91 | # Clear the single-step flag to prevent us coming this way until we get | ||
| 92 | # switched back in | ||
| 93 | bclr 0xff,(kgdb_single_step) | ||
| 94 | |||
| 95 | # Remove first breakpoint | ||
| 96 | mov (kgdb_sstep_bp_addr),a2 | ||
| 97 | cmp 0,a2 | ||
| 98 | beq 1f | ||
| 99 | movbu (kgdb_sstep_bp),d0 | ||
| 100 | movbu d0,(a2) | ||
| 101 | #if defined(CONFIG_MN10300_CACHE_FLUSH_ICACHE) || defined(CONFIG_MN10300_CACHE_INV_ICACHE) | ||
| 102 | mov a2,d0 | ||
| 103 | mov a2,d1 | ||
| 104 | add 1,d1 | ||
| 105 | calls flush_icache_range | ||
| 106 | #endif | ||
| 107 | 1: | ||
| 108 | |||
| 109 | # Remove second breakpoint | ||
| 110 | mov (kgdb_sstep_bp_addr+4),a2 | ||
| 111 | cmp 0,a2 | ||
| 112 | beq 2f | ||
| 113 | movbu (kgdb_sstep_bp+1),d0 | ||
| 114 | movbu d0,(a2) | ||
| 115 | #if defined(CONFIG_MN10300_CACHE_FLUSH_ICACHE) || defined(CONFIG_MN10300_CACHE_INV_ICACHE) | ||
| 116 | mov a2,d0 | ||
| 117 | mov a2,d1 | ||
| 118 | add 1,d1 | ||
| 119 | calls flush_icache_range | ||
| 120 | #endif | ||
| 121 | 2: | ||
| 122 | |||
| 123 | # Change the resumption address and return | ||
| 124 | mov __switch_back__reinstall_sstep_bp,d0 | ||
| 125 | mov e4,a0 | ||
| 126 | mov e5,a1 | ||
| 127 | add 12,sp | ||
| 128 | bra __switch_to__continue | ||
| 129 | |||
| 130 | ############################################################################### | ||
| 131 | # | ||
| 132 | # Reinstall the single-step breakpoints when the task being traced is switched | ||
| 133 | # back in (A1 points to the new thread_struct). | ||
| 134 | # | ||
| 135 | ############################################################################### | ||
| 136 | __switch_back__reinstall_sstep_bp: | ||
| 137 | add -12,sp | ||
| 138 | mov a0,e4 # save the return value | ||
| 139 | mov 0xff,d3 | ||
| 140 | |||
| 141 | # Reinstall first breakpoint | ||
| 142 | mov (kgdb_sstep_bp_addr),a2 | ||
| 143 | cmp 0,a2 | ||
| 144 | beq 1f | ||
| 145 | movbu (a2),d0 | ||
| 146 | movbu d0,(kgdb_sstep_bp) | ||
| 147 | movbu d3,(a2) | ||
| 148 | #if defined(CONFIG_MN10300_CACHE_FLUSH_ICACHE) || defined(CONFIG_MN10300_CACHE_INV_ICACHE) | ||
| 149 | mov a2,d0 | ||
| 150 | mov a2,d1 | ||
| 151 | add 1,d1 | ||
| 152 | calls flush_icache_range | ||
| 153 | #endif | ||
| 154 | 1: | ||
| 155 | |||
| 156 | # Reinstall second breakpoint | ||
| 157 | mov (kgdb_sstep_bp_addr+4),a2 | ||
| 158 | cmp 0,a2 | ||
| 159 | beq 2f | ||
| 160 | movbu (a2),d0 | ||
| 161 | movbu d0,(kgdb_sstep_bp+1) | ||
| 162 | movbu d3,(a2) | ||
| 163 | #if defined(CONFIG_MN10300_CACHE_FLUSH_ICACHE) || defined(CONFIG_MN10300_CACHE_INV_ICACHE) | ||
| 164 | mov a2,d0 | ||
| 165 | mov a2,d1 | ||
| 166 | add 1,d1 | ||
| 167 | calls flush_icache_range | ||
| 168 | #endif | ||
| 169 | 2: | ||
| 170 | |||
| 171 | mov d3,(kgdb_single_step) | ||
| 172 | |||
| 173 | # Restore the return value (the previous thread_struct pointer) | ||
| 174 | mov e4,a0 | ||
| 175 | mov a0,d0 | ||
| 176 | add 12,sp | ||
| 177 | bra __switch_back | ||
| 178 | |||
| 179 | #endif /* CONFIG_KGDB */ | ||
diff --git a/arch/mn10300/kernel/traps.c b/arch/mn10300/kernel/traps.c index b90c3f160c77..f03cb278828f 100644 --- a/arch/mn10300/kernel/traps.c +++ b/arch/mn10300/kernel/traps.c | |||
| @@ -38,8 +38,9 @@ | |||
| 38 | #include <asm/busctl-regs.h> | 38 | #include <asm/busctl-regs.h> |
| 39 | #include <unit/leds.h> | 39 | #include <unit/leds.h> |
| 40 | #include <asm/fpu.h> | 40 | #include <asm/fpu.h> |
| 41 | #include <asm/gdb-stub.h> | ||
| 42 | #include <asm/sections.h> | 41 | #include <asm/sections.h> |
| 42 | #include <asm/debugger.h> | ||
| 43 | #include "internal.h" | ||
| 43 | 44 | ||
| 44 | #if (CONFIG_INTERRUPT_VECTOR_BASE & 0xffffff) | 45 | #if (CONFIG_INTERRUPT_VECTOR_BASE & 0xffffff) |
| 45 | #error "INTERRUPT_VECTOR_BASE not aligned to 16MiB boundary!" | 46 | #error "INTERRUPT_VECTOR_BASE not aligned to 16MiB boundary!" |
| @@ -49,63 +50,169 @@ int kstack_depth_to_print = 24; | |||
| 49 | 50 | ||
| 50 | spinlock_t die_lock = __SPIN_LOCK_UNLOCKED(die_lock); | 51 | spinlock_t die_lock = __SPIN_LOCK_UNLOCKED(die_lock); |
| 51 | 52 | ||
| 52 | ATOMIC_NOTIFIER_HEAD(mn10300_die_chain); | 53 | struct exception_to_signal_map { |
| 54 | u8 signo; | ||
| 55 | u32 si_code; | ||
| 56 | }; | ||
| 57 | |||
| 58 | static const struct exception_to_signal_map exception_to_signal_map[256] = { | ||
| 59 | /* MMU exceptions */ | ||
| 60 | [EXCEP_ITLBMISS >> 3] = { 0, 0 }, | ||
| 61 | [EXCEP_DTLBMISS >> 3] = { 0, 0 }, | ||
| 62 | [EXCEP_IAERROR >> 3] = { 0, 0 }, | ||
| 63 | [EXCEP_DAERROR >> 3] = { 0, 0 }, | ||
| 64 | |||
| 65 | /* system exceptions */ | ||
| 66 | [EXCEP_TRAP >> 3] = { SIGTRAP, TRAP_BRKPT }, | ||
| 67 | [EXCEP_ISTEP >> 3] = { SIGTRAP, TRAP_TRACE }, /* Monitor */ | ||
| 68 | [EXCEP_IBREAK >> 3] = { SIGTRAP, TRAP_HWBKPT }, /* Monitor */ | ||
| 69 | [EXCEP_OBREAK >> 3] = { SIGTRAP, TRAP_HWBKPT }, /* Monitor */ | ||
| 70 | [EXCEP_PRIVINS >> 3] = { SIGILL, ILL_PRVOPC }, | ||
| 71 | [EXCEP_UNIMPINS >> 3] = { SIGILL, ILL_ILLOPC }, | ||
| 72 | [EXCEP_UNIMPEXINS >> 3] = { SIGILL, ILL_ILLOPC }, | ||
| 73 | [EXCEP_MEMERR >> 3] = { SIGSEGV, SEGV_ACCERR }, | ||
| 74 | [EXCEP_MISALIGN >> 3] = { SIGBUS, BUS_ADRALN }, | ||
| 75 | [EXCEP_BUSERROR >> 3] = { SIGBUS, BUS_ADRERR }, | ||
| 76 | [EXCEP_ILLINSACC >> 3] = { SIGSEGV, SEGV_ACCERR }, | ||
| 77 | [EXCEP_ILLDATACC >> 3] = { SIGSEGV, SEGV_ACCERR }, | ||
| 78 | [EXCEP_IOINSACC >> 3] = { SIGSEGV, SEGV_ACCERR }, | ||
| 79 | [EXCEP_PRIVINSACC >> 3] = { SIGSEGV, SEGV_ACCERR }, /* userspace */ | ||
| 80 | [EXCEP_PRIVDATACC >> 3] = { SIGSEGV, SEGV_ACCERR }, /* userspace */ | ||
| 81 | [EXCEP_DATINSACC >> 3] = { SIGSEGV, SEGV_ACCERR }, | ||
| 82 | [EXCEP_DOUBLE_FAULT >> 3] = { SIGILL, ILL_BADSTK }, | ||
| 83 | |||
| 84 | /* FPU exceptions */ | ||
| 85 | [EXCEP_FPU_DISABLED >> 3] = { SIGILL, ILL_COPROC }, | ||
| 86 | [EXCEP_FPU_UNIMPINS >> 3] = { SIGILL, ILL_COPROC }, | ||
| 87 | [EXCEP_FPU_OPERATION >> 3] = { SIGFPE, FPE_INTDIV }, | ||
| 88 | |||
| 89 | /* interrupts */ | ||
| 90 | [EXCEP_WDT >> 3] = { SIGALRM, 0 }, | ||
| 91 | [EXCEP_NMI >> 3] = { SIGQUIT, 0 }, | ||
| 92 | [EXCEP_IRQ_LEVEL0 >> 3] = { SIGINT, 0 }, | ||
| 93 | [EXCEP_IRQ_LEVEL1 >> 3] = { 0, 0 }, | ||
| 94 | [EXCEP_IRQ_LEVEL2 >> 3] = { 0, 0 }, | ||
| 95 | [EXCEP_IRQ_LEVEL3 >> 3] = { 0, 0 }, | ||
| 96 | [EXCEP_IRQ_LEVEL4 >> 3] = { 0, 0 }, | ||
| 97 | [EXCEP_IRQ_LEVEL5 >> 3] = { 0, 0 }, | ||
| 98 | [EXCEP_IRQ_LEVEL6 >> 3] = { 0, 0 }, | ||
| 99 | |||
| 100 | /* system calls */ | ||
| 101 | [EXCEP_SYSCALL0 >> 3] = { 0, 0 }, | ||
| 102 | [EXCEP_SYSCALL1 >> 3] = { SIGILL, ILL_ILLTRP }, | ||
| 103 | [EXCEP_SYSCALL2 >> 3] = { SIGILL, ILL_ILLTRP }, | ||
| 104 | [EXCEP_SYSCALL3 >> 3] = { SIGILL, ILL_ILLTRP }, | ||
| 105 | [EXCEP_SYSCALL4 >> 3] = { SIGILL, ILL_ILLTRP }, | ||
| 106 | [EXCEP_SYSCALL5 >> 3] = { SIGILL, ILL_ILLTRP }, | ||
| 107 | [EXCEP_SYSCALL6 >> 3] = { SIGILL, ILL_ILLTRP }, | ||
| 108 | [EXCEP_SYSCALL7 >> 3] = { SIGILL, ILL_ILLTRP }, | ||
| 109 | [EXCEP_SYSCALL8 >> 3] = { SIGILL, ILL_ILLTRP }, | ||
| 110 | [EXCEP_SYSCALL9 >> 3] = { SIGILL, ILL_ILLTRP }, | ||
| 111 | [EXCEP_SYSCALL10 >> 3] = { SIGILL, ILL_ILLTRP }, | ||
| 112 | [EXCEP_SYSCALL11 >> 3] = { SIGILL, ILL_ILLTRP }, | ||
| 113 | [EXCEP_SYSCALL12 >> 3] = { SIGILL, ILL_ILLTRP }, | ||
| 114 | [EXCEP_SYSCALL13 >> 3] = { SIGILL, ILL_ILLTRP }, | ||
| 115 | [EXCEP_SYSCALL14 >> 3] = { SIGILL, ILL_ILLTRP }, | ||
| 116 | [EXCEP_SYSCALL15 >> 3] = { SIGABRT, 0 }, | ||
| 117 | }; | ||
| 53 | 118 | ||
| 54 | /* | 119 | /* |
| 55 | * These constants are for searching for possible module text | 120 | * Handle kernel exceptions. |
| 56 | * segments. MODULE_RANGE is a guess of how much space is likely | 121 | * |
| 57 | * to be vmalloced. | 122 | * See if there's a fixup handler we can force a jump to when an exception |
| 123 | * happens due to something kernel code did | ||
| 58 | */ | 124 | */ |
| 59 | #define MODULE_RANGE (8 * 1024 * 1024) | 125 | int die_if_no_fixup(const char *str, struct pt_regs *regs, |
| 60 | 126 | enum exception_code code) | |
| 61 | #define DO_ERROR(signr, prologue, str, name) \ | 127 | { |
| 62 | asmlinkage void name(struct pt_regs *regs, u32 intcode) \ | 128 | u8 opcode; |
| 63 | { \ | 129 | int signo, si_code; |
| 64 | prologue; \ | 130 | |
| 65 | if (die_if_no_fixup(str, regs, intcode)) \ | 131 | if (user_mode(regs)) |
| 66 | return; \ | 132 | return 0; |
| 67 | force_sig(signr, current); \ | 133 | |
| 68 | } | 134 | peripheral_leds_display_exception(code); |
| 135 | |||
| 136 | signo = exception_to_signal_map[code >> 3].signo; | ||
| 137 | si_code = exception_to_signal_map[code >> 3].si_code; | ||
| 138 | |||
| 139 | switch (code) { | ||
| 140 | /* see if we can fixup the kernel accessing memory */ | ||
| 141 | case EXCEP_ITLBMISS: | ||
| 142 | case EXCEP_DTLBMISS: | ||
| 143 | case EXCEP_IAERROR: | ||
| 144 | case EXCEP_DAERROR: | ||
| 145 | case EXCEP_MEMERR: | ||
| 146 | case EXCEP_MISALIGN: | ||
| 147 | case EXCEP_BUSERROR: | ||
| 148 | case EXCEP_ILLDATACC: | ||
| 149 | case EXCEP_IOINSACC: | ||
| 150 | case EXCEP_PRIVINSACC: | ||
| 151 | case EXCEP_PRIVDATACC: | ||
| 152 | case EXCEP_DATINSACC: | ||
| 153 | if (fixup_exception(regs)) | ||
| 154 | return 1; | ||
| 155 | break; | ||
| 69 | 156 | ||
| 70 | #define DO_EINFO(signr, prologue, str, name, sicode) \ | 157 | case EXCEP_TRAP: |
| 71 | asmlinkage void name(struct pt_regs *regs, u32 intcode) \ | 158 | case EXCEP_UNIMPINS: |
| 72 | { \ | 159 | if (get_user(opcode, (uint8_t __user *)regs->pc) != 0) |
| 73 | siginfo_t info; \ | 160 | break; |
| 74 | prologue; \ | 161 | if (opcode == 0xff) { |
| 75 | if (die_if_no_fixup(str, regs, intcode)) \ | 162 | if (notify_die(DIE_BREAKPOINT, str, regs, code, 0, 0)) |
| 76 | return; \ | 163 | return 1; |
| 77 | info.si_signo = signr; \ | 164 | if (at_debugger_breakpoint(regs)) |
| 78 | if (signr == SIGILL && sicode == ILL_ILLOPC) { \ | 165 | regs->pc++; |
| 79 | uint8_t opcode; \ | 166 | signo = SIGTRAP; |
| 80 | if (get_user(opcode, (uint8_t __user *)regs->pc) == 0) \ | 167 | si_code = TRAP_BRKPT; |
| 81 | if (opcode == 0xff) \ | 168 | } |
| 82 | info.si_signo = SIGTRAP; \ | 169 | break; |
| 83 | } \ | 170 | |
| 84 | info.si_errno = 0; \ | 171 | case EXCEP_SYSCALL1 ... EXCEP_SYSCALL14: |
| 85 | info.si_code = sicode; \ | 172 | /* syscall return addr is _after_ the instruction */ |
| 86 | info.si_addr = (void *) regs->pc; \ | 173 | regs->pc -= 2; |
| 87 | force_sig_info(info.si_signo, &info, current); \ | 174 | break; |
| 175 | |||
| 176 | case EXCEP_SYSCALL15: | ||
| 177 | if (report_bug(regs->pc, regs) == BUG_TRAP_TYPE_WARN) | ||
| 178 | return 1; | ||
| 179 | |||
| 180 | /* syscall return addr is _after_ the instruction */ | ||
| 181 | regs->pc -= 2; | ||
| 182 | break; | ||
| 183 | |||
| 184 | default: | ||
| 185 | break; | ||
| 186 | } | ||
| 187 | |||
| 188 | if (debugger_intercept(code, signo, si_code, regs) == 0) | ||
| 189 | return 1; | ||
| 190 | |||
| 191 | if (notify_die(DIE_GPF, str, regs, code, 0, 0)) | ||
| 192 | return 1; | ||
| 193 | |||
| 194 | /* make the process die as the last resort */ | ||
| 195 | die(str, regs, code); | ||
| 88 | } | 196 | } |
| 89 | 197 | ||
| 90 | DO_ERROR(SIGTRAP, {}, "trap", trap); | 198 | /* |
| 91 | DO_ERROR(SIGSEGV, {}, "ibreak", ibreak); | 199 | * General exception handler |
| 92 | DO_ERROR(SIGSEGV, {}, "obreak", obreak); | 200 | */ |
| 93 | DO_EINFO(SIGSEGV, {}, "access error", access_error, SEGV_ACCERR); | 201 | asmlinkage void handle_exception(struct pt_regs *regs, u32 intcode) |
| 94 | DO_EINFO(SIGSEGV, {}, "insn access error", insn_acc_error, SEGV_ACCERR); | 202 | { |
| 95 | DO_EINFO(SIGSEGV, {}, "data access error", data_acc_error, SEGV_ACCERR); | 203 | siginfo_t info; |
| 96 | DO_EINFO(SIGILL, {}, "privileged opcode", priv_op, ILL_PRVOPC); | 204 | |
| 97 | DO_EINFO(SIGILL, {}, "invalid opcode", invalid_op, ILL_ILLOPC); | 205 | /* deal with kernel exceptions here */ |
| 98 | DO_EINFO(SIGILL, {}, "invalid ex opcode", invalid_exop, ILL_ILLOPC); | 206 | if (die_if_no_fixup(NULL, regs, intcode)) |
| 99 | DO_EINFO(SIGBUS, {}, "invalid address", mem_error, BUS_ADRERR); | 207 | return; |
| 100 | DO_EINFO(SIGBUS, {}, "bus error", bus_error, BUS_ADRERR); | 208 | |
| 101 | 209 | /* otherwise it's a userspace exception */ | |
| 102 | DO_ERROR(SIGTRAP, | 210 | info.si_signo = exception_to_signal_map[intcode >> 3].signo; |
| 103 | #ifndef CONFIG_MN10300_USING_JTAG | 211 | info.si_code = exception_to_signal_map[intcode >> 3].si_code; |
| 104 | DCR &= ~0x0001, | 212 | info.si_errno = 0; |
| 105 | #else | 213 | info.si_addr = (void *) regs->pc; |
| 106 | {}, | 214 | force_sig_info(info.si_signo, &info, current); |
| 107 | #endif | 215 | } |
| 108 | "single step", istep); | ||
| 109 | 216 | ||
| 110 | /* | 217 | /* |
| 111 | * handle NMI | 218 | * handle NMI |
| @@ -113,10 +220,8 @@ DO_ERROR(SIGTRAP, | |||
| 113 | asmlinkage void nmi(struct pt_regs *regs, enum exception_code code) | 220 | asmlinkage void nmi(struct pt_regs *regs, enum exception_code code) |
| 114 | { | 221 | { |
| 115 | /* see if gdbstub wants to deal with it */ | 222 | /* see if gdbstub wants to deal with it */ |
| 116 | #ifdef CONFIG_GDBSTUB | 223 | if (debugger_intercept(code, SIGQUIT, 0, regs)) |
| 117 | if (gdbstub_intercept(regs, code)) | ||
| 118 | return; | 224 | return; |
| 119 | #endif | ||
| 120 | 225 | ||
| 121 | printk(KERN_WARNING "--- Register Dump ---\n"); | 226 | printk(KERN_WARNING "--- Register Dump ---\n"); |
| 122 | show_registers(regs); | 227 | show_registers(regs); |
| @@ -128,29 +233,36 @@ asmlinkage void nmi(struct pt_regs *regs, enum exception_code code) | |||
| 128 | */ | 233 | */ |
| 129 | void show_trace(unsigned long *sp) | 234 | void show_trace(unsigned long *sp) |
| 130 | { | 235 | { |
| 131 | unsigned long *stack, addr, module_start, module_end; | 236 | unsigned long bottom, stack, addr, fp, raslot; |
| 132 | int i; | 237 | |
| 133 | 238 | printk(KERN_EMERG "\nCall Trace:\n"); | |
| 134 | printk(KERN_EMERG "\nCall Trace:"); | 239 | |
| 135 | 240 | //stack = (unsigned long)sp; | |
| 136 | stack = sp; | 241 | asm("mov sp,%0" : "=a"(stack)); |
| 137 | i = 0; | 242 | asm("mov a3,%0" : "=r"(fp)); |
| 138 | module_start = VMALLOC_START; | 243 | |
| 139 | module_end = VMALLOC_END; | 244 | raslot = ULONG_MAX; |
| 245 | bottom = (stack + THREAD_SIZE) & ~(THREAD_SIZE - 1); | ||
| 246 | for (; stack < bottom; stack += sizeof(addr)) { | ||
| 247 | addr = *(unsigned long *)stack; | ||
| 248 | if (stack == fp) { | ||
| 249 | if (addr > stack && addr < bottom) { | ||
| 250 | fp = addr; | ||
| 251 | raslot = stack + sizeof(addr); | ||
| 252 | continue; | ||
| 253 | } | ||
| 254 | fp = 0; | ||
| 255 | raslot = ULONG_MAX; | ||
| 256 | } | ||
| 140 | 257 | ||
| 141 | while (((long) stack & (THREAD_SIZE - 1)) != 0) { | ||
| 142 | addr = *stack++; | ||
| 143 | if (__kernel_text_address(addr)) { | 258 | if (__kernel_text_address(addr)) { |
| 144 | #if 1 | ||
| 145 | printk(" [<%08lx>]", addr); | 259 | printk(" [<%08lx>]", addr); |
| 260 | if (stack >= raslot) | ||
| 261 | raslot = ULONG_MAX; | ||
| 262 | else | ||
| 263 | printk(" ?"); | ||
| 146 | print_symbol(" %s", addr); | 264 | print_symbol(" %s", addr); |
| 147 | printk("\n"); | 265 | printk("\n"); |
| 148 | #else | ||
| 149 | if ((i % 6) == 0) | ||
| 150 | printk(KERN_EMERG " "); | ||
| 151 | printk("[<%08lx>] ", addr); | ||
| 152 | i++; | ||
| 153 | #endif | ||
| 154 | } | 266 | } |
| 155 | } | 267 | } |
| 156 | 268 | ||
| @@ -323,86 +435,6 @@ void die(const char *str, struct pt_regs *regs, enum exception_code code) | |||
| 323 | } | 435 | } |
| 324 | 436 | ||
| 325 | /* | 437 | /* |
| 326 | * see if there's a fixup handler we can force a jump to when an exception | ||
| 327 | * happens due to something kernel code did | ||
| 328 | */ | ||
| 329 | int die_if_no_fixup(const char *str, struct pt_regs *regs, | ||
| 330 | enum exception_code code) | ||
| 331 | { | ||
| 332 | if (user_mode(regs)) | ||
| 333 | return 0; | ||
| 334 | |||
| 335 | peripheral_leds_display_exception(code); | ||
| 336 | |||
| 337 | switch (code) { | ||
| 338 | /* see if we can fixup the kernel accessing memory */ | ||
| 339 | case EXCEP_ITLBMISS: | ||
| 340 | case EXCEP_DTLBMISS: | ||
| 341 | case EXCEP_IAERROR: | ||
| 342 | case EXCEP_DAERROR: | ||
| 343 | case EXCEP_MEMERR: | ||
| 344 | case EXCEP_MISALIGN: | ||
| 345 | case EXCEP_BUSERROR: | ||
| 346 | case EXCEP_ILLDATACC: | ||
| 347 | case EXCEP_IOINSACC: | ||
| 348 | case EXCEP_PRIVINSACC: | ||
| 349 | case EXCEP_PRIVDATACC: | ||
| 350 | case EXCEP_DATINSACC: | ||
| 351 | if (fixup_exception(regs)) | ||
| 352 | return 1; | ||
| 353 | case EXCEP_UNIMPINS: | ||
| 354 | if (regs->pc && *(uint8_t *)regs->pc == 0xff) | ||
| 355 | if (notify_die(DIE_BREAKPOINT, str, regs, code, 0, 0)) | ||
| 356 | return 1; | ||
| 357 | break; | ||
| 358 | default: | ||
| 359 | break; | ||
| 360 | } | ||
| 361 | |||
| 362 | /* see if gdbstub wants to deal with it */ | ||
| 363 | #ifdef CONFIG_GDBSTUB | ||
| 364 | if (gdbstub_intercept(regs, code)) | ||
| 365 | return 1; | ||
| 366 | #endif | ||
| 367 | |||
| 368 | if (notify_die(DIE_GPF, str, regs, code, 0, 0)) | ||
| 369 | return 1; | ||
| 370 | |||
| 371 | /* make the process die as the last resort */ | ||
| 372 | die(str, regs, code); | ||
| 373 | } | ||
| 374 | |||
| 375 | /* | ||
| 376 | * handle unsupported syscall instructions (syscall 1-15) | ||
| 377 | */ | ||
| 378 | static asmlinkage void unsupported_syscall(struct pt_regs *regs, | ||
| 379 | enum exception_code code) | ||
| 380 | { | ||
| 381 | struct task_struct *tsk = current; | ||
| 382 | siginfo_t info; | ||
| 383 | |||
| 384 | /* catch a kernel BUG() */ | ||
| 385 | if (code == EXCEP_SYSCALL15 && !user_mode(regs)) { | ||
| 386 | if (report_bug(regs->pc, regs) == BUG_TRAP_TYPE_BUG) { | ||
| 387 | #ifdef CONFIG_GDBSTUB | ||
| 388 | gdbstub_intercept(regs, code); | ||
| 389 | #endif | ||
| 390 | } | ||
| 391 | } | ||
| 392 | |||
| 393 | regs->pc -= 2; /* syscall return addr is _after_ the instruction */ | ||
| 394 | |||
| 395 | die_if_no_fixup("An unsupported syscall insn was used by the kernel\n", | ||
| 396 | regs, code); | ||
| 397 | |||
| 398 | info.si_signo = SIGILL; | ||
| 399 | info.si_errno = ENOSYS; | ||
| 400 | info.si_code = ILL_ILLTRP; | ||
| 401 | info.si_addr = (void *) regs->pc; | ||
| 402 | force_sig_info(SIGILL, &info, tsk); | ||
| 403 | } | ||
| 404 | |||
| 405 | /* | ||
| 406 | * display the register file when the stack pointer gets clobbered | 438 | * display the register file when the stack pointer gets clobbered |
| 407 | */ | 439 | */ |
| 408 | asmlinkage void do_double_fault(struct pt_regs *regs) | 440 | asmlinkage void do_double_fault(struct pt_regs *regs) |
| @@ -481,10 +513,8 @@ asmlinkage void uninitialised_exception(struct pt_regs *regs, | |||
| 481 | { | 513 | { |
| 482 | 514 | ||
| 483 | /* see if gdbstub wants to deal with it */ | 515 | /* see if gdbstub wants to deal with it */ |
| 484 | #ifdef CONFIG_GDBSTUB | 516 | if (debugger_intercept(code, SIGSYS, 0, regs) == 0) |
| 485 | if (gdbstub_intercept(regs, code)) | ||
| 486 | return; | 517 | return; |
| 487 | #endif | ||
| 488 | 518 | ||
| 489 | peripheral_leds_display_exception(code); | 519 | peripheral_leds_display_exception(code); |
| 490 | printk(KERN_EMERG "Uninitialised Exception 0x%04x\n", code & 0xFFFF); | 520 | printk(KERN_EMERG "Uninitialised Exception 0x%04x\n", code & 0xFFFF); |
| @@ -549,43 +579,43 @@ void __init set_intr_stub(enum exception_code code, void *handler) | |||
| 549 | */ | 579 | */ |
| 550 | void __init trap_init(void) | 580 | void __init trap_init(void) |
| 551 | { | 581 | { |
| 552 | set_excp_vector(EXCEP_TRAP, trap); | 582 | set_excp_vector(EXCEP_TRAP, handle_exception); |
| 553 | set_excp_vector(EXCEP_ISTEP, istep); | 583 | set_excp_vector(EXCEP_ISTEP, handle_exception); |
| 554 | set_excp_vector(EXCEP_IBREAK, ibreak); | 584 | set_excp_vector(EXCEP_IBREAK, handle_exception); |
| 555 | set_excp_vector(EXCEP_OBREAK, obreak); | 585 | set_excp_vector(EXCEP_OBREAK, handle_exception); |
| 556 | 586 | ||
| 557 | set_excp_vector(EXCEP_PRIVINS, priv_op); | 587 | set_excp_vector(EXCEP_PRIVINS, handle_exception); |
| 558 | set_excp_vector(EXCEP_UNIMPINS, invalid_op); | 588 | set_excp_vector(EXCEP_UNIMPINS, handle_exception); |
| 559 | set_excp_vector(EXCEP_UNIMPEXINS, invalid_exop); | 589 | set_excp_vector(EXCEP_UNIMPEXINS, handle_exception); |
| 560 | set_excp_vector(EXCEP_MEMERR, mem_error); | 590 | set_excp_vector(EXCEP_MEMERR, handle_exception); |
| 561 | set_excp_vector(EXCEP_MISALIGN, misalignment); | 591 | set_excp_vector(EXCEP_MISALIGN, misalignment); |
| 562 | set_excp_vector(EXCEP_BUSERROR, bus_error); | 592 | set_excp_vector(EXCEP_BUSERROR, handle_exception); |
| 563 | set_excp_vector(EXCEP_ILLINSACC, insn_acc_error); | 593 | set_excp_vector(EXCEP_ILLINSACC, handle_exception); |
| 564 | set_excp_vector(EXCEP_ILLDATACC, data_acc_error); | 594 | set_excp_vector(EXCEP_ILLDATACC, handle_exception); |
| 565 | set_excp_vector(EXCEP_IOINSACC, insn_acc_error); | 595 | set_excp_vector(EXCEP_IOINSACC, handle_exception); |
| 566 | set_excp_vector(EXCEP_PRIVINSACC, insn_acc_error); | 596 | set_excp_vector(EXCEP_PRIVINSACC, handle_exception); |
| 567 | set_excp_vector(EXCEP_PRIVDATACC, data_acc_error); | 597 | set_excp_vector(EXCEP_PRIVDATACC, handle_exception); |
| 568 | set_excp_vector(EXCEP_DATINSACC, insn_acc_error); | 598 | set_excp_vector(EXCEP_DATINSACC, handle_exception); |
| 569 | set_excp_vector(EXCEP_FPU_UNIMPINS, fpu_invalid_op); | 599 | set_excp_vector(EXCEP_FPU_UNIMPINS, handle_exception); |
| 570 | set_excp_vector(EXCEP_FPU_OPERATION, fpu_exception); | 600 | set_excp_vector(EXCEP_FPU_OPERATION, fpu_exception); |
| 571 | 601 | ||
| 572 | set_excp_vector(EXCEP_NMI, nmi); | 602 | set_excp_vector(EXCEP_NMI, nmi); |
| 573 | 603 | ||
| 574 | set_excp_vector(EXCEP_SYSCALL1, unsupported_syscall); | 604 | set_excp_vector(EXCEP_SYSCALL1, handle_exception); |
| 575 | set_excp_vector(EXCEP_SYSCALL2, unsupported_syscall); | 605 | set_excp_vector(EXCEP_SYSCALL2, handle_exception); |
| 576 | set_excp_vector(EXCEP_SYSCALL3, unsupported_syscall); | 606 | set_excp_vector(EXCEP_SYSCALL3, handle_exception); |
| 577 | set_excp_vector(EXCEP_SYSCALL4, unsupported_syscall); | 607 | set_excp_vector(EXCEP_SYSCALL4, handle_exception); |
| 578 | set_excp_vector(EXCEP_SYSCALL5, unsupported_syscall); | 608 | set_excp_vector(EXCEP_SYSCALL5, handle_exception); |
| 579 | set_excp_vector(EXCEP_SYSCALL6, unsupported_syscall); | 609 | set_excp_vector(EXCEP_SYSCALL6, handle_exception); |
| 580 | set_excp_vector(EXCEP_SYSCALL7, unsupported_syscall); | 610 | set_excp_vector(EXCEP_SYSCALL7, handle_exception); |
| 581 | set_excp_vector(EXCEP_SYSCALL8, unsupported_syscall); | 611 | set_excp_vector(EXCEP_SYSCALL8, handle_exception); |
| 582 | set_excp_vector(EXCEP_SYSCALL9, unsupported_syscall); | 612 | set_excp_vector(EXCEP_SYSCALL9, handle_exception); |
| 583 | set_excp_vector(EXCEP_SYSCALL10, unsupported_syscall); | 613 | set_excp_vector(EXCEP_SYSCALL10, handle_exception); |
| 584 | set_excp_vector(EXCEP_SYSCALL11, unsupported_syscall); | 614 | set_excp_vector(EXCEP_SYSCALL11, handle_exception); |
| 585 | set_excp_vector(EXCEP_SYSCALL12, unsupported_syscall); | 615 | set_excp_vector(EXCEP_SYSCALL12, handle_exception); |
| 586 | set_excp_vector(EXCEP_SYSCALL13, unsupported_syscall); | 616 | set_excp_vector(EXCEP_SYSCALL13, handle_exception); |
| 587 | set_excp_vector(EXCEP_SYSCALL14, unsupported_syscall); | 617 | set_excp_vector(EXCEP_SYSCALL14, handle_exception); |
| 588 | set_excp_vector(EXCEP_SYSCALL15, unsupported_syscall); | 618 | set_excp_vector(EXCEP_SYSCALL15, handle_exception); |
| 589 | } | 619 | } |
| 590 | 620 | ||
| 591 | /* | 621 | /* |
diff --git a/arch/mn10300/mm/Kconfig.cache b/arch/mn10300/mm/Kconfig.cache index c4fd923a55a0..bfbe52691f2c 100644 --- a/arch/mn10300/mm/Kconfig.cache +++ b/arch/mn10300/mm/Kconfig.cache | |||
| @@ -99,3 +99,49 @@ config MN10300_CACHE_INV_ICACHE | |||
| 99 | help | 99 | help |
| 100 | Set if we need the icache to be invalidated, even if the dcache is in | 100 | Set if we need the icache to be invalidated, even if the dcache is in |
| 101 | write-through mode and doesn't need flushing. | 101 | write-through mode and doesn't need flushing. |
| 102 | |||
| 103 | # | ||
| 104 | # The kernel debugger gets its own separate cache flushing functions | ||
| 105 | # | ||
| 106 | config MN10300_DEBUGGER_CACHE_FLUSH_BY_TAG | ||
| 107 | def_bool y if KERNEL_DEBUGGER && \ | ||
| 108 | MN10300_CACHE_WBACK && \ | ||
| 109 | !MN10300_CACHE_SNOOP && \ | ||
| 110 | MN10300_CACHE_MANAGE_BY_TAG | ||
| 111 | help | ||
| 112 | Set if the debugger needs to flush the dcache and invalidate the | ||
| 113 | icache using the cache tag registers to make breakpoints work. | ||
| 114 | |||
| 115 | config MN10300_DEBUGGER_CACHE_FLUSH_BY_REG | ||
| 116 | def_bool y if KERNEL_DEBUGGER && \ | ||
| 117 | MN10300_CACHE_WBACK && \ | ||
| 118 | !MN10300_CACHE_SNOOP && \ | ||
| 119 | MN10300_CACHE_MANAGE_BY_REG | ||
| 120 | help | ||
| 121 | Set if the debugger needs to flush the dcache and invalidate the | ||
| 122 | icache using automatic purge registers to make breakpoints work. | ||
| 123 | |||
| 124 | config MN10300_DEBUGGER_CACHE_INV_BY_TAG | ||
| 125 | def_bool y if KERNEL_DEBUGGER && \ | ||
| 126 | MN10300_CACHE_WTHRU && \ | ||
| 127 | !MN10300_CACHE_SNOOP && \ | ||
| 128 | MN10300_CACHE_MANAGE_BY_TAG | ||
| 129 | help | ||
| 130 | Set if the debugger needs to invalidate the icache using the cache | ||
| 131 | tag registers to make breakpoints work. | ||
| 132 | |||
| 133 | config MN10300_DEBUGGER_CACHE_INV_BY_REG | ||
| 134 | def_bool y if KERNEL_DEBUGGER && \ | ||
| 135 | MN10300_CACHE_WTHRU && \ | ||
| 136 | !MN10300_CACHE_SNOOP && \ | ||
| 137 | MN10300_CACHE_MANAGE_BY_REG | ||
| 138 | help | ||
| 139 | Set if the debugger needs to invalidate the icache using automatic | ||
| 140 | purge registers to make breakpoints work. | ||
| 141 | |||
| 142 | config MN10300_DEBUGGER_CACHE_NO_FLUSH | ||
| 143 | def_bool y if KERNEL_DEBUGGER && \ | ||
| 144 | (MN10300_CACHE_DISABLED || MN10300_CACHE_SNOOP) | ||
| 145 | help | ||
| 146 | Set if the debugger does not need to flush the dcache and/or | ||
| 147 | invalidate the icache to make breakpoints work. | ||
diff --git a/arch/mn10300/mm/Makefile b/arch/mn10300/mm/Makefile index 203fee23f7d7..11f38466ac28 100644 --- a/arch/mn10300/mm/Makefile +++ b/arch/mn10300/mm/Makefile | |||
| @@ -13,6 +13,15 @@ cacheflush-$(CONFIG_MN10300_CACHE_INV_BY_REG) += cache-inv-by-reg.o | |||
| 13 | cacheflush-$(CONFIG_MN10300_CACHE_FLUSH_BY_TAG) += cache-flush-by-tag.o | 13 | cacheflush-$(CONFIG_MN10300_CACHE_FLUSH_BY_TAG) += cache-flush-by-tag.o |
| 14 | cacheflush-$(CONFIG_MN10300_CACHE_FLUSH_BY_REG) += cache-flush-by-reg.o | 14 | cacheflush-$(CONFIG_MN10300_CACHE_FLUSH_BY_REG) += cache-flush-by-reg.o |
| 15 | 15 | ||
| 16 | cacheflush-$(CONFIG_MN10300_DEBUGGER_CACHE_FLUSH_BY_TAG) += \ | ||
| 17 | cache-dbg-flush-by-tag.o cache-dbg-inv-by-tag.o | ||
| 18 | cacheflush-$(CONFIG_MN10300_DEBUGGER_CACHE_FLUSH_BY_REG) += \ | ||
| 19 | cache-dbg-flush-by-reg.o | ||
| 20 | cacheflush-$(CONFIG_MN10300_DEBUGGER_CACHE_INV_BY_TAG) += \ | ||
| 21 | cache-dbg-inv-by-tag.o cache-dbg-inv.o | ||
| 22 | cacheflush-$(CONFIG_MN10300_DEBUGGER_CACHE_INV_BY_REG) += \ | ||
| 23 | cache-dbg-inv-by-reg.o cache-dbg-inv.o | ||
| 24 | |||
| 16 | cacheflush-$(CONFIG_MN10300_CACHE_DISABLED) := cache-disabled.o | 25 | cacheflush-$(CONFIG_MN10300_CACHE_DISABLED) := cache-disabled.o |
| 17 | 26 | ||
| 18 | obj-y := \ | 27 | obj-y := \ |
diff --git a/arch/mn10300/mm/cache-dbg-flush-by-reg.S b/arch/mn10300/mm/cache-dbg-flush-by-reg.S new file mode 100644 index 000000000000..665919f2ab62 --- /dev/null +++ b/arch/mn10300/mm/cache-dbg-flush-by-reg.S | |||
| @@ -0,0 +1,160 @@ | |||
| 1 | /* MN10300 CPU cache invalidation routines, using automatic purge registers | ||
| 2 | * | ||
| 3 | * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | #include <linux/sys.h> | ||
| 12 | #include <linux/linkage.h> | ||
| 13 | #include <asm/smp.h> | ||
| 14 | #include <asm/page.h> | ||
| 15 | #include <asm/cache.h> | ||
| 16 | #include <asm/irqflags.h> | ||
| 17 | #include <asm/cacheflush.h> | ||
| 18 | #include "cache.inc" | ||
| 19 | |||
| 20 | .am33_2 | ||
| 21 | |||
| 22 | ############################################################################### | ||
| 23 | # | ||
| 24 | # void debugger_local_cache_flushinv(void) | ||
| 25 | # Flush the entire data cache back to RAM and invalidate the icache | ||
| 26 | # | ||
| 27 | ############################################################################### | ||
| 28 | ALIGN | ||
| 29 | .globl debugger_local_cache_flushinv | ||
| 30 | .type debugger_local_cache_flushinv,@function | ||
| 31 | debugger_local_cache_flushinv: | ||
| 32 | # | ||
| 33 | # firstly flush the dcache | ||
| 34 | # | ||
| 35 | movhu (CHCTR),d0 | ||
| 36 | btst CHCTR_DCEN|CHCTR_ICEN,d0 | ||
| 37 | beq debugger_local_cache_flushinv_end | ||
| 38 | |||
| 39 | mov DCPGCR,a0 | ||
| 40 | |||
| 41 | mov epsw,d1 | ||
| 42 | and ~EPSW_IE,epsw | ||
| 43 | or EPSW_NMID,epsw | ||
| 44 | nop | ||
| 45 | |||
| 46 | btst CHCTR_DCEN,d0 | ||
| 47 | beq debugger_local_cache_flushinv_no_dcache | ||
| 48 | |||
| 49 | # wait for busy bit of area purge | ||
| 50 | setlb | ||
| 51 | mov (a0),d0 | ||
| 52 | btst DCPGCR_DCPGBSY,d0 | ||
| 53 | lne | ||
| 54 | |||
| 55 | # set mask | ||
| 56 | clr d0 | ||
| 57 | mov d0,(DCPGMR) | ||
| 58 | |||
| 59 | # area purge | ||
| 60 | # | ||
| 61 | # DCPGCR = DCPGCR_DCP | ||
| 62 | # | ||
| 63 | mov DCPGCR_DCP,d0 | ||
| 64 | mov d0,(a0) | ||
| 65 | |||
| 66 | # wait for busy bit of area purge | ||
| 67 | setlb | ||
| 68 | mov (a0),d0 | ||
| 69 | btst DCPGCR_DCPGBSY,d0 | ||
| 70 | lne | ||
| 71 | |||
| 72 | debugger_local_cache_flushinv_no_dcache: | ||
| 73 | # | ||
| 74 | # secondly, invalidate the icache if it is enabled | ||
| 75 | # | ||
| 76 | mov CHCTR,a0 | ||
| 77 | movhu (a0),d0 | ||
| 78 | btst CHCTR_ICEN,d0 | ||
| 79 | beq debugger_local_cache_flushinv_done | ||
| 80 | |||
| 81 | invalidate_icache 0 | ||
| 82 | |||
| 83 | debugger_local_cache_flushinv_done: | ||
| 84 | mov d1,epsw | ||
| 85 | |||
| 86 | debugger_local_cache_flushinv_end: | ||
| 87 | ret [],0 | ||
| 88 | .size debugger_local_cache_flushinv,.-debugger_local_cache_flushinv | ||
| 89 | |||
| 90 | ############################################################################### | ||
| 91 | # | ||
| 92 | # void debugger_local_cache_flushinv_one(u8 *addr) | ||
| 93 | # | ||
| 94 | # Invalidate one particular cacheline if it's in the icache | ||
| 95 | # | ||
| 96 | ############################################################################### | ||
| 97 | ALIGN | ||
| 98 | .globl debugger_local_cache_flushinv_one | ||
| 99 | .type debugger_local_cache_flushinv_one,@function | ||
| 100 | debugger_local_cache_flushinv_one: | ||
| 101 | movhu (CHCTR),d1 | ||
| 102 | btst CHCTR_DCEN|CHCTR_ICEN,d1 | ||
| 103 | beq debugger_local_cache_flushinv_one_end | ||
| 104 | btst CHCTR_DCEN,d1 | ||
| 105 | beq debugger_local_cache_flushinv_one_no_dcache | ||
| 106 | |||
| 107 | # round cacheline addr down | ||
| 108 | and L1_CACHE_TAG_MASK,d0 | ||
| 109 | mov d0,a1 | ||
| 110 | mov d0,d1 | ||
| 111 | |||
| 112 | # determine the dcache purge control reg address | ||
| 113 | mov DCACHE_PURGE(0,0),a0 | ||
| 114 | and L1_CACHE_TAG_ENTRY,d0 | ||
| 115 | add d0,a0 | ||
| 116 | |||
| 117 | # retain valid entries in the cache | ||
| 118 | or L1_CACHE_TAG_VALID,d1 | ||
| 119 | |||
| 120 | # conditionally purge this line in all ways | ||
| 121 | mov d1,(L1_CACHE_WAYDISP*0,a0) | ||
| 122 | |||
| 123 | debugger_local_cache_flushinv_no_dcache: | ||
| 124 | # | ||
| 125 | # now try to flush the icache | ||
| 126 | # | ||
| 127 | mov CHCTR,a0 | ||
| 128 | movhu (a0),d0 | ||
| 129 | btst CHCTR_ICEN,d0 | ||
| 130 | beq mn10300_local_icache_inv_range_reg_end | ||
| 131 | |||
| 132 | LOCAL_CLI_SAVE(d1) | ||
| 133 | |||
| 134 | mov ICIVCR,a0 | ||
| 135 | |||
| 136 | # wait for the invalidator to quiesce | ||
| 137 | setlb | ||
| 138 | mov (a0),d0 | ||
| 139 | btst ICIVCR_ICIVBSY,d0 | ||
| 140 | lne | ||
| 141 | |||
| 142 | # set the mask | ||
| 143 | mov L1_CACHE_TAG_MASK,d0 | ||
| 144 | mov d0,(ICIVMR) | ||
| 145 | |||
| 146 | # invalidate the cache line at the given address | ||
| 147 | or ICIVCR_ICI,a1 | ||
| 148 | mov a1,(a0) | ||
| 149 | |||
| 150 | # wait for the invalidator to quiesce again | ||
| 151 | setlb | ||
| 152 | mov (a0),d0 | ||
| 153 | btst ICIVCR_ICIVBSY,d0 | ||
| 154 | lne | ||
| 155 | |||
| 156 | LOCAL_IRQ_RESTORE(d1) | ||
| 157 | |||
| 158 | debugger_local_cache_flushinv_one_end: | ||
| 159 | ret [],0 | ||
| 160 | .size debugger_local_cache_flushinv_one,.-debugger_local_cache_flushinv_one | ||
diff --git a/arch/mn10300/mm/cache-dbg-flush-by-tag.S b/arch/mn10300/mm/cache-dbg-flush-by-tag.S new file mode 100644 index 000000000000..bf56930e6e70 --- /dev/null +++ b/arch/mn10300/mm/cache-dbg-flush-by-tag.S | |||
| @@ -0,0 +1,114 @@ | |||
| 1 | /* MN10300 CPU cache invalidation routines, using direct tag flushing | ||
| 2 | * | ||
| 3 | * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | #include <linux/sys.h> | ||
| 12 | #include <linux/linkage.h> | ||
| 13 | #include <asm/smp.h> | ||
| 14 | #include <asm/page.h> | ||
| 15 | #include <asm/cache.h> | ||
| 16 | #include <asm/irqflags.h> | ||
| 17 | #include <asm/cacheflush.h> | ||
| 18 | #include "cache.inc" | ||
| 19 | |||
| 20 | .am33_2 | ||
| 21 | |||
| 22 | ############################################################################### | ||
| 23 | # | ||
| 24 | # void debugger_local_cache_flushinv(void) | ||
| 25 | # | ||
| 26 | # Flush the entire data cache back to RAM and invalidate the icache | ||
| 27 | # | ||
| 28 | ############################################################################### | ||
| 29 | ALIGN | ||
| 30 | .globl debugger_local_cache_flushinv | ||
| 31 | .type debugger_local_cache_flushinv,@function | ||
| 32 | debugger_local_cache_flushinv: | ||
| 33 | # | ||
| 34 | # firstly flush the dcache | ||
| 35 | # | ||
| 36 | movhu (CHCTR),d0 | ||
| 37 | btst CHCTR_DCEN|CHCTR_ICEN,d0 | ||
| 38 | beq debugger_local_cache_flushinv_end | ||
| 39 | |||
| 40 | btst CHCTR_DCEN,d0 | ||
| 41 | beq debugger_local_cache_flushinv_no_dcache | ||
| 42 | |||
| 43 | # read the addresses tagged in the cache's tag RAM and attempt to flush | ||
| 44 | # those addresses specifically | ||
| 45 | # - we rely on the hardware to filter out invalid tag entry addresses | ||
| 46 | mov DCACHE_TAG(0,0),a0 # dcache tag RAM access address | ||
| 47 | mov DCACHE_PURGE(0,0),a1 # dcache purge request address | ||
| 48 | mov L1_CACHE_NWAYS*L1_CACHE_NENTRIES,e0 # total number of entries | ||
| 49 | |||
| 50 | mn10300_local_dcache_flush_loop: | ||
| 51 | mov (a0),d0 | ||
| 52 | and L1_CACHE_TAG_MASK,d0 | ||
| 53 | or L1_CACHE_TAG_VALID,d0 # retain valid entries in the | ||
| 54 | # cache | ||
| 55 | mov d0,(a1) # conditional purge | ||
| 56 | |||
| 57 | add L1_CACHE_BYTES,a0 | ||
| 58 | add L1_CACHE_BYTES,a1 | ||
| 59 | add -1,e0 | ||
| 60 | bne mn10300_local_dcache_flush_loop | ||
| 61 | |||
| 62 | debugger_local_cache_flushinv_no_dcache: | ||
| 63 | # | ||
| 64 | # secondly, invalidate the icache if it is enabled | ||
| 65 | # | ||
| 66 | mov CHCTR,a0 | ||
| 67 | movhu (a0),d0 | ||
| 68 | btst CHCTR_ICEN,d0 | ||
| 69 | beq debugger_local_cache_flushinv_end | ||
| 70 | |||
| 71 | invalidate_icache 1 | ||
| 72 | |||
| 73 | debugger_local_cache_flushinv_end: | ||
| 74 | ret [],0 | ||
| 75 | .size debugger_local_cache_flushinv,.-debugger_local_cache_flushinv | ||
| 76 | |||
| 77 | ############################################################################### | ||
| 78 | # | ||
| 79 | # void debugger_local_cache_flushinv_one(u8 *addr) | ||
| 80 | # | ||
| 81 | # Invalidate one particular cacheline if it's in the icache | ||
| 82 | # | ||
| 83 | ############################################################################### | ||
| 84 | ALIGN | ||
| 85 | .globl debugger_local_cache_flushinv_one | ||
| 86 | .type debugger_local_cache_flushinv_one,@function | ||
| 87 | debugger_local_cache_flushinv_one: | ||
| 88 | movhu (CHCTR),d1 | ||
| 89 | btst CHCTR_DCEN|CHCTR_ICEN,d1 | ||
| 90 | beq debugger_local_cache_flushinv_one_end | ||
| 91 | btst CHCTR_DCEN,d1 | ||
| 92 | beq debugger_local_cache_flushinv_one_icache | ||
| 93 | |||
| 94 | # round cacheline addr down | ||
| 95 | and L1_CACHE_TAG_MASK,d0 | ||
| 96 | mov d0,a1 | ||
| 97 | |||
| 98 | # determine the dcache purge control reg address | ||
| 99 | mov DCACHE_PURGE(0,0),a0 | ||
| 100 | and L1_CACHE_TAG_ENTRY,d0 | ||
| 101 | add d0,a0 | ||
| 102 | |||
| 103 | # retain valid entries in the cache | ||
| 104 | or L1_CACHE_TAG_VALID,a1 | ||
| 105 | |||
| 106 | # conditionally purge this line in all ways | ||
| 107 | mov a1,(L1_CACHE_WAYDISP*0,a0) | ||
| 108 | |||
| 109 | # now go and do the icache | ||
| 110 | bra debugger_local_cache_flushinv_one_icache | ||
| 111 | |||
| 112 | debugger_local_cache_flushinv_one_end: | ||
| 113 | ret [],0 | ||
| 114 | .size debugger_local_cache_flushinv_one,.-debugger_local_cache_flushinv_one | ||
diff --git a/arch/mn10300/mm/cache-dbg-inv-by-reg.S b/arch/mn10300/mm/cache-dbg-inv-by-reg.S new file mode 100644 index 000000000000..c4e6252941b1 --- /dev/null +++ b/arch/mn10300/mm/cache-dbg-inv-by-reg.S | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | /* MN10300 CPU cache invalidation routines, using automatic purge registers | ||
| 2 | * | ||
| 3 | * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | #include <linux/sys.h> | ||
| 12 | #include <linux/linkage.h> | ||
| 13 | #include <asm/cache.h> | ||
| 14 | #include <asm/irqflags.h> | ||
| 15 | #include <asm/cacheflush.h> | ||
| 16 | #include "cache.inc" | ||
| 17 | |||
| 18 | .am33_2 | ||
| 19 | |||
| 20 | .globl debugger_local_cache_flushinv_one | ||
| 21 | |||
| 22 | ############################################################################### | ||
| 23 | # | ||
| 24 | # void debugger_local_cache_flushinv_one(u8 *addr) | ||
| 25 | # | ||
| 26 | # Invalidate one particular cacheline if it's in the icache | ||
| 27 | # | ||
| 28 | ############################################################################### | ||
| 29 | ALIGN | ||
| 30 | .globl debugger_local_cache_flushinv_one | ||
| 31 | .type debugger_local_cache_flushinv_one,@function | ||
| 32 | debugger_local_cache_flushinv_one: | ||
| 33 | mov d0,a1 | ||
| 34 | |||
| 35 | mov CHCTR,a0 | ||
| 36 | movhu (a0),d0 | ||
| 37 | btst CHCTR_ICEN,d0 | ||
| 38 | beq mn10300_local_icache_inv_range_reg_end | ||
| 39 | |||
| 40 | LOCAL_CLI_SAVE(d1) | ||
| 41 | |||
| 42 | mov ICIVCR,a0 | ||
| 43 | |||
| 44 | # wait for the invalidator to quiesce | ||
| 45 | setlb | ||
| 46 | mov (a0),d0 | ||
| 47 | btst ICIVCR_ICIVBSY,d0 | ||
| 48 | lne | ||
| 49 | |||
| 50 | # set the mask | ||
| 51 | mov ~L1_CACHE_TAG_MASK,d0 | ||
| 52 | mov d0,(ICIVMR) | ||
| 53 | |||
| 54 | # invalidate the cache line at the given address | ||
| 55 | and ~L1_CACHE_TAG_MASK,a1 | ||
| 56 | or ICIVCR_ICI,a1 | ||
| 57 | mov a1,(a0) | ||
| 58 | |||
| 59 | # wait for the invalidator to quiesce again | ||
| 60 | setlb | ||
| 61 | mov (a0),d0 | ||
| 62 | btst ICIVCR_ICIVBSY,d0 | ||
| 63 | lne | ||
| 64 | |||
| 65 | LOCAL_IRQ_RESTORE(d1) | ||
| 66 | |||
| 67 | mn10300_local_icache_inv_range_reg_end: | ||
| 68 | ret [],0 | ||
| 69 | .size debugger_local_cache_flushinv_one,.-debugger_local_cache_flushinv_one | ||
diff --git a/arch/mn10300/mm/cache-dbg-inv-by-tag.S b/arch/mn10300/mm/cache-dbg-inv-by-tag.S new file mode 100644 index 000000000000..d8ec821e5f88 --- /dev/null +++ b/arch/mn10300/mm/cache-dbg-inv-by-tag.S | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | /* MN10300 CPU cache invalidation routines, using direct tag flushing | ||
| 2 | * | ||
| 3 | * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | #include <linux/sys.h> | ||
| 12 | #include <linux/linkage.h> | ||
| 13 | #include <asm/smp.h> | ||
| 14 | #include <asm/page.h> | ||
| 15 | #include <asm/cache.h> | ||
| 16 | #include <asm/irqflags.h> | ||
| 17 | #include <asm/cacheflush.h> | ||
| 18 | #include "cache.inc" | ||
| 19 | |||
| 20 | .am33_2 | ||
| 21 | |||
| 22 | .globl debugger_local_cache_flushinv_one_icache | ||
| 23 | |||
| 24 | ############################################################################### | ||
| 25 | # | ||
| 26 | # void debugger_local_cache_flushinv_one(u8 *addr) | ||
| 27 | # | ||
| 28 | # Invalidate one particular cacheline if it's in the icache | ||
| 29 | # | ||
| 30 | ############################################################################### | ||
| 31 | ALIGN | ||
| 32 | .globl debugger_local_cache_flushinv_one_icache | ||
| 33 | .type debugger_local_cache_flushinv_one_icache,@function | ||
| 34 | debugger_local_cache_flushinv_one_icache: | ||
| 35 | movm [d3,a2],(sp) | ||
| 36 | |||
| 37 | mov CHCTR,a2 | ||
| 38 | movhu (a2),d0 | ||
| 39 | btst CHCTR_ICEN,d0 | ||
| 40 | beq debugger_local_cache_flushinv_one_icache_end | ||
| 41 | |||
| 42 | mov d0,a1 | ||
| 43 | and L1_CACHE_TAG_MASK,a1 | ||
| 44 | |||
| 45 | # read the tags from the tag RAM, and if they indicate a matching valid | ||
| 46 | # cache line then we invalidate that line | ||
| 47 | mov ICACHE_TAG(0,0),a0 | ||
| 48 | mov a1,d0 | ||
| 49 | and L1_CACHE_TAG_ENTRY,d0 | ||
| 50 | add d0,a0 # starting icache tag RAM | ||
| 51 | # access address | ||
| 52 | |||
| 53 | and ~(L1_CACHE_DISPARITY-1),a1 # determine comparator base | ||
| 54 | or L1_CACHE_TAG_VALID,a1 | ||
| 55 | mov L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_VALID,d1 | ||
| 56 | |||
| 57 | LOCAL_CLI_SAVE(d3) | ||
| 58 | |||
| 59 | # disable the icache | ||
| 60 | movhu (a2),d0 | ||
| 61 | and ~CHCTR_ICEN,d0 | ||
| 62 | movhu d0,(a2) | ||
| 63 | |||
| 64 | # and wait for it to calm down | ||
| 65 | setlb | ||
| 66 | movhu (a2),d0 | ||
| 67 | btst CHCTR_ICBUSY,d0 | ||
| 68 | lne | ||
| 69 | |||
| 70 | # check all the way tags for this cache entry | ||
| 71 | mov (a0),d0 # read the tag in the way 0 slot | ||
| 72 | xor a1,d0 | ||
| 73 | and d1,d0 | ||
| 74 | beq debugger_local_icache_kill # jump if matched | ||
| 75 | |||
| 76 | add L1_CACHE_WAYDISP,a0 | ||
| 77 | mov (a0),d0 # read the tag in the way 1 slot | ||
| 78 | xor a1,d0 | ||
| 79 | and d1,d0 | ||
| 80 | beq debugger_local_icache_kill # jump if matched | ||
| 81 | |||
| 82 | add L1_CACHE_WAYDISP,a0 | ||
| 83 | mov (a0),d0 # read the tag in the way 2 slot | ||
| 84 | xor a1,d0 | ||
| 85 | and d1,d0 | ||
| 86 | beq debugger_local_icache_kill # jump if matched | ||
| 87 | |||
| 88 | add L1_CACHE_WAYDISP,a0 | ||
| 89 | mov (a0),d0 # read the tag in the way 3 slot | ||
| 90 | xor a1,d0 | ||
| 91 | and d1,d0 | ||
| 92 | bne debugger_local_icache_finish # jump if not matched | ||
| 93 | |||
| 94 | debugger_local_icache_kill: | ||
| 95 | mov d0,(a0) # kill the tag (D0 is 0 at this point) | ||
| 96 | |||
| 97 | debugger_local_icache_finish: | ||
| 98 | # wait for the cache to finish what it's doing | ||
| 99 | setlb | ||
| 100 | movhu (a2),d0 | ||
| 101 | btst CHCTR_ICBUSY,d0 | ||
| 102 | lne | ||
| 103 | |||
| 104 | # and reenable it | ||
| 105 | or CHCTR_ICEN,d0 | ||
| 106 | movhu d0,(a2) | ||
| 107 | movhu (a2),d0 | ||
| 108 | |||
| 109 | # re-enable interrupts | ||
| 110 | LOCAL_IRQ_RESTORE(d3) | ||
| 111 | |||
| 112 | debugger_local_cache_flushinv_one_icache_end: | ||
| 113 | ret [d3,a2],8 | ||
| 114 | .size debugger_local_cache_flushinv_one_icache,.-debugger_local_cache_flushinv_one_icache | ||
| 115 | |||
| 116 | #ifdef CONFIG_MN10300_DEBUGGER_CACHE_INV_BY_TAG | ||
| 117 | .globl debugger_local_cache_flushinv_one | ||
| 118 | .type debugger_local_cache_flushinv_one,@function | ||
| 119 | debugger_local_cache_flushinv_one = debugger_local_cache_flushinv_one_icache | ||
| 120 | #endif | ||
diff --git a/arch/mn10300/mm/cache-dbg-inv.S b/arch/mn10300/mm/cache-dbg-inv.S new file mode 100644 index 000000000000..eba2d6dca066 --- /dev/null +++ b/arch/mn10300/mm/cache-dbg-inv.S | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | /* MN10300 CPU cache invalidation routines | ||
| 2 | * | ||
| 3 | * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | #include <linux/sys.h> | ||
| 12 | #include <linux/linkage.h> | ||
| 13 | #include <asm/smp.h> | ||
| 14 | #include <asm/page.h> | ||
| 15 | #include <asm/cache.h> | ||
| 16 | #include <asm/irqflags.h> | ||
| 17 | #include <asm/cacheflush.h> | ||
| 18 | #include "cache.inc" | ||
| 19 | |||
| 20 | .am33_2 | ||
| 21 | |||
| 22 | .globl debugger_local_cache_flushinv | ||
| 23 | |||
| 24 | ############################################################################### | ||
| 25 | # | ||
| 26 | # void debugger_local_cache_flushinv(void) | ||
| 27 | # | ||
| 28 | # Invalidate the entire icache | ||
| 29 | # | ||
| 30 | ############################################################################### | ||
| 31 | ALIGN | ||
| 32 | .globl debugger_local_cache_flushinv | ||
| 33 | .type debugger_local_cache_flushinv,@function | ||
| 34 | debugger_local_cache_flushinv: | ||
| 35 | # | ||
| 36 | # we only need to invalidate the icache in this cache mode | ||
| 37 | # | ||
| 38 | mov CHCTR,a0 | ||
| 39 | movhu (a0),d0 | ||
| 40 | btst CHCTR_ICEN,d0 | ||
| 41 | beq debugger_local_cache_flushinv_end | ||
| 42 | |||
| 43 | invalidate_icache 1 | ||
| 44 | |||
| 45 | debugger_local_cache_flushinv_end: | ||
| 46 | ret [],0 | ||
| 47 | .size debugger_local_cache_flushinv,.-debugger_local_cache_flushinv | ||
diff --git a/arch/mn10300/mm/cache-flush-by-tag.S b/arch/mn10300/mm/cache-flush-by-tag.S index 5cd6a27dd63e..1ddc06849242 100644 --- a/arch/mn10300/mm/cache-flush-by-tag.S +++ b/arch/mn10300/mm/cache-flush-by-tag.S | |||
| @@ -62,7 +62,7 @@ mn10300_local_dcache_flush: | |||
| 62 | 62 | ||
| 63 | mn10300_local_dcache_flush_loop: | 63 | mn10300_local_dcache_flush_loop: |
| 64 | mov (a0),d0 | 64 | mov (a0),d0 |
| 65 | and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 | 65 | and L1_CACHE_TAG_MASK,d0 |
| 66 | or L1_CACHE_TAG_VALID,d0 # retain valid entries in the | 66 | or L1_CACHE_TAG_VALID,d0 # retain valid entries in the |
| 67 | # cache | 67 | # cache |
| 68 | mov d0,(a1) # conditional purge | 68 | mov d0,(a1) # conditional purge |
| @@ -112,11 +112,11 @@ mn10300_local_dcache_flush_range: | |||
| 112 | 1: | 112 | 1: |
| 113 | 113 | ||
| 114 | # round start addr down | 114 | # round start addr down |
| 115 | and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 | 115 | and L1_CACHE_TAG_MASK,d0 |
| 116 | mov d0,a1 | 116 | mov d0,a1 |
| 117 | 117 | ||
| 118 | add L1_CACHE_BYTES,d1 # round end addr up | 118 | add L1_CACHE_BYTES,d1 # round end addr up |
| 119 | and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1 | 119 | and L1_CACHE_TAG_MASK,d1 |
| 120 | 120 | ||
| 121 | # write a request to flush all instances of an address from the cache | 121 | # write a request to flush all instances of an address from the cache |
| 122 | mov DCACHE_PURGE(0,0),a0 | 122 | mov DCACHE_PURGE(0,0),a0 |
| @@ -215,12 +215,11 @@ mn10300_local_dcache_flush_inv_range: | |||
| 215 | bra mn10300_local_dcache_flush_inv | 215 | bra mn10300_local_dcache_flush_inv |
| 216 | 1: | 216 | 1: |
| 217 | 217 | ||
| 218 | and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start | 218 | and L1_CACHE_TAG_MASK,d0 # round start addr down |
| 219 | # addr down | ||
| 220 | mov d0,a1 | 219 | mov d0,a1 |
| 221 | 220 | ||
| 222 | add L1_CACHE_BYTES,d1 # round end addr up | 221 | add L1_CACHE_BYTES,d1 # round end addr up |
| 223 | and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1 | 222 | and L1_CACHE_TAG_MASK,d1 |
| 224 | 223 | ||
| 225 | # write a request to flush and invalidate all instances of an address | 224 | # write a request to flush and invalidate all instances of an address |
| 226 | # from the cache | 225 | # from the cache |
diff --git a/arch/mn10300/mm/cache-inv-by-reg.S b/arch/mn10300/mm/cache-inv-by-reg.S index c8950861ed77..a60825b91e77 100644 --- a/arch/mn10300/mm/cache-inv-by-reg.S +++ b/arch/mn10300/mm/cache-inv-by-reg.S | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <asm/cache.h> | 15 | #include <asm/cache.h> |
| 16 | #include <asm/irqflags.h> | 16 | #include <asm/irqflags.h> |
| 17 | #include <asm/cacheflush.h> | 17 | #include <asm/cacheflush.h> |
| 18 | #include "cache.inc" | ||
| 18 | 19 | ||
| 19 | #define mn10300_local_dcache_inv_range_intr_interval \ | 20 | #define mn10300_local_dcache_inv_range_intr_interval \ |
| 20 | +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1) | 21 | +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1) |
| @@ -62,10 +63,7 @@ mn10300_local_icache_inv: | |||
| 62 | btst CHCTR_ICEN,d0 | 63 | btst CHCTR_ICEN,d0 |
| 63 | beq mn10300_local_icache_inv_end | 64 | beq mn10300_local_icache_inv_end |
| 64 | 65 | ||
| 65 | # invalidate | 66 | invalidate_icache 1 |
| 66 | or CHCTR_ICINV,d0 | ||
| 67 | movhu d0,(a0) | ||
| 68 | movhu (a0),d0 | ||
| 69 | 67 | ||
| 70 | mn10300_local_icache_inv_end: | 68 | mn10300_local_icache_inv_end: |
| 71 | ret [],0 | 69 | ret [],0 |
| @@ -87,11 +85,8 @@ mn10300_local_dcache_inv: | |||
| 87 | btst CHCTR_DCEN,d0 | 85 | btst CHCTR_DCEN,d0 |
| 88 | beq mn10300_local_dcache_inv_end | 86 | beq mn10300_local_dcache_inv_end |
| 89 | 87 | ||
| 90 | # invalidate | 88 | invalidate_dcache 1 |
| 91 | or CHCTR_DCINV,d0 | 89 | |
| 92 | movhu d0,(a0) | ||
| 93 | movhu (a0),d0 | ||
| 94 | |||
| 95 | mn10300_local_dcache_inv_end: | 90 | mn10300_local_dcache_inv_end: |
| 96 | ret [],0 | 91 | ret [],0 |
| 97 | .size mn10300_local_dcache_inv,.-mn10300_local_dcache_inv | 92 | .size mn10300_local_dcache_inv,.-mn10300_local_dcache_inv |
| @@ -121,9 +116,9 @@ mn10300_local_dcache_inv_range: | |||
| 121 | # and if they're not cacheline-aligned, we must flush any bits outside | 116 | # and if they're not cacheline-aligned, we must flush any bits outside |
| 122 | # the range that share cachelines with stuff inside the range | 117 | # the range that share cachelines with stuff inside the range |
| 123 | #ifdef CONFIG_MN10300_CACHE_WBACK | 118 | #ifdef CONFIG_MN10300_CACHE_WBACK |
| 124 | btst ~(L1_CACHE_BYTES-1),d0 | 119 | btst ~L1_CACHE_TAG_MASK,d0 |
| 125 | bne 1f | 120 | bne 1f |
| 126 | btst ~(L1_CACHE_BYTES-1),d1 | 121 | btst ~L1_CACHE_TAG_MASK,d1 |
| 127 | beq 2f | 122 | beq 2f |
| 128 | 1: | 123 | 1: |
| 129 | bra mn10300_local_dcache_flush_inv_range | 124 | bra mn10300_local_dcache_flush_inv_range |
| @@ -141,12 +136,11 @@ mn10300_local_dcache_inv_range: | |||
| 141 | # writeback mode, in which case we would be in flush and invalidate by | 136 | # writeback mode, in which case we would be in flush and invalidate by |
| 142 | # now | 137 | # now |
| 143 | #ifndef CONFIG_MN10300_CACHE_WBACK | 138 | #ifndef CONFIG_MN10300_CACHE_WBACK |
| 144 | and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start | 139 | and L1_CACHE_TAG_MASK,d0 # round start addr down |
| 145 | # addr down | ||
| 146 | 140 | ||
| 147 | mov L1_CACHE_BYTES-1,d2 | 141 | mov L1_CACHE_BYTES-1,d2 |
| 148 | add d2,d1 | 142 | add d2,d1 |
| 149 | and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1 # round end addr up | 143 | and L1_CACHE_TAG_MASK,d1 # round end addr up |
| 150 | #endif /* !CONFIG_MN10300_CACHE_WBACK */ | 144 | #endif /* !CONFIG_MN10300_CACHE_WBACK */ |
| 151 | 145 | ||
| 152 | sub d0,d1,d2 # calculate the total size | 146 | sub d0,d1,d2 # calculate the total size |
diff --git a/arch/mn10300/mm/cache-inv-by-tag.S b/arch/mn10300/mm/cache-inv-by-tag.S index e9713b40c0ff..ccedce9c144d 100644 --- a/arch/mn10300/mm/cache-inv-by-tag.S +++ b/arch/mn10300/mm/cache-inv-by-tag.S | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <asm/cache.h> | 15 | #include <asm/cache.h> |
| 16 | #include <asm/irqflags.h> | 16 | #include <asm/irqflags.h> |
| 17 | #include <asm/cacheflush.h> | 17 | #include <asm/cacheflush.h> |
| 18 | #include "cache.inc" | ||
| 18 | 19 | ||
| 19 | #define mn10300_local_dcache_inv_range_intr_interval \ | 20 | #define mn10300_local_dcache_inv_range_intr_interval \ |
| 20 | +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1) | 21 | +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1) |
| @@ -70,43 +71,7 @@ mn10300_local_icache_inv: | |||
| 70 | btst CHCTR_ICEN,d0 | 71 | btst CHCTR_ICEN,d0 |
| 71 | beq mn10300_local_icache_inv_end | 72 | beq mn10300_local_icache_inv_end |
| 72 | 73 | ||
| 73 | #if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3) | 74 | invalidate_icache 1 |
| 74 | LOCAL_CLI_SAVE(d1) | ||
| 75 | |||
| 76 | # disable the icache | ||
| 77 | and ~CHCTR_ICEN,d0 | ||
| 78 | movhu d0,(a0) | ||
| 79 | |||
| 80 | # and wait for it to calm down | ||
| 81 | setlb | ||
| 82 | movhu (a0),d0 | ||
| 83 | btst CHCTR_ICBUSY,d0 | ||
| 84 | lne | ||
| 85 | |||
| 86 | # invalidate | ||
| 87 | or CHCTR_ICINV,d0 | ||
| 88 | movhu d0,(a0) | ||
| 89 | |||
| 90 | # wait for the cache to finish | ||
| 91 | mov CHCTR,a0 | ||
| 92 | setlb | ||
| 93 | movhu (a0),d0 | ||
| 94 | btst CHCTR_ICBUSY,d0 | ||
| 95 | lne | ||
| 96 | |||
| 97 | # and reenable it | ||
| 98 | and ~CHCTR_ICINV,d0 | ||
| 99 | or CHCTR_ICEN,d0 | ||
| 100 | movhu d0,(a0) | ||
| 101 | movhu (a0),d0 | ||
| 102 | |||
| 103 | LOCAL_IRQ_RESTORE(d1) | ||
| 104 | #else /* CONFIG_AM33_2 || CONFIG_AM33_3 */ | ||
| 105 | # invalidate | ||
| 106 | or CHCTR_ICINV,d0 | ||
| 107 | movhu d0,(a0) | ||
| 108 | movhu (a0),d0 | ||
| 109 | #endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */ | ||
| 110 | 75 | ||
| 111 | mn10300_local_icache_inv_end: | 76 | mn10300_local_icache_inv_end: |
| 112 | ret [],0 | 77 | ret [],0 |
| @@ -128,43 +93,7 @@ mn10300_local_dcache_inv: | |||
| 128 | btst CHCTR_DCEN,d0 | 93 | btst CHCTR_DCEN,d0 |
| 129 | beq mn10300_local_dcache_inv_end | 94 | beq mn10300_local_dcache_inv_end |
| 130 | 95 | ||
| 131 | #if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3) | 96 | invalidate_dcache 1 |
| 132 | LOCAL_CLI_SAVE(d1) | ||
| 133 | |||
| 134 | # disable the dcache | ||
| 135 | and ~CHCTR_DCEN,d0 | ||
| 136 | movhu d0,(a0) | ||
| 137 | |||
| 138 | # and wait for it to calm down | ||
| 139 | setlb | ||
| 140 | movhu (a0),d0 | ||
| 141 | btst CHCTR_DCBUSY,d0 | ||
| 142 | lne | ||
| 143 | |||
| 144 | # invalidate | ||
| 145 | or CHCTR_DCINV,d0 | ||
| 146 | movhu d0,(a0) | ||
| 147 | |||
| 148 | # wait for the cache to finish | ||
| 149 | mov CHCTR,a0 | ||
| 150 | setlb | ||
| 151 | movhu (a0),d0 | ||
| 152 | btst CHCTR_DCBUSY,d0 | ||
| 153 | lne | ||
| 154 | |||
| 155 | # and reenable it | ||
| 156 | and ~CHCTR_DCINV,d0 | ||
| 157 | or CHCTR_DCEN,d0 | ||
| 158 | movhu d0,(a0) | ||
| 159 | movhu (a0),d0 | ||
| 160 | |||
| 161 | LOCAL_IRQ_RESTORE(d1) | ||
| 162 | #else /* CONFIG_AM33_2 || CONFIG_AM33_3 */ | ||
| 163 | # invalidate | ||
| 164 | or CHCTR_DCINV,d0 | ||
| 165 | movhu d0,(a0) | ||
| 166 | movhu (a0),d0 | ||
| 167 | #endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */ | ||
| 168 | 97 | ||
| 169 | mn10300_local_dcache_inv_end: | 98 | mn10300_local_dcache_inv_end: |
| 170 | ret [],0 | 99 | ret [],0 |
| @@ -195,9 +124,9 @@ mn10300_local_dcache_inv_range: | |||
| 195 | # and if they're not cacheline-aligned, we must flush any bits outside | 124 | # and if they're not cacheline-aligned, we must flush any bits outside |
| 196 | # the range that share cachelines with stuff inside the range | 125 | # the range that share cachelines with stuff inside the range |
| 197 | #ifdef CONFIG_MN10300_CACHE_WBACK | 126 | #ifdef CONFIG_MN10300_CACHE_WBACK |
| 198 | btst ~(L1_CACHE_BYTES-1),d0 | 127 | btst ~L1_CACHE_TAG_MASK,d0 |
| 199 | bne 1f | 128 | bne 1f |
| 200 | btst ~(L1_CACHE_BYTES-1),d1 | 129 | btst ~L1_CACHE_TAG_MASK,d1 |
| 201 | beq 2f | 130 | beq 2f |
| 202 | 1: | 131 | 1: |
| 203 | bra mn10300_local_dcache_flush_inv_range | 132 | bra mn10300_local_dcache_flush_inv_range |
| @@ -212,11 +141,10 @@ mn10300_local_dcache_inv_range: | |||
| 212 | beq mn10300_local_dcache_inv_range_end | 141 | beq mn10300_local_dcache_inv_range_end |
| 213 | 142 | ||
| 214 | #ifndef CONFIG_MN10300_CACHE_WBACK | 143 | #ifndef CONFIG_MN10300_CACHE_WBACK |
| 215 | and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start | 144 | and L1_CACHE_TAG_MASK,d0 # round start addr down |
| 216 | # addr down | ||
| 217 | 145 | ||
| 218 | add L1_CACHE_BYTES,d1 # round end addr up | 146 | add L1_CACHE_BYTES,d1 # round end addr up |
| 219 | and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1 | 147 | and L1_CACHE_TAG_MASK,d1 |
| 220 | #endif /* !CONFIG_MN10300_CACHE_WBACK */ | 148 | #endif /* !CONFIG_MN10300_CACHE_WBACK */ |
| 221 | mov d0,a1 | 149 | mov d0,a1 |
| 222 | 150 | ||
diff --git a/arch/mn10300/mm/cache.inc b/arch/mn10300/mm/cache.inc new file mode 100644 index 000000000000..394a119b9c73 --- /dev/null +++ b/arch/mn10300/mm/cache.inc | |||
| @@ -0,0 +1,133 @@ | |||
| 1 | /* MN10300 CPU core caching macros -*- asm -*- | ||
| 2 | * | ||
| 3 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | |||
| 13 | ############################################################################### | ||
| 14 | # | ||
| 15 | # Invalidate the instruction cache. | ||
| 16 | # A0: Should hold CHCTR | ||
| 17 | # D0: Should have been read from CHCTR | ||
| 18 | # D1: Will be clobbered | ||
| 19 | # | ||
| 20 | # On some cores it is necessary to disable the icache whilst we do this. | ||
| 21 | # | ||
| 22 | ############################################################################### | ||
| 23 | .macro invalidate_icache,disable_irq | ||
| 24 | |||
| 25 | #if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3) | ||
| 26 | .if \disable_irq | ||
| 27 | # don't want an interrupt routine seeing a disabled cache | ||
| 28 | mov epsw,d1 | ||
| 29 | and ~EPSW_IE,epsw | ||
| 30 | or EPSW_NMID,epsw | ||
| 31 | nop | ||
| 32 | nop | ||
| 33 | .endif | ||
| 34 | |||
| 35 | # disable the icache | ||
| 36 | and ~CHCTR_ICEN,d0 | ||
| 37 | movhu d0,(a0) | ||
| 38 | |||
| 39 | # and wait for it to calm down | ||
| 40 | setlb | ||
| 41 | movhu (a0),d0 | ||
| 42 | btst CHCTR_ICBUSY,d0 | ||
| 43 | lne | ||
| 44 | |||
| 45 | # invalidate | ||
| 46 | or CHCTR_ICINV,d0 | ||
| 47 | movhu d0,(a0) | ||
| 48 | |||
| 49 | # wait for the cache to finish | ||
| 50 | setlb | ||
| 51 | movhu (a0),d0 | ||
| 52 | btst CHCTR_ICBUSY,d0 | ||
| 53 | lne | ||
| 54 | |||
| 55 | # and reenable it | ||
| 56 | or CHCTR_ICEN,d0 | ||
| 57 | movhu d0,(a0) | ||
| 58 | movhu (a0),d0 | ||
| 59 | |||
| 60 | .if \disable_irq | ||
| 61 | LOCAL_IRQ_RESTORE(d1) | ||
| 62 | .endif | ||
| 63 | |||
| 64 | #else /* CONFIG_AM33_2 || CONFIG_AM33_3 */ | ||
| 65 | |||
| 66 | # invalidate | ||
| 67 | or CHCTR_ICINV,d0 | ||
| 68 | movhu d0,(a0) | ||
| 69 | movhu (a0),d0 | ||
| 70 | |||
| 71 | #endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */ | ||
| 72 | .endm | ||
| 73 | |||
| 74 | ############################################################################### | ||
| 75 | # | ||
| 76 | # Invalidate the data cache. | ||
| 77 | # A0: Should hold CHCTR | ||
| 78 | # D0: Should have been read from CHCTR | ||
| 79 | # D1: Will be clobbered | ||
| 80 | # | ||
| 81 | # On some cores it is necessary to disable the dcache whilst we do this. | ||
| 82 | # | ||
| 83 | ############################################################################### | ||
| 84 | .macro invalidate_dcache,disable_irq | ||
| 85 | |||
| 86 | #if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3) | ||
| 87 | .if \disable_irq | ||
| 88 | # don't want an interrupt routine seeing a disabled cache | ||
| 89 | mov epsw,d1 | ||
| 90 | and ~EPSW_IE,epsw | ||
| 91 | or EPSW_NMID,epsw | ||
| 92 | nop | ||
| 93 | nop | ||
| 94 | .endif | ||
| 95 | |||
| 96 | # disable the dcache | ||
| 97 | and ~CHCTR_DCEN,d0 | ||
| 98 | movhu d0,(a0) | ||
| 99 | |||
| 100 | # and wait for it to calm down | ||
| 101 | setlb | ||
| 102 | movhu (a0),d0 | ||
| 103 | btst CHCTR_DCBUSY,d0 | ||
| 104 | lne | ||
| 105 | |||
| 106 | # invalidate | ||
| 107 | or CHCTR_DCINV,d0 | ||
| 108 | movhu d0,(a0) | ||
| 109 | |||
| 110 | # wait for the cache to finish | ||
| 111 | setlb | ||
| 112 | movhu (a0),d0 | ||
| 113 | btst CHCTR_DCBUSY,d0 | ||
| 114 | lne | ||
| 115 | |||
| 116 | # and reenable it | ||
| 117 | or CHCTR_DCEN,d0 | ||
| 118 | movhu d0,(a0) | ||
| 119 | movhu (a0),d0 | ||
| 120 | |||
| 121 | .if \disable_irq | ||
| 122 | LOCAL_IRQ_RESTORE(d1) | ||
| 123 | .endif | ||
| 124 | |||
| 125 | #else /* CONFIG_AM33_2 || CONFIG_AM33_3 */ | ||
| 126 | |||
| 127 | # invalidate | ||
| 128 | or CHCTR_DCINV,d0 | ||
| 129 | movhu d0,(a0) | ||
| 130 | movhu (a0),d0 | ||
| 131 | |||
| 132 | #endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */ | ||
| 133 | .endm | ||
diff --git a/arch/mn10300/mm/fault.c b/arch/mn10300/mm/fault.c index 59c3da49d9d9..0945409a8022 100644 --- a/arch/mn10300/mm/fault.c +++ b/arch/mn10300/mm/fault.c | |||
| @@ -28,8 +28,9 @@ | |||
| 28 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
| 29 | #include <asm/pgalloc.h> | 29 | #include <asm/pgalloc.h> |
| 30 | #include <asm/hardirq.h> | 30 | #include <asm/hardirq.h> |
| 31 | #include <asm/gdb-stub.h> | ||
| 32 | #include <asm/cpu-regs.h> | 31 | #include <asm/cpu-regs.h> |
| 32 | #include <asm/debugger.h> | ||
| 33 | #include <asm/gdb-stub.h> | ||
| 33 | 34 | ||
| 34 | /* | 35 | /* |
| 35 | * Unlock any spinlocks which will prevent us from getting the | 36 | * Unlock any spinlocks which will prevent us from getting the |
| @@ -306,10 +307,8 @@ no_context: | |||
| 306 | printk(" printing pc:\n"); | 307 | printk(" printing pc:\n"); |
| 307 | printk(KERN_ALERT "%08lx\n", regs->pc); | 308 | printk(KERN_ALERT "%08lx\n", regs->pc); |
| 308 | 309 | ||
| 309 | #ifdef CONFIG_GDBSTUB | 310 | debugger_intercept(fault_code & 0x00010000 ? EXCEP_IAERROR : EXCEP_DAERROR, |
| 310 | gdbstub_intercept( | 311 | SIGSEGV, SEGV_ACCERR, regs); |
| 311 | regs, fault_code & 0x00010000 ? EXCEP_IAERROR : EXCEP_DAERROR); | ||
| 312 | #endif | ||
| 313 | 312 | ||
| 314 | page = PTBR; | 313 | page = PTBR; |
| 315 | page = ((unsigned long *) __va(page))[address >> 22]; | 314 | page = ((unsigned long *) __va(page))[address >> 22]; |
diff --git a/arch/mn10300/proc-mn103e010/include/proc/cache.h b/arch/mn10300/proc-mn103e010/include/proc/cache.h index c1528004163c..967d144f307e 100644 --- a/arch/mn10300/proc-mn103e010/include/proc/cache.h +++ b/arch/mn10300/proc-mn103e010/include/proc/cache.h | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #define L1_CACHE_TAG_DIRTY 0x00000008 /* data cache tag dirty bit */ | 23 | #define L1_CACHE_TAG_DIRTY 0x00000008 /* data cache tag dirty bit */ |
| 24 | #define L1_CACHE_TAG_ENTRY 0x00000ff0 /* cache tag entry address mask */ | 24 | #define L1_CACHE_TAG_ENTRY 0x00000ff0 /* cache tag entry address mask */ |
| 25 | #define L1_CACHE_TAG_ADDRESS 0xfffff000 /* cache tag line address mask */ | 25 | #define L1_CACHE_TAG_ADDRESS 0xfffff000 /* cache tag line address mask */ |
| 26 | #define L1_CACHE_TAG_MASK +(L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY) | ||
| 26 | 27 | ||
| 27 | /* | 28 | /* |
| 28 | * specification of the interval between interrupt checking intervals whilst | 29 | * specification of the interval between interrupt checking intervals whilst |
diff --git a/arch/mn10300/proc-mn2ws0050/include/proc/cache.h b/arch/mn10300/proc-mn2ws0050/include/proc/cache.h index cafd7b5b55b4..bcb5df2d892f 100644 --- a/arch/mn10300/proc-mn2ws0050/include/proc/cache.h +++ b/arch/mn10300/proc-mn2ws0050/include/proc/cache.h | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #define L1_CACHE_TAG_DIRTY 0x00000008 /* data cache tag dirty bit */ | 29 | #define L1_CACHE_TAG_DIRTY 0x00000008 /* data cache tag dirty bit */ |
| 30 | #define L1_CACHE_TAG_ENTRY 0x00000fe0 /* cache tag entry address mask */ | 30 | #define L1_CACHE_TAG_ENTRY 0x00000fe0 /* cache tag entry address mask */ |
| 31 | #define L1_CACHE_TAG_ADDRESS 0xfffff000 /* cache tag line address mask */ | 31 | #define L1_CACHE_TAG_ADDRESS 0xfffff000 /* cache tag line address mask */ |
| 32 | #define L1_CACHE_TAG_MASK +(L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY) | ||
| 32 | 33 | ||
| 33 | /* | 34 | /* |
| 34 | * specification of the interval between interrupt checking intervals whilst | 35 | * specification of the interval between interrupt checking intervals whilst |
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h index 092e4250a458..10ca03d0a250 100644 --- a/include/linux/kgdb.h +++ b/include/linux/kgdb.h | |||
| @@ -297,6 +297,7 @@ extern int | |||
| 297 | kgdb_handle_exception(int ex_vector, int signo, int err_code, | 297 | kgdb_handle_exception(int ex_vector, int signo, int err_code, |
| 298 | struct pt_regs *regs); | 298 | struct pt_regs *regs); |
| 299 | extern int kgdb_nmicallback(int cpu, void *regs); | 299 | extern int kgdb_nmicallback(int cpu, void *regs); |
| 300 | extern void gdbstub_exit(int status); | ||
| 300 | 301 | ||
| 301 | extern int kgdb_single_step; | 302 | extern int kgdb_single_step; |
| 302 | extern atomic_t kgdb_active; | 303 | extern atomic_t kgdb_active; |
diff --git a/kernel/debug/gdbstub.c b/kernel/debug/gdbstub.c index 481a7bd2dfe7..a11db956dd62 100644 --- a/kernel/debug/gdbstub.c +++ b/kernel/debug/gdbstub.c | |||
| @@ -1093,3 +1093,33 @@ int gdbstub_state(struct kgdb_state *ks, char *cmd) | |||
| 1093 | put_packet(remcom_out_buffer); | 1093 | put_packet(remcom_out_buffer); |
| 1094 | return 0; | 1094 | return 0; |
| 1095 | } | 1095 | } |
| 1096 | |||
| 1097 | /** | ||
| 1098 | * gdbstub_exit - Send an exit message to GDB | ||
| 1099 | * @status: The exit code to report. | ||
| 1100 | */ | ||
| 1101 | void gdbstub_exit(int status) | ||
| 1102 | { | ||
| 1103 | unsigned char checksum, ch, buffer[3]; | ||
| 1104 | int loop; | ||
| 1105 | |||
| 1106 | buffer[0] = 'W'; | ||
| 1107 | buffer[1] = hex_asc_hi(status); | ||
| 1108 | buffer[2] = hex_asc_lo(status); | ||
| 1109 | |||
| 1110 | dbg_io_ops->write_char('$'); | ||
| 1111 | checksum = 0; | ||
| 1112 | |||
| 1113 | for (loop = 0; loop < 3; loop++) { | ||
| 1114 | ch = buffer[loop]; | ||
| 1115 | checksum += ch; | ||
| 1116 | dbg_io_ops->write_char(ch); | ||
| 1117 | } | ||
| 1118 | |||
| 1119 | dbg_io_ops->write_char('#'); | ||
| 1120 | dbg_io_ops->write_char(hex_asc_hi(checksum)); | ||
| 1121 | dbg_io_ops->write_char(hex_asc_lo(checksum)); | ||
| 1122 | |||
| 1123 | /* make sure the output is flushed, lest the bootloader clobber it */ | ||
| 1124 | dbg_io_ops->flush(); | ||
| 1125 | } | ||
