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 |