[PATCH] linux-user/s390x: restore fpu_status rounding mode from FPC on sigreturn

Matt Turner posted 1 patch 5 days, 1 hour ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260525152210.4119543-1-mattst88@gmail.com
Maintainers: Laurent Vivier <laurent@vivier.eu>, Helge Deller <deller@gmx.de>, Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>, Cornelia Huck <cohuck@redhat.com>, Eric Farman <farman@linux.ibm.com>, Matthew Rosato <mjrosato@linux.ibm.com>, Richard Henderson <richard.henderson@linaro.org>, Ilya Leoshkevich <iii@linux.ibm.com>, David Hildenbrand <david@kernel.org>
There is a newer version of this series
linux-user/s390x/signal.c     | 6 +++++-
target/s390x/cpu.h            | 1 +
target/s390x/tcg/fpu_helper.c | 6 ++++++
3 files changed, 12 insertions(+), 1 deletion(-)
[PATCH] linux-user/s390x: restore fpu_status rounding mode from FPC on sigreturn
Posted by Matt Turner 5 days, 1 hour ago
QEMU keeps the s390x floating-point control register (FPC) in env->fpc.
The rounding mode bits [2:0] of FPC are reflected into the derived
env->fpu_status via set_float_rounding_mode(); every architectural
write to FPC goes through HELPER(sfpc) which keeps the two in sync.

restore_sigregs() restored FPC with a direct assignment:

    __get_user(env->fpc, &sc->fpregs.fpc);

This wrote env->fpc correctly but never updated env->fpu_status, so on
sigreturn the interrupted code resumed with whatever rounding mode the
signal handler last installed in fpu_status.

Factor the two-step "write fpc + sync fpu_status" logic out of
HELPER(sfpc) into cpu_s390x_load_fpc(), declare it in cpu.h, and call
it from restore_sigregs() in place of the direct assignment.
cpu_s390x_load_fpc() omits the specification-exception check that
HELPER(sfpc) performs; raw signal frame restoration does not validate
the saved state.

Fixes: 2941e0fa05 ("linux-user/s390x: Save/restore fpc when handling a signal")
Cc: qemu-stable@nongnu.org
---
 linux-user/s390x/signal.c     | 6 +++++-
 target/s390x/cpu.h            | 1 +
 target/s390x/tcg/fpu_helper.c | 6 ++++++
 3 files changed, 12 insertions(+), 1 deletion(-)

diff --git ./linux-user/s390x/signal.c ./linux-user/s390x/signal.c
index 96d1c8d11c..28ad80bde4 100644
--- ./linux-user/s390x/signal.c
+++ ./linux-user/s390x/signal.c
@@ -332,7 +332,11 @@ static void restore_sigregs(CPUS390XState *env, target_sigregs *sc)
     for (i = 0; i < 16; i++) {
         __get_user(env->aregs[i], &sc->regs.acrs[i]);
     }
-    __get_user(env->fpc, &sc->fpregs.fpc);
+    {
+        uint32_t fpc;
+        __get_user(fpc, &sc->fpregs.fpc);
+        cpu_s390x_load_fpc(env, fpc);
+    }
     for (i = 0; i < 16; i++) {
         __get_user(*get_freg(env, i), &sc->fpregs.fprs[i]);
     }
diff --git ./target/s390x/cpu.h ./target/s390x/cpu.h
index 3acbe83f0f..f55b79ef8a 100644
--- ./target/s390x/cpu.h
+++ ./target/s390x/cpu.h
@@ -895,6 +895,7 @@ void s390_init_sigp(void);
 /* helper.c */
 void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
 uint64_t s390_cpu_get_psw_mask(CPUS390XState *env);
+void cpu_s390x_load_fpc(CPUS390XState *env, uint32_t fpc);
 
 /* outside of target/s390x/ */
 S390CPU *s390_cpu_addr2state(uint16_t cpu_addr);
diff --git ./target/s390x/tcg/fpu_helper.c ./target/s390x/tcg/fpu_helper.c
index 6ca0b7162b..b1c61d73d7 100644
--- ./target/s390x/tcg/fpu_helper.c
+++ ./target/s390x/tcg/fpu_helper.c
@@ -1087,6 +1087,12 @@ static const int fpc_to_rnd[8] = {
     float_round_to_odd,
 };
 
+void cpu_s390x_load_fpc(CPUS390XState *env, uint32_t fpc)
+{
+    env->fpc = fpc;
+    set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
+}
+
 /* set fpc */
 void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
 {
-- 
2.53.0
Re: [PATCH] linux-user/s390x: restore fpu_status rounding mode from FPC on sigreturn
Posted by Ilya Leoshkevich 4 days, 5 hours ago
On 5/25/26 17:22, Matt Turner wrote:
> QEMU keeps the s390x floating-point control register (FPC) in env->fpc.
> The rounding mode bits [2:0] of FPC are reflected into the derived
> env->fpu_status via set_float_rounding_mode(); every architectural
> write to FPC goes through HELPER(sfpc) which keeps the two in sync.
> 
> restore_sigregs() restored FPC with a direct assignment:
> 
>      __get_user(env->fpc, &sc->fpregs.fpc);
> 
> This wrote env->fpc correctly but never updated env->fpu_status, so on
> sigreturn the interrupted code resumed with whatever rounding mode the
> signal handler last installed in fpu_status.
> 
> Factor the two-step "write fpc + sync fpu_status" logic out of
> HELPER(sfpc) into cpu_s390x_load_fpc(), declare it in cpu.h, and call
> it from restore_sigregs() in place of the direct assignment.
> cpu_s390x_load_fpc() omits the specification-exception check that
> HELPER(sfpc) performs; raw signal frame restoration does not validate
> the saved state.
> 
> Fixes: 2941e0fa05 ("linux-user/s390x: Save/restore fpc when handling a signal")
> Cc: qemu-stable@nongnu.org
> ---
>   linux-user/s390x/signal.c     | 6 +++++-
>   target/s390x/cpu.h            | 1 +
>   target/s390x/tcg/fpu_helper.c | 6 ++++++
>   3 files changed, 12 insertions(+), 1 deletion(-)

Just curious, how did you stumble upon this?
It looks like a source of nasty intermittent bugs.

> diff --git ./linux-user/s390x/signal.c ./linux-user/s390x/signal.c
> index 96d1c8d11c..28ad80bde4 100644
> --- ./linux-user/s390x/signal.c
> +++ ./linux-user/s390x/signal.c
> @@ -332,7 +332,11 @@ static void restore_sigregs(CPUS390XState *env, target_sigregs *sc)
>       for (i = 0; i < 16; i++) {
>           __get_user(env->aregs[i], &sc->regs.acrs[i]);
>       }
> -    __get_user(env->fpc, &sc->fpregs.fpc);
> +    {
> +        uint32_t fpc;
> +        __get_user(fpc, &sc->fpregs.fpc);
> +        cpu_s390x_load_fpc(env, fpc);
> +    }
>       for (i = 0; i < 16; i++) {
>           __get_user(*get_freg(env, i), &sc->fpregs.fprs[i]);
>       }
> diff --git ./target/s390x/cpu.h ./target/s390x/cpu.h
> index 3acbe83f0f..f55b79ef8a 100644
> --- ./target/s390x/cpu.h
> +++ ./target/s390x/cpu.h
> @@ -895,6 +895,7 @@ void s390_init_sigp(void);
>   /* helper.c */
>   void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
>   uint64_t s390_cpu_get_psw_mask(CPUS390XState *env);
> +void cpu_s390x_load_fpc(CPUS390XState *env, uint32_t fpc);
>   
>   /* outside of target/s390x/ */
>   S390CPU *s390_cpu_addr2state(uint16_t cpu_addr);
> diff --git ./target/s390x/tcg/fpu_helper.c ./target/s390x/tcg/fpu_helper.c
> index 6ca0b7162b..b1c61d73d7 100644
> --- ./target/s390x/tcg/fpu_helper.c
> +++ ./target/s390x/tcg/fpu_helper.c
> @@ -1087,6 +1087,12 @@ static const int fpc_to_rnd[8] = {
>       float_round_to_odd,
>   };
>   
> +void cpu_s390x_load_fpc(CPUS390XState *env, uint32_t fpc)
> +{
> +    env->fpc = fpc;
> +    set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
> +}
> +
>   /* set fpc */
>   void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
>   {

Could you reuse cpu_s390x_load_fpc() in HELPER(sfpc)?
The new sequence looks semantically identical to the one in the helper.

Also, I think we do need to partially reuse the sanity check.
Looking at kernel's fpu_lfpc_safe(), whenever the user writes a corrupt
value into the signal frame and the kernel tries to restore it, an
exception happens and 0 ends up being used instead.
Re: [PATCH] linux-user/s390x: restore fpu_status rounding mode from FPC on sigreturn
Posted by Matt Turner 4 days, 1 hour ago
On Tue, May 26, 2026 at 7:20 AM Ilya Leoshkevich <iii@linux.ibm.com> wrote:
>
> On 5/25/26 17:22, Matt Turner wrote:
> > QEMU keeps the s390x floating-point control register (FPC) in env->fpc.
> > The rounding mode bits [2:0] of FPC are reflected into the derived
> > env->fpu_status via set_float_rounding_mode(); every architectural
> > write to FPC goes through HELPER(sfpc) which keeps the two in sync.
> >
> > restore_sigregs() restored FPC with a direct assignment:
> >
> >      __get_user(env->fpc, &sc->fpregs.fpc);
> >
> > This wrote env->fpc correctly but never updated env->fpu_status, so on
> > sigreturn the interrupted code resumed with whatever rounding mode the
> > signal handler last installed in fpu_status.
> >
> > Factor the two-step "write fpc + sync fpu_status" logic out of
> > HELPER(sfpc) into cpu_s390x_load_fpc(), declare it in cpu.h, and call
> > it from restore_sigregs() in place of the direct assignment.
> > cpu_s390x_load_fpc() omits the specification-exception check that
> > HELPER(sfpc) performs; raw signal frame restoration does not validate
> > the saved state.
> >
> > Fixes: 2941e0fa05 ("linux-user/s390x: Save/restore fpc when handling a signal")
> > Cc: qemu-stable@nongnu.org
> > ---
> >   linux-user/s390x/signal.c     | 6 +++++-
> >   target/s390x/cpu.h            | 1 +
> >   target/s390x/tcg/fpu_helper.c | 6 ++++++
> >   3 files changed, 12 insertions(+), 1 deletion(-)
>
> Just curious, how did you stumble upon this?
> It looks like a source of nasty intermittent bugs.

Indeed.

I spent a lot of time this weekend debugging the `signals` test on
sh4, which resulted in this patch:

https://lists.gnu.org/archive/html/qemu-devel/2026-05/msg06646.html

It was hard to debug from scratch, but the solution was so simple and
the problem so obvious (if you know to look for it) that I figured I
would do an audit of other architectures. I found this, as well as an
issue on MIPS and another on PPC.

Hopefully my ten minutes of effort on s390/mips/ppc will save someone
a couple of days in the future. :)
Re: [PATCH] linux-user/s390x: restore fpu_status rounding mode from FPC on sigreturn
Posted by Matt Turner 4 days, 18 hours ago
On Mon, May 25, 2026 at 11:22 AM Matt Turner <mattst88@gmail.com> wrote:
>
> QEMU keeps the s390x floating-point control register (FPC) in env->fpc.
> The rounding mode bits [2:0] of FPC are reflected into the derived
> env->fpu_status via set_float_rounding_mode(); every architectural
> write to FPC goes through HELPER(sfpc) which keeps the two in sync.
>
> restore_sigregs() restored FPC with a direct assignment:
>
>     __get_user(env->fpc, &sc->fpregs.fpc);
>
> This wrote env->fpc correctly but never updated env->fpu_status, so on
> sigreturn the interrupted code resumed with whatever rounding mode the
> signal handler last installed in fpu_status.
>
> Factor the two-step "write fpc + sync fpu_status" logic out of
> HELPER(sfpc) into cpu_s390x_load_fpc(), declare it in cpu.h, and call
> it from restore_sigregs() in place of the direct assignment.
> cpu_s390x_load_fpc() omits the specification-exception check that
> HELPER(sfpc) performs; raw signal frame restoration does not validate
> the saved state.
>
> Fixes: 2941e0fa05 ("linux-user/s390x: Save/restore fpc when handling a signal")
> Cc: qemu-stable@nongnu.org
> ---

Signed-off-by: Matt Turner <mattst88@gmail.com>
[PATCH v2] linux-user/s390x: restore fpu_status rounding mode from FPC on sigreturn
Posted by Matt Turner 4 days, 1 hour ago
QEMU keeps the s390x floating-point control register (FPC) in env->fpc.
The rounding mode bits [2:0] of FPC are reflected into the derived
env->fpu_status via set_float_rounding_mode(); every architectural
write to FPC goes through HELPER(sfpc) which keeps the two in sync.

restore_sigregs() restored FPC with a direct assignment:

    __get_user(env->fpc, &sc->fpregs.fpc);

This wrote env->fpc correctly but never updated env->fpu_status, so on
sigreturn the interrupted code resumed with whatever rounding mode the
signal handler last installed in fpu_status.

Factor the two-step "write fpc + sync fpu_status" logic out of
HELPER(sfpc) into cpu_s390x_load_fpc(), declare it in cpu.h, and call
it from restore_sigregs() in place of the direct assignment.

cpu_s390x_load_fpc() partially reuses the sanity check from
HELPER(sfpc): if the FPC value has an invalid rounding mode or reserved
bits set, it falls back to 0, matching the kernel's fpu_lfpc_safe()
behavior where a corrupt signal frame value causes a specification
exception and 0 is used instead.

HELPER(sfpc) now calls cpu_s390x_load_fpc() after its full
specification-exception check, including the FEAT_FLOATING_POINT_EXT
test that is not needed for the signal restore path.

Fixes: 2941e0fa05 ("linux-user/s390x: Save/restore fpc when handling a signal")
Cc: qemu-stable@nongnu.org
Signed-off-by: Matt Turner <mattst88@gmail.com>
---
 linux-user/s390x/signal.c     |  6 +++++-
 target/s390x/cpu.h            |  1 +
 target/s390x/tcg/fpu_helper.c | 20 ++++++++++++++------
 3 files changed, 20 insertions(+), 7 deletions(-)

diff --git ./linux-user/s390x/signal.c ./linux-user/s390x/signal.c
index 96d1c8d11c..28ad80bde4 100644
--- ./linux-user/s390x/signal.c
+++ ./linux-user/s390x/signal.c
@@ -332,7 +332,11 @@ static void restore_sigregs(CPUS390XState *env, target_sigregs *sc)
     for (i = 0; i < 16; i++) {
         __get_user(env->aregs[i], &sc->regs.acrs[i]);
     }
-    __get_user(env->fpc, &sc->fpregs.fpc);
+    {
+        uint32_t fpc;
+        __get_user(fpc, &sc->fpregs.fpc);
+        cpu_s390x_load_fpc(env, fpc);
+    }
     for (i = 0; i < 16; i++) {
         __get_user(*get_freg(env, i), &sc->fpregs.fprs[i]);
     }
diff --git ./target/s390x/cpu.h ./target/s390x/cpu.h
index 3acbe83f0f..f55b79ef8a 100644
--- ./target/s390x/cpu.h
+++ ./target/s390x/cpu.h
@@ -895,6 +895,7 @@ void s390_init_sigp(void);
 /* helper.c */
 void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
 uint64_t s390_cpu_get_psw_mask(CPUS390XState *env);
+void cpu_s390x_load_fpc(CPUS390XState *env, uint32_t fpc);
 
 /* outside of target/s390x/ */
 S390CPU *s390_cpu_addr2state(uint16_t cpu_addr);
diff --git ./target/s390x/tcg/fpu_helper.c ./target/s390x/tcg/fpu_helper.c
index 6ca0b7162b..107025e675 100644
--- ./target/s390x/tcg/fpu_helper.c
+++ ./target/s390x/tcg/fpu_helper.c
@@ -1087,6 +1087,19 @@ static const int fpc_to_rnd[8] = {
     float_round_to_odd,
 };
 
+void cpu_s390x_load_fpc(CPUS390XState *env, uint32_t fpc)
+{
+    /*
+     * Mimic kernel fpu_lfpc_safe(): a corrupt signal frame value that would
+     * trigger a specification exception instead results in FPC being set to 0.
+     */
+    if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u) {
+        fpc = 0;
+    }
+    env->fpc = fpc;
+    set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
+}
+
 /* set fpc */
 void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
 {
@@ -1094,12 +1107,7 @@ void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
         (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
         tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
     }
-
-    /* Install everything in the main FPC.  */
-    env->fpc = fpc;
-
-    /* Install the rounding mode in the shadow fpu_status.  */
-    set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
+    cpu_s390x_load_fpc(env, fpc);
 }
 
 /* set fpc and signal */
-- 
2.53.0
Re: [PATCH v2] linux-user/s390x: restore fpu_status rounding mode from FPC on sigreturn
Posted by Helge Deller 4 days, 1 hour ago
On 5/26/26 17:05, Matt Turner wrote:
> QEMU keeps the s390x floating-point control register (FPC) in env->fpc.
> The rounding mode bits [2:0] of FPC are reflected into the derived
> env->fpu_status via set_float_rounding_mode(); every architectural
> write to FPC goes through HELPER(sfpc) which keeps the two in sync.
> 
> restore_sigregs() restored FPC with a direct assignment:
> 
>      __get_user(env->fpc, &sc->fpregs.fpc);
> 
> This wrote env->fpc correctly but never updated env->fpu_status, so on
> sigreturn the interrupted code resumed with whatever rounding mode the
> signal handler last installed in fpu_status.
> 
> Factor the two-step "write fpc + sync fpu_status" logic out of
> HELPER(sfpc) into cpu_s390x_load_fpc(), declare it in cpu.h, and call
> it from restore_sigregs() in place of the direct assignment.
> 
> cpu_s390x_load_fpc() partially reuses the sanity check from
> HELPER(sfpc): if the FPC value has an invalid rounding mode or reserved
> bits set, it falls back to 0, matching the kernel's fpu_lfpc_safe()
> behavior where a corrupt signal frame value causes a specification
> exception and 0 is used instead.
> 
> HELPER(sfpc) now calls cpu_s390x_load_fpc() after its full
> specification-exception check, including the FEAT_FLOATING_POINT_EXT
> test that is not needed for the signal restore path.
> 
> Fixes: 2941e0fa05 ("linux-user/s390x: Save/restore fpc when handling a signal")
> Cc: qemu-stable@nongnu.org
> Signed-off-by: Matt Turner <mattst88@gmail.com>
> ---
>   linux-user/s390x/signal.c     |  6 +++++-
>   target/s390x/cpu.h            |  1 +
>   target/s390x/tcg/fpu_helper.c | 20 ++++++++++++++------
>   3 files changed, 20 insertions(+), 7 deletions(-)
> 
> diff --git ./linux-user/s390x/signal.c ./linux-user/s390x/signal.c
> index 96d1c8d11c..28ad80bde4 100644
> --- ./linux-user/s390x/signal.c
> +++ ./linux-user/s390x/signal.c
> @@ -332,7 +332,11 @@ static void restore_sigregs(CPUS390XState *env, target_sigregs *sc)
>       for (i = 0; i < 16; i++) {
>           __get_user(env->aregs[i], &sc->regs.acrs[i]);
>       }
> -    __get_user(env->fpc, &sc->fpregs.fpc);
> +    {
> +        uint32_t fpc;

to avoid putting this block into braces, can't fpc be moved some lines above,
where the other variables are declared?

> +        __get_user(fpc, &sc->fpregs.fpc);
> +        cpu_s390x_load_fpc(env, fpc);
> +    }
>       for (i = 0; i < 16; i++) {
>           __get_user(*get_freg(env, i), &sc->fpregs.fprs[i]);
>       }
> diff --git ./target/s390x/cpu.h ./target/s390x/cpu.h
> index 3acbe83f0f..f55b79ef8a 100644
> --- ./target/s390x/cpu.h
> +++ ./target/s390x/cpu.h
> @@ -895,6 +895,7 @@ void s390_init_sigp(void);
>   /* helper.c */
>   void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
>   uint64_t s390_cpu_get_psw_mask(CPUS390XState *env);
> +void cpu_s390x_load_fpc(CPUS390XState *env, uint32_t fpc);
>   
>   /* outside of target/s390x/ */
>   S390CPU *s390_cpu_addr2state(uint16_t cpu_addr);
> diff --git ./target/s390x/tcg/fpu_helper.c ./target/s390x/tcg/fpu_helper.c
> index 6ca0b7162b..107025e675 100644
> --- ./target/s390x/tcg/fpu_helper.c
> +++ ./target/s390x/tcg/fpu_helper.c
> @@ -1087,6 +1087,19 @@ static const int fpc_to_rnd[8] = {
>       float_round_to_odd,
>   };
>   
> +void cpu_s390x_load_fpc(CPUS390XState *env, uint32_t fpc)
> +{
> +    /*
> +     * Mimic kernel fpu_lfpc_safe(): a corrupt signal frame value that would
> +     * trigger a specification exception instead results in FPC being set to 0.
> +     */
> +    if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u) {
> +        fpc = 0;
> +    }
> +    env->fpc = fpc;
> +    set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
> +}
> +
>   /* set fpc */
>   void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
>   {
> @@ -1094,12 +1107,7 @@ void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
>           (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
>           tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
>       }
> -
> -    /* Install everything in the main FPC.  */
> -    env->fpc = fpc;
> -
> -    /* Install the rounding mode in the shadow fpu_status.  */
> -    set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
> +    cpu_s390x_load_fpc(env, fpc);
>   }
>   
>   /* set fpc and signal */
Re: [PATCH v2] linux-user/s390x: restore fpu_status rounding mode from FPC on sigreturn
Posted by Helge Deller 3 days, 22 hours ago
On 5/26/26 17:10, Helge Deller wrote:
> On 5/26/26 17:05, Matt Turner wrote:
>> QEMU keeps the s390x floating-point control register (FPC) in env->fpc.
>> The rounding mode bits [2:0] of FPC are reflected into the derived
>> env->fpu_status via set_float_rounding_mode(); every architectural
>> write to FPC goes through HELPER(sfpc) which keeps the two in sync.
>>
>> restore_sigregs() restored FPC with a direct assignment:
>>
>>      __get_user(env->fpc, &sc->fpregs.fpc);
>>
>> This wrote env->fpc correctly but never updated env->fpu_status, so on
>> sigreturn the interrupted code resumed with whatever rounding mode the
>> signal handler last installed in fpu_status.
>>
>> Factor the two-step "write fpc + sync fpu_status" logic out of
>> HELPER(sfpc) into cpu_s390x_load_fpc(), declare it in cpu.h, and call
>> it from restore_sigregs() in place of the direct assignment.
>>
>> cpu_s390x_load_fpc() partially reuses the sanity check from
>> HELPER(sfpc): if the FPC value has an invalid rounding mode or reserved
>> bits set, it falls back to 0, matching the kernel's fpu_lfpc_safe()
>> behavior where a corrupt signal frame value causes a specification
>> exception and 0 is used instead.
>>
>> HELPER(sfpc) now calls cpu_s390x_load_fpc() after its full
>> specification-exception check, including the FEAT_FLOATING_POINT_EXT
>> test that is not needed for the signal restore path.
>>
>> Fixes: 2941e0fa05 ("linux-user/s390x: Save/restore fpc when handling a signal")
>> Cc: qemu-stable@nongnu.org
>> Signed-off-by: Matt Turner <mattst88@gmail.com>
>> ---
>>   linux-user/s390x/signal.c     |  6 +++++-
>>   target/s390x/cpu.h            |  1 +
>>   target/s390x/tcg/fpu_helper.c | 20 ++++++++++++++------
>>   3 files changed, 20 insertions(+), 7 deletions(-)
>>
>> diff --git ./linux-user/s390x/signal.c ./linux-user/s390x/signal.c
>> index 96d1c8d11c..28ad80bde4 100644
>> --- ./linux-user/s390x/signal.c
>> +++ ./linux-user/s390x/signal.c
>> @@ -332,7 +332,11 @@ static void restore_sigregs(CPUS390XState *env, target_sigregs *sc)
>>       for (i = 0; i < 16; i++) {
>>           __get_user(env->aregs[i], &sc->regs.acrs[i]);
>>       }
>> -    __get_user(env->fpc, &sc->fpregs.fpc);
>> +    {
>> +        uint32_t fpc;
> 
> to avoid putting this block into braces, can't fpc be moved some lines above,
> where the other variables are declared?

Forget this. ^^^
I see it's used like this in various places across architectures, so
let's keep it like you have in this patch here.

Helge