diff options
author | Paul Mackerras <paulus@samba.org> | 2006-03-07 21:24:22 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-03-07 21:24:22 -0500 |
commit | 1bd79336a426c5e4f3bab142407059ceb12cadf9 (patch) | |
tree | dd8767b0ab3ce310c7df049822100e3838b37a97 | |
parent | ab1b55e21f6977e420341727e9f4a50691057b5e (diff) |
powerpc: Fix various syscall/signal/swapcontext bugs
A careful reading of the recent changes to the system call entry/exit
paths revealed several problems, plus some things that could be
simplified and improved:
* 32-bit wasn't testing the _TIF_NOERROR bit in the syscall fast exit
path, so it was only doing anything with it once it saw some other
bit being set. In other words, the noerror behaviour would apply to
the next system call where we had to reschedule or deliver a signal,
which is not necessarily the current system call.
* 32-bit wasn't doing the call to ptrace_notify in the syscall exit
path when the _TIF_SINGLESTEP bit was set.
* _TIF_RESTOREALL was in both _TIF_USER_WORK_MASK and
_TIF_PERSYSCALL_MASK, which is odd since _TIF_RESTOREALL is only set
by system calls. I took it out of _TIF_USER_WORK_MASK.
* On 64-bit, _TIF_RESTOREALL wasn't causing the non-volatile registers
to be restored (unless perhaps a signal was delivered or the syscall
was traced or single-stepped). Thus the non-volatile registers
weren't restored on exit from a signal handler. We probably got
away with it mostly because signal handlers written in C wouldn't
alter the non-volatile registers.
* On 32-bit I simplified the code and made it more like 64-bit by
making the syscall exit path jump to ret_from_except to handle
preemption and signal delivery.
* 32-bit was calling do_signal unnecessarily when _TIF_RESTOREALL was
set - but I think because of that 32-bit was actually restoring the
non-volatile registers on exit from a signal handler.
* I changed the order of enabling interrupts and saving the
non-volatile registers before calling do_syscall_trace_leave; now we
enable interrupts first.
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/kernel/asm-offsets.c | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/entry_32.S | 95 | ||||
-rw-r--r-- | arch/powerpc/kernel/entry_64.S | 94 | ||||
-rw-r--r-- | arch/powerpc/kernel/ptrace.c | 5 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal_32.c | 19 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal_64.c | 9 | ||||
-rw-r--r-- | arch/powerpc/kernel/systbl.S | 2 | ||||
-rw-r--r-- | arch/ppc/kernel/asm-offsets.c | 1 | ||||
-rw-r--r-- | arch/ppc/kernel/entry.S | 95 | ||||
-rw-r--r-- | include/asm-powerpc/thread_info.h | 8 |
10 files changed, 78 insertions, 251 deletions
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 840aad43a98b..c9a660e4c2db 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -92,7 +92,6 @@ int main(void) | |||
92 | 92 | ||
93 | DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); | 93 | DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); |
94 | DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); | 94 | DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); |
95 | DEFINE(TI_SIGFRAME, offsetof(struct thread_info, nvgprs_frame)); | ||
96 | DEFINE(TI_TASK, offsetof(struct thread_info, task)); | 95 | DEFINE(TI_TASK, offsetof(struct thread_info, task)); |
97 | #ifdef CONFIG_PPC32 | 96 | #ifdef CONFIG_PPC32 |
98 | DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); | 97 | DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); |
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index f20a67261ec7..4827ca1ec89b 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S | |||
@@ -227,7 +227,7 @@ ret_from_syscall: | |||
227 | MTMSRD(r10) | 227 | MTMSRD(r10) |
228 | lwz r9,TI_FLAGS(r12) | 228 | lwz r9,TI_FLAGS(r12) |
229 | li r8,-_LAST_ERRNO | 229 | li r8,-_LAST_ERRNO |
230 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_RESTORE_SIGMASK) | 230 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_USER_WORK_MASK|_TIF_PERSYSCALL_MASK) |
231 | bne- syscall_exit_work | 231 | bne- syscall_exit_work |
232 | cmplw 0,r3,r8 | 232 | cmplw 0,r3,r8 |
233 | blt+ syscall_exit_cont | 233 | blt+ syscall_exit_cont |
@@ -287,8 +287,10 @@ syscall_dotrace: | |||
287 | 287 | ||
288 | syscall_exit_work: | 288 | syscall_exit_work: |
289 | andi. r0,r9,_TIF_RESTOREALL | 289 | andi. r0,r9,_TIF_RESTOREALL |
290 | bne- 2f | 290 | beq+ 0f |
291 | cmplw 0,r3,r8 | 291 | REST_NVGPRS(r1) |
292 | b 2f | ||
293 | 0: cmplw 0,r3,r8 | ||
292 | blt+ 1f | 294 | blt+ 1f |
293 | andi. r0,r9,_TIF_NOERROR | 295 | andi. r0,r9,_TIF_NOERROR |
294 | bne- 1f | 296 | bne- 1f |
@@ -302,9 +304,7 @@ syscall_exit_work: | |||
302 | 2: andi. r0,r9,(_TIF_PERSYSCALL_MASK) | 304 | 2: andi. r0,r9,(_TIF_PERSYSCALL_MASK) |
303 | beq 4f | 305 | beq 4f |
304 | 306 | ||
305 | /* Clear per-syscall TIF flags if any are set, but _leave_ | 307 | /* Clear per-syscall TIF flags if any are set. */ |
306 | _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that | ||
307 | yet. */ | ||
308 | 308 | ||
309 | li r11,_TIF_PERSYSCALL_MASK | 309 | li r11,_TIF_PERSYSCALL_MASK |
310 | addi r12,r12,TI_FLAGS | 310 | addi r12,r12,TI_FLAGS |
@@ -318,8 +318,13 @@ syscall_exit_work: | |||
318 | subi r12,r12,TI_FLAGS | 318 | subi r12,r12,TI_FLAGS |
319 | 319 | ||
320 | 4: /* Anything which requires enabling interrupts? */ | 320 | 4: /* Anything which requires enabling interrupts? */ |
321 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS) | 321 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) |
322 | beq 7f | 322 | beq ret_from_except |
323 | |||
324 | /* Re-enable interrupts */ | ||
325 | ori r10,r10,MSR_EE | ||
326 | SYNC | ||
327 | MTMSRD(r10) | ||
323 | 328 | ||
324 | /* Save NVGPRS if they're not saved already */ | 329 | /* Save NVGPRS if they're not saved already */ |
325 | lwz r4,_TRAP(r1) | 330 | lwz r4,_TRAP(r1) |
@@ -328,71 +333,11 @@ syscall_exit_work: | |||
328 | SAVE_NVGPRS(r1) | 333 | SAVE_NVGPRS(r1) |
329 | li r4,0xc00 | 334 | li r4,0xc00 |
330 | stw r4,_TRAP(r1) | 335 | stw r4,_TRAP(r1) |
331 | 336 | 5: | |
332 | /* Re-enable interrupts */ | ||
333 | 5: ori r10,r10,MSR_EE | ||
334 | SYNC | ||
335 | MTMSRD(r10) | ||
336 | |||
337 | andi. r0,r9,_TIF_SAVE_NVGPRS | ||
338 | bne save_user_nvgprs | ||
339 | |||
340 | save_user_nvgprs_cont: | ||
341 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) | ||
342 | beq 7f | ||
343 | |||
344 | addi r3,r1,STACK_FRAME_OVERHEAD | 337 | addi r3,r1,STACK_FRAME_OVERHEAD |
345 | bl do_syscall_trace_leave | 338 | bl do_syscall_trace_leave |
346 | REST_NVGPRS(r1) | 339 | b ret_from_except_full |
347 | |||
348 | 6: lwz r3,GPR3(r1) | ||
349 | LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ | ||
350 | SYNC | ||
351 | MTMSRD(r10) /* disable interrupts again */ | ||
352 | rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ | ||
353 | lwz r9,TI_FLAGS(r12) | ||
354 | 7: | ||
355 | andi. r0,r9,_TIF_NEED_RESCHED | ||
356 | bne 8f | ||
357 | lwz r5,_MSR(r1) | ||
358 | andi. r5,r5,MSR_PR | ||
359 | beq ret_from_except | ||
360 | andi. r0,r9,_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK | ||
361 | beq ret_from_except | ||
362 | b do_user_signal | ||
363 | 8: | ||
364 | ori r10,r10,MSR_EE | ||
365 | SYNC | ||
366 | MTMSRD(r10) /* re-enable interrupts */ | ||
367 | bl schedule | ||
368 | b 6b | ||
369 | |||
370 | save_user_nvgprs: | ||
371 | lwz r8,TI_SIGFRAME(r12) | ||
372 | |||
373 | .macro savewords start, end | ||
374 | 1: stw \start,4*(\start)(r8) | ||
375 | .section __ex_table,"a" | ||
376 | .align 2 | ||
377 | .long 1b,save_user_nvgprs_fault | ||
378 | .previous | ||
379 | .if \end - \start | ||
380 | savewords "(\start+1)",\end | ||
381 | .endif | ||
382 | .endm | ||
383 | savewords 14,31 | ||
384 | b save_user_nvgprs_cont | ||
385 | |||
386 | |||
387 | save_user_nvgprs_fault: | ||
388 | li r3,11 /* SIGSEGV */ | ||
389 | lwz r4,TI_TASK(r12) | ||
390 | bl force_sigsegv | ||
391 | 340 | ||
392 | rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ | ||
393 | lwz r9,TI_FLAGS(r12) | ||
394 | b save_user_nvgprs_cont | ||
395 | |||
396 | #ifdef SHOW_SYSCALLS | 341 | #ifdef SHOW_SYSCALLS |
397 | do_show_syscall: | 342 | do_show_syscall: |
398 | #ifdef SHOW_SYSCALLS_TASK | 343 | #ifdef SHOW_SYSCALLS_TASK |
@@ -490,6 +435,14 @@ ppc_clone: | |||
490 | stw r0,_TRAP(r1) /* register set saved */ | 435 | stw r0,_TRAP(r1) /* register set saved */ |
491 | b sys_clone | 436 | b sys_clone |
492 | 437 | ||
438 | .globl ppc_swapcontext | ||
439 | ppc_swapcontext: | ||
440 | SAVE_NVGPRS(r1) | ||
441 | lwz r0,_TRAP(r1) | ||
442 | rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ | ||
443 | stw r0,_TRAP(r1) /* register set saved */ | ||
444 | b sys_swapcontext | ||
445 | |||
493 | /* | 446 | /* |
494 | * Top-level page fault handling. | 447 | * Top-level page fault handling. |
495 | * This is in assembler because if do_page_fault tells us that | 448 | * This is in assembler because if do_page_fault tells us that |
@@ -683,7 +636,7 @@ user_exc_return: /* r10 contains MSR_KERNEL here */ | |||
683 | /* Check current_thread_info()->flags */ | 636 | /* Check current_thread_info()->flags */ |
684 | rlwinm r9,r1,0,0,(31-THREAD_SHIFT) | 637 | rlwinm r9,r1,0,0,(31-THREAD_SHIFT) |
685 | lwz r9,TI_FLAGS(r9) | 638 | lwz r9,TI_FLAGS(r9) |
686 | andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_RESTORE_SIGMASK) | 639 | andi. r0,r9,(_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_NEED_RESCHED) |
687 | bne do_work | 640 | bne do_work |
688 | 641 | ||
689 | restore_user: | 642 | restore_user: |
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 388f861b8ed1..24be0cf86d7f 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -160,7 +160,7 @@ syscall_exit: | |||
160 | mtmsrd r10,1 | 160 | mtmsrd r10,1 |
161 | ld r9,TI_FLAGS(r12) | 161 | ld r9,TI_FLAGS(r12) |
162 | li r11,-_LAST_ERRNO | 162 | li r11,-_LAST_ERRNO |
163 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_SAVE_NVGPRS|_TIF_NOERROR|_TIF_RESTORE_SIGMASK) | 163 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_USER_WORK_MASK|_TIF_PERSYSCALL_MASK) |
164 | bne- syscall_exit_work | 164 | bne- syscall_exit_work |
165 | cmpld r3,r11 | 165 | cmpld r3,r11 |
166 | ld r5,_CCR(r1) | 166 | ld r5,_CCR(r1) |
@@ -216,8 +216,10 @@ syscall_exit_work: | |||
216 | If TIF_NOERROR is set, just save r3 as it is. */ | 216 | If TIF_NOERROR is set, just save r3 as it is. */ |
217 | 217 | ||
218 | andi. r0,r9,_TIF_RESTOREALL | 218 | andi. r0,r9,_TIF_RESTOREALL |
219 | bne- 2f | 219 | beq+ 0f |
220 | cmpld r3,r11 /* r10 is -LAST_ERRNO */ | 220 | REST_NVGPRS(r1) |
221 | b 2f | ||
222 | 0: cmpld r3,r11 /* r10 is -LAST_ERRNO */ | ||
221 | blt+ 1f | 223 | blt+ 1f |
222 | andi. r0,r9,_TIF_NOERROR | 224 | andi. r0,r9,_TIF_NOERROR |
223 | bne- 1f | 225 | bne- 1f |
@@ -229,9 +231,7 @@ syscall_exit_work: | |||
229 | 2: andi. r0,r9,(_TIF_PERSYSCALL_MASK) | 231 | 2: andi. r0,r9,(_TIF_PERSYSCALL_MASK) |
230 | beq 4f | 232 | beq 4f |
231 | 233 | ||
232 | /* Clear per-syscall TIF flags if any are set, but _leave_ | 234 | /* Clear per-syscall TIF flags if any are set. */ |
233 | _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that | ||
234 | yet. */ | ||
235 | 235 | ||
236 | li r11,_TIF_PERSYSCALL_MASK | 236 | li r11,_TIF_PERSYSCALL_MASK |
237 | addi r12,r12,TI_FLAGS | 237 | addi r12,r12,TI_FLAGS |
@@ -240,10 +240,9 @@ syscall_exit_work: | |||
240 | stdcx. r10,0,r12 | 240 | stdcx. r10,0,r12 |
241 | bne- 3b | 241 | bne- 3b |
242 | subi r12,r12,TI_FLAGS | 242 | subi r12,r12,TI_FLAGS |
243 | 243 | ||
244 | 4: bl .save_nvgprs | 244 | 4: /* Anything else left to do? */ |
245 | /* Anything else left to do? */ | 245 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) |
246 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS) | ||
247 | beq .ret_from_except_lite | 246 | beq .ret_from_except_lite |
248 | 247 | ||
249 | /* Re-enable interrupts */ | 248 | /* Re-enable interrupts */ |
@@ -251,26 +250,10 @@ syscall_exit_work: | |||
251 | ori r10,r10,MSR_EE | 250 | ori r10,r10,MSR_EE |
252 | mtmsrd r10,1 | 251 | mtmsrd r10,1 |
253 | 252 | ||
254 | andi. r0,r9,_TIF_SAVE_NVGPRS | 253 | bl .save_nvgprs |
255 | bne save_user_nvgprs | ||
256 | |||
257 | /* If tracing, re-enable interrupts and do it */ | ||
258 | save_user_nvgprs_cont: | ||
259 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) | ||
260 | beq 5f | ||
261 | |||
262 | addi r3,r1,STACK_FRAME_OVERHEAD | 254 | addi r3,r1,STACK_FRAME_OVERHEAD |
263 | bl .do_syscall_trace_leave | 255 | bl .do_syscall_trace_leave |
264 | REST_NVGPRS(r1) | 256 | b .ret_from_except |
265 | clrrdi r12,r1,THREAD_SHIFT | ||
266 | |||
267 | /* Disable interrupts again and handle other work if any */ | ||
268 | 5: mfmsr r10 | ||
269 | rldicl r10,r10,48,1 | ||
270 | rotldi r10,r10,16 | ||
271 | mtmsrd r10,1 | ||
272 | |||
273 | b .ret_from_except_lite | ||
274 | 257 | ||
275 | /* Save non-volatile GPRs, if not already saved. */ | 258 | /* Save non-volatile GPRs, if not already saved. */ |
276 | _GLOBAL(save_nvgprs) | 259 | _GLOBAL(save_nvgprs) |
@@ -282,51 +265,6 @@ _GLOBAL(save_nvgprs) | |||
282 | std r0,_TRAP(r1) | 265 | std r0,_TRAP(r1) |
283 | blr | 266 | blr |
284 | 267 | ||
285 | |||
286 | save_user_nvgprs: | ||
287 | ld r10,TI_SIGFRAME(r12) | ||
288 | andi. r0,r9,_TIF_32BIT | ||
289 | beq- save_user_nvgprs_64 | ||
290 | |||
291 | /* 32-bit save to userspace */ | ||
292 | |||
293 | .macro savewords start, end | ||
294 | 1: stw \start,4*(\start)(r10) | ||
295 | .section __ex_table,"a" | ||
296 | .align 3 | ||
297 | .llong 1b,save_user_nvgprs_fault | ||
298 | .previous | ||
299 | .if \end - \start | ||
300 | savewords "(\start+1)",\end | ||
301 | .endif | ||
302 | .endm | ||
303 | savewords 14,31 | ||
304 | b save_user_nvgprs_cont | ||
305 | |||
306 | save_user_nvgprs_64: | ||
307 | /* 64-bit save to userspace */ | ||
308 | |||
309 | .macro savelongs start, end | ||
310 | 1: std \start,8*(\start)(r10) | ||
311 | .section __ex_table,"a" | ||
312 | .align 3 | ||
313 | .llong 1b,save_user_nvgprs_fault | ||
314 | .previous | ||
315 | .if \end - \start | ||
316 | savelongs "(\start+1)",\end | ||
317 | .endif | ||
318 | .endm | ||
319 | savelongs 14,31 | ||
320 | b save_user_nvgprs_cont | ||
321 | |||
322 | save_user_nvgprs_fault: | ||
323 | li r3,11 /* SIGSEGV */ | ||
324 | ld r4,TI_TASK(r12) | ||
325 | bl .force_sigsegv | ||
326 | |||
327 | clrrdi r12,r1,THREAD_SHIFT | ||
328 | ld r9,TI_FLAGS(r12) | ||
329 | b save_user_nvgprs_cont | ||
330 | 268 | ||
331 | /* | 269 | /* |
332 | * The sigsuspend and rt_sigsuspend system calls can call do_signal | 270 | * The sigsuspend and rt_sigsuspend system calls can call do_signal |
@@ -352,6 +290,16 @@ _GLOBAL(ppc_clone) | |||
352 | bl .sys_clone | 290 | bl .sys_clone |
353 | b syscall_exit | 291 | b syscall_exit |
354 | 292 | ||
293 | _GLOBAL(ppc32_swapcontext) | ||
294 | bl .save_nvgprs | ||
295 | bl .compat_sys_swapcontext | ||
296 | b syscall_exit | ||
297 | |||
298 | _GLOBAL(ppc64_swapcontext) | ||
299 | bl .save_nvgprs | ||
300 | bl .sys_swapcontext | ||
301 | b syscall_exit | ||
302 | |||
355 | _GLOBAL(ret_from_fork) | 303 | _GLOBAL(ret_from_fork) |
356 | bl .schedule_tail | 304 | bl .schedule_tail |
357 | REST_NVGPRS(r1) | 305 | REST_NVGPRS(r1) |
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 400793c71304..bcb83574335b 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -561,10 +561,7 @@ void do_syscall_trace_leave(struct pt_regs *regs) | |||
561 | regs->result); | 561 | regs->result); |
562 | 562 | ||
563 | if ((test_thread_flag(TIF_SYSCALL_TRACE) | 563 | if ((test_thread_flag(TIF_SYSCALL_TRACE) |
564 | #ifdef CONFIG_PPC64 | 564 | || test_thread_flag(TIF_SINGLESTEP)) |
565 | || test_thread_flag(TIF_SINGLESTEP) | ||
566 | #endif | ||
567 | ) | ||
568 | && (current->ptrace & PT_PTRACED)) | 565 | && (current->ptrace & PT_PTRACED)) |
569 | do_syscall_trace(); | 566 | do_syscall_trace(); |
570 | } | 567 | } |
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index bd837b5dbf06..d7a4e814974d 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c | |||
@@ -151,10 +151,7 @@ static inline int save_general_regs(struct pt_regs *regs, | |||
151 | elf_greg_t64 *gregs = (elf_greg_t64 *)regs; | 151 | elf_greg_t64 *gregs = (elf_greg_t64 *)regs; |
152 | int i; | 152 | int i; |
153 | 153 | ||
154 | if (!FULL_REGS(regs)) { | 154 | WARN_ON(!FULL_REGS(regs)); |
155 | set_thread_flag(TIF_SAVE_NVGPRS); | ||
156 | current_thread_info()->nvgprs_frame = frame->mc_gregs; | ||
157 | } | ||
158 | 155 | ||
159 | for (i = 0; i <= PT_RESULT; i ++) { | 156 | for (i = 0; i <= PT_RESULT; i ++) { |
160 | if (i == 14 && !FULL_REGS(regs)) | 157 | if (i == 14 && !FULL_REGS(regs)) |
@@ -215,15 +212,7 @@ static inline int get_old_sigaction(struct k_sigaction *new_ka, | |||
215 | static inline int save_general_regs(struct pt_regs *regs, | 212 | static inline int save_general_regs(struct pt_regs *regs, |
216 | struct mcontext __user *frame) | 213 | struct mcontext __user *frame) |
217 | { | 214 | { |
218 | if (!FULL_REGS(regs)) { | 215 | WARN_ON(!FULL_REGS(regs)); |
219 | /* Zero out the unsaved GPRs to avoid information | ||
220 | leak, and set TIF_SAVE_NVGPRS to ensure that the | ||
221 | registers do actually get saved later. */ | ||
222 | memset(®s->gpr[14], 0, 18 * sizeof(unsigned long)); | ||
223 | current_thread_info()->nvgprs_frame = &frame->mc_gregs; | ||
224 | set_thread_flag(TIF_SAVE_NVGPRS); | ||
225 | } | ||
226 | |||
227 | return __copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE); | 216 | return __copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE); |
228 | } | 217 | } |
229 | 218 | ||
@@ -826,8 +815,8 @@ static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs, int | |||
826 | } | 815 | } |
827 | 816 | ||
828 | long sys_swapcontext(struct ucontext __user *old_ctx, | 817 | long sys_swapcontext(struct ucontext __user *old_ctx, |
829 | struct ucontext __user *new_ctx, | 818 | struct ucontext __user *new_ctx, |
830 | int ctx_size, int r6, int r7, int r8, struct pt_regs *regs) | 819 | int ctx_size, int r6, int r7, int r8, struct pt_regs *regs) |
831 | { | 820 | { |
832 | unsigned char tmp; | 821 | unsigned char tmp; |
833 | 822 | ||
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 497a5d3df359..4324f8a8ba24 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c | |||
@@ -118,14 +118,7 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | |||
118 | err |= __put_user(0, &sc->v_regs); | 118 | err |= __put_user(0, &sc->v_regs); |
119 | #endif /* CONFIG_ALTIVEC */ | 119 | #endif /* CONFIG_ALTIVEC */ |
120 | err |= __put_user(&sc->gp_regs, &sc->regs); | 120 | err |= __put_user(&sc->gp_regs, &sc->regs); |
121 | if (!FULL_REGS(regs)) { | 121 | WARN_ON(!FULL_REGS(regs)); |
122 | /* Zero out the unsaved GPRs to avoid information | ||
123 | leak, and set TIF_SAVE_NVGPRS to ensure that the | ||
124 | registers do actually get saved later. */ | ||
125 | memset(®s->gpr[14], 0, 18 * sizeof(unsigned long)); | ||
126 | set_thread_flag(TIF_SAVE_NVGPRS); | ||
127 | current_thread_info()->nvgprs_frame = &sc->gp_regs; | ||
128 | } | ||
129 | err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE); | 122 | err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE); |
130 | err |= __copy_to_user(&sc->fp_regs, ¤t->thread.fpr, FP_REGS_SIZE); | 123 | err |= __copy_to_user(&sc->fp_regs, ¤t->thread.fpr, FP_REGS_SIZE); |
131 | err |= __put_user(signr, &sc->signal); | 124 | err |= __put_user(signr, &sc->signal); |
diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 8a9f994ed917..1ad55f0466fd 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S | |||
@@ -288,7 +288,7 @@ COMPAT_SYS(clock_settime) | |||
288 | COMPAT_SYS(clock_gettime) | 288 | COMPAT_SYS(clock_gettime) |
289 | COMPAT_SYS(clock_getres) | 289 | COMPAT_SYS(clock_getres) |
290 | COMPAT_SYS(clock_nanosleep) | 290 | COMPAT_SYS(clock_nanosleep) |
291 | COMPAT_SYS(swapcontext) | 291 | SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext) |
292 | COMPAT_SYS(tgkill) | 292 | COMPAT_SYS(tgkill) |
293 | COMPAT_SYS(utimes) | 293 | COMPAT_SYS(utimes) |
294 | COMPAT_SYS(statfs64) | 294 | COMPAT_SYS(statfs64) |
diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c index 7964bf660e92..77e4dc780f8c 100644 --- a/arch/ppc/kernel/asm-offsets.c +++ b/arch/ppc/kernel/asm-offsets.c | |||
@@ -131,7 +131,6 @@ main(void) | |||
131 | DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); | 131 | DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); |
132 | DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); | 132 | DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); |
133 | 133 | ||
134 | DEFINE(TI_SIGFRAME, offsetof(struct thread_info, nvgprs_frame)); | ||
135 | DEFINE(TI_TASK, offsetof(struct thread_info, task)); | 134 | DEFINE(TI_TASK, offsetof(struct thread_info, task)); |
136 | DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); | 135 | DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); |
137 | DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); | 136 | DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); |
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index a48b950722a1..3a2815978488 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S | |||
@@ -227,7 +227,7 @@ ret_from_syscall: | |||
227 | MTMSRD(r10) | 227 | MTMSRD(r10) |
228 | lwz r9,TI_FLAGS(r12) | 228 | lwz r9,TI_FLAGS(r12) |
229 | li r8,-_LAST_ERRNO | 229 | li r8,-_LAST_ERRNO |
230 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL) | 230 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_USER_WORK_MASK|_TIF_PERSYSCALL_MASK) |
231 | bne- syscall_exit_work | 231 | bne- syscall_exit_work |
232 | cmplw 0,r3,r8 | 232 | cmplw 0,r3,r8 |
233 | blt+ syscall_exit_cont | 233 | blt+ syscall_exit_cont |
@@ -287,8 +287,10 @@ syscall_dotrace: | |||
287 | 287 | ||
288 | syscall_exit_work: | 288 | syscall_exit_work: |
289 | andi. r0,r9,_TIF_RESTOREALL | 289 | andi. r0,r9,_TIF_RESTOREALL |
290 | bne- 2f | 290 | beq+ 0f |
291 | cmplw 0,r3,r8 | 291 | REST_NVGPRS(r1) |
292 | b 2f | ||
293 | 0: cmplw 0,r3,r8 | ||
292 | blt+ 1f | 294 | blt+ 1f |
293 | andi. r0,r9,_TIF_NOERROR | 295 | andi. r0,r9,_TIF_NOERROR |
294 | bne- 1f | 296 | bne- 1f |
@@ -302,9 +304,7 @@ syscall_exit_work: | |||
302 | 2: andi. r0,r9,(_TIF_PERSYSCALL_MASK) | 304 | 2: andi. r0,r9,(_TIF_PERSYSCALL_MASK) |
303 | beq 4f | 305 | beq 4f |
304 | 306 | ||
305 | /* Clear per-syscall TIF flags if any are set, but _leave_ | 307 | /* Clear per-syscall TIF flags if any are set. */ |
306 | _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that | ||
307 | yet. */ | ||
308 | 308 | ||
309 | li r11,_TIF_PERSYSCALL_MASK | 309 | li r11,_TIF_PERSYSCALL_MASK |
310 | addi r12,r12,TI_FLAGS | 310 | addi r12,r12,TI_FLAGS |
@@ -318,8 +318,13 @@ syscall_exit_work: | |||
318 | subi r12,r12,TI_FLAGS | 318 | subi r12,r12,TI_FLAGS |
319 | 319 | ||
320 | 4: /* Anything which requires enabling interrupts? */ | 320 | 4: /* Anything which requires enabling interrupts? */ |
321 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS) | 321 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) |
322 | beq 7f | 322 | beq ret_from_except |
323 | |||
324 | /* Re-enable interrupts */ | ||
325 | ori r10,r10,MSR_EE | ||
326 | SYNC | ||
327 | MTMSRD(r10) | ||
323 | 328 | ||
324 | /* Save NVGPRS if they're not saved already */ | 329 | /* Save NVGPRS if they're not saved already */ |
325 | lwz r4,TRAP(r1) | 330 | lwz r4,TRAP(r1) |
@@ -328,71 +333,11 @@ syscall_exit_work: | |||
328 | SAVE_NVGPRS(r1) | 333 | SAVE_NVGPRS(r1) |
329 | li r4,0xc00 | 334 | li r4,0xc00 |
330 | stw r4,TRAP(r1) | 335 | stw r4,TRAP(r1) |
331 | 336 | 5: | |
332 | /* Re-enable interrupts */ | ||
333 | 5: ori r10,r10,MSR_EE | ||
334 | SYNC | ||
335 | MTMSRD(r10) | ||
336 | |||
337 | andi. r0,r9,_TIF_SAVE_NVGPRS | ||
338 | bne save_user_nvgprs | ||
339 | |||
340 | save_user_nvgprs_cont: | ||
341 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) | ||
342 | beq 7f | ||
343 | |||
344 | addi r3,r1,STACK_FRAME_OVERHEAD | 337 | addi r3,r1,STACK_FRAME_OVERHEAD |
345 | bl do_syscall_trace_leave | 338 | bl do_syscall_trace_leave |
346 | REST_NVGPRS(r1) | 339 | b ret_from_except_full |
347 | |||
348 | 6: lwz r3,GPR3(r1) | ||
349 | LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ | ||
350 | SYNC | ||
351 | MTMSRD(r10) /* disable interrupts again */ | ||
352 | rlwinm r12,r1,0,0,18 /* current_thread_info() */ | ||
353 | lwz r9,TI_FLAGS(r12) | ||
354 | 7: | ||
355 | andi. r0,r9,_TIF_NEED_RESCHED | ||
356 | bne 8f | ||
357 | lwz r5,_MSR(r1) | ||
358 | andi. r5,r5,MSR_PR | ||
359 | beq ret_from_except | ||
360 | andi. r0,r9,_TIF_SIGPENDING | ||
361 | beq ret_from_except | ||
362 | b do_user_signal | ||
363 | 8: | ||
364 | ori r10,r10,MSR_EE | ||
365 | SYNC | ||
366 | MTMSRD(r10) /* re-enable interrupts */ | ||
367 | bl schedule | ||
368 | b 6b | ||
369 | |||
370 | save_user_nvgprs: | ||
371 | lwz r8,TI_SIGFRAME(r12) | ||
372 | |||
373 | .macro savewords start, end | ||
374 | 1: stw \start,4*(\start)(r8) | ||
375 | .section __ex_table,"a" | ||
376 | .align 2 | ||
377 | .long 1b,save_user_nvgprs_fault | ||
378 | .previous | ||
379 | .if \end - \start | ||
380 | savewords "(\start+1)",\end | ||
381 | .endif | ||
382 | .endm | ||
383 | savewords 14,31 | ||
384 | b save_user_nvgprs_cont | ||
385 | |||
386 | |||
387 | save_user_nvgprs_fault: | ||
388 | li r3,11 /* SIGSEGV */ | ||
389 | lwz r4,TI_TASK(r12) | ||
390 | bl force_sigsegv | ||
391 | 340 | ||
392 | rlwinm r12,r1,0,0,18 /* current_thread_info() */ | ||
393 | lwz r9,TI_FLAGS(r12) | ||
394 | b save_user_nvgprs_cont | ||
395 | |||
396 | #ifdef SHOW_SYSCALLS | 341 | #ifdef SHOW_SYSCALLS |
397 | do_show_syscall: | 342 | do_show_syscall: |
398 | #ifdef SHOW_SYSCALLS_TASK | 343 | #ifdef SHOW_SYSCALLS_TASK |
@@ -490,6 +435,14 @@ ppc_clone: | |||
490 | stw r0,TRAP(r1) /* register set saved */ | 435 | stw r0,TRAP(r1) /* register set saved */ |
491 | b sys_clone | 436 | b sys_clone |
492 | 437 | ||
438 | .globl ppc_swapcontext | ||
439 | ppc_swapcontext: | ||
440 | SAVE_NVGPRS(r1) | ||
441 | lwz r0,TRAP(r1) | ||
442 | rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ | ||
443 | stw r0,TRAP(r1) /* register set saved */ | ||
444 | b sys_swapcontext | ||
445 | |||
493 | /* | 446 | /* |
494 | * Top-level page fault handling. | 447 | * Top-level page fault handling. |
495 | * This is in assembler because if do_page_fault tells us that | 448 | * This is in assembler because if do_page_fault tells us that |
@@ -683,7 +636,7 @@ user_exc_return: /* r10 contains MSR_KERNEL here */ | |||
683 | /* Check current_thread_info()->flags */ | 636 | /* Check current_thread_info()->flags */ |
684 | rlwinm r9,r1,0,0,18 | 637 | rlwinm r9,r1,0,0,18 |
685 | lwz r9,TI_FLAGS(r9) | 638 | lwz r9,TI_FLAGS(r9) |
686 | andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL) | 639 | andi. r0,r9,(_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_NEED_RESCHED) |
687 | bne do_work | 640 | bne do_work |
688 | 641 | ||
689 | restore_user: | 642 | restore_user: |
diff --git a/include/asm-powerpc/thread_info.h b/include/asm-powerpc/thread_info.h index 237fc2b72974..ffc7462d77ba 100644 --- a/include/asm-powerpc/thread_info.h +++ b/include/asm-powerpc/thread_info.h | |||
@@ -37,7 +37,6 @@ struct thread_info { | |||
37 | int preempt_count; /* 0 => preemptable, | 37 | int preempt_count; /* 0 => preemptable, |
38 | <0 => BUG */ | 38 | <0 => BUG */ |
39 | struct restart_block restart_block; | 39 | struct restart_block restart_block; |
40 | void __user *nvgprs_frame; | ||
41 | /* low level flags - has atomic operations done on it */ | 40 | /* low level flags - has atomic operations done on it */ |
42 | unsigned long flags ____cacheline_aligned_in_smp; | 41 | unsigned long flags ____cacheline_aligned_in_smp; |
43 | }; | 42 | }; |
@@ -120,7 +119,6 @@ static inline struct thread_info *current_thread_info(void) | |||
120 | #define TIF_MEMDIE 10 | 119 | #define TIF_MEMDIE 10 |
121 | #define TIF_SECCOMP 11 /* secure computing */ | 120 | #define TIF_SECCOMP 11 /* secure computing */ |
122 | #define TIF_RESTOREALL 12 /* Restore all regs (implies NOERROR) */ | 121 | #define TIF_RESTOREALL 12 /* Restore all regs (implies NOERROR) */ |
123 | #define TIF_SAVE_NVGPRS 13 /* Save r14-r31 in signal frame */ | ||
124 | #define TIF_NOERROR 14 /* Force successful syscall return */ | 122 | #define TIF_NOERROR 14 /* Force successful syscall return */ |
125 | #define TIF_RESTORE_SIGMASK 15 /* Restore signal mask in do_signal */ | 123 | #define TIF_RESTORE_SIGMASK 15 /* Restore signal mask in do_signal */ |
126 | 124 | ||
@@ -137,15 +135,13 @@ static inline struct thread_info *current_thread_info(void) | |||
137 | #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) | 135 | #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) |
138 | #define _TIF_SECCOMP (1<<TIF_SECCOMP) | 136 | #define _TIF_SECCOMP (1<<TIF_SECCOMP) |
139 | #define _TIF_RESTOREALL (1<<TIF_RESTOREALL) | 137 | #define _TIF_RESTOREALL (1<<TIF_RESTOREALL) |
140 | #define _TIF_SAVE_NVGPRS (1<<TIF_SAVE_NVGPRS) | ||
141 | #define _TIF_NOERROR (1<<TIF_NOERROR) | 138 | #define _TIF_NOERROR (1<<TIF_NOERROR) |
142 | #define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) | 139 | #define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) |
143 | #define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP) | 140 | #define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP) |
144 | 141 | ||
145 | #define _TIF_USER_WORK_MASK (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \ | 142 | #define _TIF_USER_WORK_MASK (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \ |
146 | _TIF_NEED_RESCHED | _TIF_RESTOREALL | \ | 143 | _TIF_NEED_RESCHED | _TIF_RESTORE_SIGMASK) |
147 | _TIF_RESTORE_SIGMASK) | 144 | #define _TIF_PERSYSCALL_MASK (_TIF_RESTOREALL|_TIF_NOERROR) |
148 | #define _TIF_PERSYSCALL_MASK (_TIF_RESTOREALL|_TIF_NOERROR|_TIF_SAVE_NVGPRS) | ||
149 | 145 | ||
150 | #endif /* __KERNEL__ */ | 146 | #endif /* __KERNEL__ */ |
151 | 147 | ||