diff options
Diffstat (limited to 'arch/ia64/kernel/traps.c')
| -rw-r--r-- | arch/ia64/kernel/traps.c | 29 |
1 files changed, 28 insertions, 1 deletions
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index e82ad78081b3..1861173bd4f6 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c | |||
| @@ -111,6 +111,24 @@ ia64_bad_break (unsigned long break_num, struct pt_regs *regs) | |||
| 111 | siginfo_t siginfo; | 111 | siginfo_t siginfo; |
| 112 | int sig, code; | 112 | int sig, code; |
| 113 | 113 | ||
| 114 | /* break.b always sets cr.iim to 0, which causes problems for | ||
| 115 | * debuggers. Get the real break number from the original instruction, | ||
| 116 | * but only for kernel code. User space break.b is left alone, to | ||
| 117 | * preserve the existing behaviour. All break codings have the same | ||
| 118 | * format, so there is no need to check the slot type. | ||
| 119 | */ | ||
| 120 | if (break_num == 0 && !user_mode(regs)) { | ||
| 121 | struct ia64_psr *ipsr = ia64_psr(regs); | ||
| 122 | unsigned long *bundle = (unsigned long *)regs->cr_iip; | ||
| 123 | unsigned long slot; | ||
| 124 | switch (ipsr->ri) { | ||
| 125 | case 0: slot = (bundle[0] >> 5); break; | ||
| 126 | case 1: slot = (bundle[0] >> 46) | (bundle[1] << 18); break; | ||
| 127 | default: slot = (bundle[1] >> 23); break; | ||
| 128 | } | ||
| 129 | break_num = ((slot >> 36 & 1) << 20) | (slot >> 6 & 0xfffff); | ||
| 130 | } | ||
| 131 | |||
| 114 | /* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */ | 132 | /* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */ |
| 115 | siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); | 133 | siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); |
| 116 | siginfo.si_imm = break_num; | 134 | siginfo.si_imm = break_num; |
| @@ -202,13 +220,21 @@ disabled_fph_fault (struct pt_regs *regs) | |||
| 202 | 220 | ||
| 203 | /* first, grant user-level access to fph partition: */ | 221 | /* first, grant user-level access to fph partition: */ |
| 204 | psr->dfh = 0; | 222 | psr->dfh = 0; |
| 223 | |||
| 224 | /* | ||
| 225 | * Make sure that no other task gets in on this processor | ||
| 226 | * while we're claiming the FPU | ||
| 227 | */ | ||
| 228 | preempt_disable(); | ||
| 205 | #ifndef CONFIG_SMP | 229 | #ifndef CONFIG_SMP |
| 206 | { | 230 | { |
| 207 | struct task_struct *fpu_owner | 231 | struct task_struct *fpu_owner |
| 208 | = (struct task_struct *)ia64_get_kr(IA64_KR_FPU_OWNER); | 232 | = (struct task_struct *)ia64_get_kr(IA64_KR_FPU_OWNER); |
| 209 | 233 | ||
| 210 | if (ia64_is_local_fpu_owner(current)) | 234 | if (ia64_is_local_fpu_owner(current)) { |
| 235 | preempt_enable_no_resched(); | ||
| 211 | return; | 236 | return; |
| 237 | } | ||
| 212 | 238 | ||
| 213 | if (fpu_owner) | 239 | if (fpu_owner) |
| 214 | ia64_flush_fph(fpu_owner); | 240 | ia64_flush_fph(fpu_owner); |
| @@ -226,6 +252,7 @@ disabled_fph_fault (struct pt_regs *regs) | |||
| 226 | */ | 252 | */ |
| 227 | psr->mfh = 1; | 253 | psr->mfh = 1; |
| 228 | } | 254 | } |
| 255 | preempt_enable_no_resched(); | ||
| 229 | } | 256 | } |
| 230 | 257 | ||
| 231 | static inline int | 258 | static inline int |
