diff mbox series

[3/7] linux-user/nios2: Adjust error return

Message ID 20220320160009.2665152-4-richard.henderson@linaro.org
State New
Headers show
Series linux-user/nios2: Fix clone and sigreturn | expand

Commit Message

Richard Henderson March 20, 2022, 4 p.m. UTC
Follow syscall_set_return_value rather than the kernel assembly
in setting the syscall return values.  Only negate ret on error.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/nios2/cpu_loop.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

Comments

Peter Maydell March 25, 2022, 12:12 p.m. UTC | #1
On Sun, 20 Mar 2022 at 16:06, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Follow syscall_set_return_value rather than the kernel assembly
> in setting the syscall return values.  Only negate ret on error.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  linux-user/nios2/cpu_loop.c | 15 ++++++++++++---
>  1 file changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/linux-user/nios2/cpu_loop.c b/linux-user/nios2/cpu_loop.c
> index ac71f4ee47..2ae94f4a95 100644
> --- a/linux-user/nios2/cpu_loop.c
> +++ b/linux-user/nios2/cpu_loop.c
> @@ -48,9 +48,18 @@ void cpu_loop(CPUNios2State *env)
>                                   env->regs[7], env->regs[8], env->regs[9],
>                                   0, 0);
>
> -                env->regs[2] = abs(ret);
> -                /* Return value is 0..4096 */
> -                env->regs[7] = ret > 0xfffff000u;
> +                /*
> +                 * See syscall_set_return_value.
> +                 * Use the QEMU traditional -515 error indication in
> +                 * preference to the < 0 indication used in entry.S.
> +                 */

Well, it is traditional, in that we've used it for sparc for
instance right back to commit 060366c5ad18b3e in 2004, and
even earlier for ppc since commit 678673089d1b.
probably for about as long for ppc. But *why* do we use this?
Well, 516 is ERESTART_RESTARTBLOCK, and that's what the
arch/sparc/kernel/entry.S code is comparing against (it does a
greater-than-or-equal check, I think, hence 516, not 515).

For powerpc, however, the kernel handles setting the CCR
bit in syscall_exit_prepare(), and there it checks against
-MAX_ERRNO.

nios2, as you note in the commit message, does a < 0 check.

So I think:
 * 515 is correct for SPARC, but we really ought not to use
   a hardcoded constant there
 * we are checking against the wrong value for PPC and should
   be checking MAX_ERRNO
 * this patch does the wrong thing for nios2

If we do the same < 0 check that the kernel does, does anything
break ?

thanks
-- PMM
Peter Maydell March 25, 2022, 1:37 p.m. UTC | #2
On Fri, 25 Mar 2022 at 12:12, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Sun, 20 Mar 2022 at 16:06, Richard Henderson
> <richard.henderson@linaro.org> wrote:
> >
> > Follow syscall_set_return_value rather than the kernel assembly
> > in setting the syscall return values.  Only negate ret on error.
> >
> > Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> > ---
> >  linux-user/nios2/cpu_loop.c | 15 ++++++++++++---
> >  1 file changed, 12 insertions(+), 3 deletions(-)
> >
> > diff --git a/linux-user/nios2/cpu_loop.c b/linux-user/nios2/cpu_loop.c
> > index ac71f4ee47..2ae94f4a95 100644
> > --- a/linux-user/nios2/cpu_loop.c
> > +++ b/linux-user/nios2/cpu_loop.c
> > @@ -48,9 +48,18 @@ void cpu_loop(CPUNios2State *env)
> >                                   env->regs[7], env->regs[8], env->regs[9],
> >                                   0, 0);
> >
> > -                env->regs[2] = abs(ret);
> > -                /* Return value is 0..4096 */
> > -                env->regs[7] = ret > 0xfffff000u;
> > +                /*
> > +                 * See syscall_set_return_value.
> > +                 * Use the QEMU traditional -515 error indication in
> > +                 * preference to the < 0 indication used in entry.S.
> > +                 */
>
> Well, it is traditional, in that we've used it for sparc for
> instance right back to commit 060366c5ad18b3e in 2004, and
> even earlier for ppc since commit 678673089d1b.
> probably for about as long for ppc. But *why* do we use this?
> Well, 516 is ERESTART_RESTARTBLOCK, and that's what the
> arch/sparc/kernel/entry.S code is comparing against (it does a
> greater-than-or-equal check, I think, hence 516, not 515).
>
> For powerpc, however, the kernel handles setting the CCR
> bit in syscall_exit_prepare(), and there it checks against
> -MAX_ERRNO.

This turns out to be because in 2015 kernel commit c3525940cca5
switched powerpc from checking against 515/516 and instead made
them check MAX_ERRNO (4095).

(If anybody cared about seccomp on sparc hosts they'd probably
want to fix the sparc kernel similarly, but presumably nobody
does :-))

The kernel commit message mentions some infrastructure in
the form of force_successful_syscall_return() where syscall
implementations can force that a value above -MAX_ERRNO
is still treated as "success". In theory perhaps we should
have something similar...

-- PMM
Richard Henderson March 25, 2022, 6:55 p.m. UTC | #3
On 3/25/22 07:37, Peter Maydell wrote:
> This turns out to be because in 2015 kernel commit c3525940cca5
> switched powerpc from checking against 515/516 and instead made
> them check MAX_ERRNO (4095).
> 
> (If anybody cared about seccomp on sparc hosts they'd probably
> want to fix the sparc kernel similarly, but presumably nobody
> does :-))

Indeed, thanks for the archaeology.

> The kernel commit message mentions some infrastructure in
> the form of force_successful_syscall_return() where syscall
> implementations can force that a value above -MAX_ERRNO
> is still treated as "success". In theory perhaps we should
> have something similar...

In theory, yes.  It affects 3 or 4 syscalls.
That said, nios2 doesn't define force_successful_syscall_return. :-P


r~
diff mbox series

Patch

diff --git a/linux-user/nios2/cpu_loop.c b/linux-user/nios2/cpu_loop.c
index ac71f4ee47..2ae94f4a95 100644
--- a/linux-user/nios2/cpu_loop.c
+++ b/linux-user/nios2/cpu_loop.c
@@ -48,9 +48,18 @@  void cpu_loop(CPUNios2State *env)
                                  env->regs[7], env->regs[8], env->regs[9],
                                  0, 0);
 
-                env->regs[2] = abs(ret);
-                /* Return value is 0..4096 */
-                env->regs[7] = ret > 0xfffff000u;
+                /*
+                 * See syscall_set_return_value.
+                 * Use the QEMU traditional -515 error indication in
+                 * preference to the < 0 indication used in entry.S.
+                 */
+                if (ret > (abi_ulong)-515) {
+                    env->regs[2] = -ret;
+                    env->regs[7] = 1;
+                } else {
+                    env->regs[2] = ret;
+                    env->regs[7] = 0;
+                }
                 break;
 
             case 1: