parisc: fix double restarts
Don't bother restoring r28 on syscall restarts; it's clobbered by syscall anyway. Reuse (now unused) ->orig_r28 as "no restarts allowed" flag. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Родитель
8ca8230b71
Коммит
00df111e7e
|
@ -71,7 +71,7 @@ ENTRY(hpux_gateway_page)
|
|||
STREG %r26, TASK_PT_GR26(%r1) /* 1st argument */
|
||||
STREG %r27, TASK_PT_GR27(%r1) /* user dp */
|
||||
STREG %r28, TASK_PT_GR28(%r1) /* return value 0 */
|
||||
STREG %r28, TASK_PT_ORIG_R28(%r1) /* return value 0 (saved for signals) */
|
||||
STREG %r0, TASK_PT_ORIG_R28(%r1) /* don't prohibit restarts */
|
||||
STREG %r29, TASK_PT_GR29(%r1) /* 8th argument */
|
||||
STREG %r31, TASK_PT_GR31(%r1) /* preserve syscall return ptr */
|
||||
|
||||
|
|
|
@ -113,6 +113,8 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
|
|||
(usp - sigframe_size);
|
||||
DBG(2,"sys_rt_sigreturn: frame is %p\n", frame);
|
||||
|
||||
regs->orig_r28 = 1; /* no restarts for sigreturn */
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
compat_frame = (struct compat_rt_sigframe __user *)frame;
|
||||
|
||||
|
@ -462,6 +464,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
|
|||
static inline void
|
||||
syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
|
||||
{
|
||||
if (regs->orig_r28)
|
||||
return;
|
||||
regs->orig_r28 = 1; /* no more restarts */
|
||||
/* Check the return code */
|
||||
switch (regs->gr[28]) {
|
||||
case -ERESTART_RESTARTBLOCK:
|
||||
|
@ -482,8 +487,6 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
|
|||
* we have to do is fiddle the return pointer.
|
||||
*/
|
||||
regs->gr[31] -= 8; /* delayed branching */
|
||||
/* Preserve original r28. */
|
||||
regs->gr[28] = regs->orig_r28;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -491,6 +494,9 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
|
|||
static inline void
|
||||
insert_restart_trampoline(struct pt_regs *regs)
|
||||
{
|
||||
if (regs->orig_r28)
|
||||
return;
|
||||
regs->orig_r28 = 1; /* no more restarts */
|
||||
switch(regs->gr[28]) {
|
||||
case -ERESTART_RESTARTBLOCK: {
|
||||
/* Restart the system call - no handlers present */
|
||||
|
@ -525,9 +531,6 @@ insert_restart_trampoline(struct pt_regs *regs)
|
|||
flush_user_icache_range(regs->gr[30], regs->gr[30] + 4);
|
||||
|
||||
regs->gr[31] = regs->gr[30] + 8;
|
||||
/* Preserve original r28. */
|
||||
regs->gr[28] = regs->orig_r28;
|
||||
|
||||
return;
|
||||
}
|
||||
case -ERESTARTNOHAND:
|
||||
|
@ -539,9 +542,6 @@ insert_restart_trampoline(struct pt_regs *regs)
|
|||
* slot of the branch external instruction.
|
||||
*/
|
||||
regs->gr[31] -= 8;
|
||||
/* Preserve original r28. */
|
||||
regs->gr[28] = regs->orig_r28;
|
||||
|
||||
return;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -156,7 +156,7 @@ linux_gateway_entry:
|
|||
STREG %r26, TASK_PT_GR26(%r1) /* 1st argument */
|
||||
STREG %r27, TASK_PT_GR27(%r1) /* user dp */
|
||||
STREG %r28, TASK_PT_GR28(%r1) /* return value 0 */
|
||||
STREG %r28, TASK_PT_ORIG_R28(%r1) /* return value 0 (saved for signals) */
|
||||
STREG %r0, TASK_PT_ORIG_R28(%r1) /* don't prohibit restarts */
|
||||
STREG %r29, TASK_PT_GR29(%r1) /* return value 1 */
|
||||
STREG %r31, TASK_PT_GR31(%r1) /* preserve syscall return ptr */
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче