diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-04-29 04:11:34 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-02-03 18:16:02 -0500 |
commit | 14203e19cbc562a79f49117c45c80639a1e65bdd (patch) | |
tree | 758937f82d73a963b9ed0f5979f303c1522195fa | |
parent | c886a9fc1f69c0e53788a9c4a780b6b8825bd4ab (diff) |
microblaze: fix the horror with restarts of sigreturn()
solution a-la arm one - pick a callee-saved register (r30), set it
non-zero when entering a syscall, have sigreturn wrapper zero it out
and pass the value in it to do_notify_resume() as "in_syscall" (actually,
"restarts allowed") argument.
Note that we don't give a damn about ret_from_fork() - return value
is not restart-worthy anyway.
Possible remaining bug: on !MMU we still have _debug_exception()
restartable. If it hits with -ERESTART_... accidentally in r3, fun happens.
MMU does _not_ have _debug_exception() restartable. If that's decided to
be a bug (as I strongly suspect it to be), we'll just need to replace
setting r30 to 1 with setting r30 to 0 in !MMU _debug_exception().
Up to microblaze maintainers...
[folded a fix from Michal]
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | arch/microblaze/kernel/entry-nommu.S | 5 | ||||
-rw-r--r-- | arch/microblaze/kernel/entry.S | 4 |
2 files changed, 7 insertions, 2 deletions
diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S index 29a05d62ec1a..96f97f845495 100644 --- a/arch/microblaze/kernel/entry-nommu.S +++ b/arch/microblaze/kernel/entry-nommu.S | |||
@@ -280,6 +280,7 @@ ENTRY(_user_exception) | |||
280 | /* Figure out which function to use for this system call. */ | 280 | /* Figure out which function to use for this system call. */ |
281 | /* Note Microblaze barrel shift is optional, so don't rely on it */ | 281 | /* Note Microblaze barrel shift is optional, so don't rely on it */ |
282 | add r12, r12, r12 /* convert num -> ptr */ | 282 | add r12, r12, r12 /* convert num -> ptr */ |
283 | addik r30, r0, 1 /* restarts allowed */ | ||
283 | add r12, r12, r12 | 284 | add r12, r12, r12 |
284 | lwi r12, r12, sys_call_table /* Get function pointer */ | 285 | lwi r12, r12, sys_call_table /* Get function pointer */ |
285 | addik r15, r0, ret_to_user-8 /* set return address */ | 286 | addik r15, r0, ret_to_user-8 /* set return address */ |
@@ -369,6 +370,7 @@ ENTRY(_debug_exception) | |||
369 | bralid r15, send_sig | 370 | bralid r15, send_sig |
370 | add r7, r0, r0 /* 3rd param zero */ | 371 | add r7, r0, r0 /* 3rd param zero */ |
371 | 372 | ||
373 | addik r30, r0, 1 /* restarts allowed ??? */ | ||
372 | /* Restore r3/r4 to work around how ret_to_user works */ | 374 | /* Restore r3/r4 to work around how ret_to_user works */ |
373 | lwi r3, r1, PT_R3 | 375 | lwi r3, r1, PT_R3 |
374 | lwi r4, r1, PT_R4 | 376 | lwi r4, r1, PT_R4 |
@@ -492,7 +494,7 @@ work_pending: | |||
492 | nop | 494 | nop |
493 | 1: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME | 495 | 1: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME |
494 | beqi r11, no_work_pending | 496 | beqi r11, no_work_pending |
495 | addk r5, r1, r0 | 497 | addk r5, r30, r0 |
496 | bralid r15, do_notify_resume | 498 | bralid r15, do_notify_resume |
497 | addik r6, r0, 1 | 499 | addik r6, r0, 1 |
498 | bri no_work_pending | 500 | bri no_work_pending |
@@ -562,6 +564,7 @@ no_work_pending: | |||
562 | nop | 564 | nop |
563 | 565 | ||
564 | sys_rt_sigreturn_wrapper: | 566 | sys_rt_sigreturn_wrapper: |
567 | addk r30, r0, r0 /* no restarts for this one */ | ||
565 | brid sys_rt_sigreturn | 568 | brid sys_rt_sigreturn |
566 | addk r5, r1, r0 | 569 | addk r5, r1, r0 |
567 | 570 | ||
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index c217367dfc7b..18908d29248b 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S | |||
@@ -353,6 +353,7 @@ C_ENTRY(_user_exception): | |||
353 | /* Figure out which function to use for this system call. */ | 353 | /* Figure out which function to use for this system call. */ |
354 | /* Note Microblaze barrel shift is optional, so don't rely on it */ | 354 | /* Note Microblaze barrel shift is optional, so don't rely on it */ |
355 | add r12, r12, r12; /* convert num -> ptr */ | 355 | add r12, r12, r12; /* convert num -> ptr */ |
356 | addi r30, r0, 1 /* restarts allowed */ | ||
356 | add r12, r12, r12; | 357 | add r12, r12, r12; |
357 | 358 | ||
358 | #ifdef DEBUG | 359 | #ifdef DEBUG |
@@ -417,7 +418,7 @@ C_ENTRY(ret_from_trap): | |||
417 | 418 | ||
418 | addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ | 419 | addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ |
419 | bralid r15, do_notify_resume; /* Handle any signals */ | 420 | bralid r15, do_notify_resume; /* Handle any signals */ |
420 | addi r6, r0, 1; /* Arg 2: int in_syscall */ | 421 | add r6, r30, r0; /* Arg 2: int in_syscall */ |
421 | 422 | ||
422 | /* Finally, return to user state. */ | 423 | /* Finally, return to user state. */ |
423 | 1: set_bip; /* Ints masked for state restore */ | 424 | 1: set_bip; /* Ints masked for state restore */ |
@@ -464,6 +465,7 @@ C_ENTRY(ret_from_kernel_thread): | |||
464 | add r3, r0, r0 | 465 | add r3, r0, r0 |
465 | 466 | ||
466 | C_ENTRY(sys_rt_sigreturn_wrapper): | 467 | C_ENTRY(sys_rt_sigreturn_wrapper): |
468 | addik r30, r0, 0 /* no restarts */ | ||
467 | brid sys_rt_sigreturn /* Do real work */ | 469 | brid sys_rt_sigreturn /* Do real work */ |
468 | addik r5, r1, 0; /* add user context as 1st arg */ | 470 | addik r5, r1, 0; /* add user context as 1st arg */ |
469 | 471 | ||