qemu-e2k/linux-user/sh4
Mikulas Patocka 3b894b699c linux-user/sh4: Fix crashes on signal delivery
sh4 uses gUSA (general UserSpace Atomicity) to provide atomicity on CPUs
that don't have atomic instructions. A gUSA region that adds 1 to an
atomic variable stored in @R2 looks like this:

  4004b6:       03 c7           mova    4004c4 <gusa+0x10>,r0
  4004b8:       f3 61           mov     r15,r1
  4004ba:       09 00           nop
  4004bc:       fa ef           mov     #-6,r15
  4004be:       22 63           mov.l   @r2,r3
  4004c0:       01 73           add     #1,r3
  4004c2:       32 22           mov.l   r3,@r2
  4004c4:       13 6f           mov     r1,r15

R0 contains a pointer to the end of the gUSA region
R1 contains the saved stack pointer
R15 contains negative length of the gUSA region

When this region is interrupted by a signal, the kernel detects if
R15 >= -128U. If yes, the kernel rolls back PC to the beginning of the
region and restores SP by copying R1 to R15.

The problem happens if we are interrupted by a signal at address 4004c4.
R15 still holds the value -6, but the atomic value was already written by
an instruction at address 4004c2. In this situation we can't undo the
gUSA. The function unwind_gusa does nothing, the signal handler attempts
to push a signal frame to the address -6 and crashes.

This patch fixes it, so that if we are interrupted at the last instruction
in a gUSA region, we copy R1 to R15 to restore the correct stack pointer
and avoid crashing.

There's another bug: if we are interrupted in a delay slot, we save the
address of the instruction in the delay slot. We must save the address of
the previous instruction.

Cc: qemu-stable@nongnu.org
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Reviewed-by: Yoshinori Sato <ysato@users.sourcefoege.jp>
Message-Id: <b16389f7-6c62-70b7-59b3-87533c0bcc@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
2023-10-18 15:32:16 -07:00
..
cpu_loop.c Remove qemu-common.h include from most units 2022-04-06 14:31:55 +02:00
meson.build meson: linux-user 2020-08-21 06:30:38 -04:00
signal.c linux-user/sh4: Fix crashes on signal delivery 2023-10-18 15:32:16 -07:00
sockbits.h linux-user: move socket.h generic definitions to generic/sockbits.h 2018-05-25 10:10:55 +02:00
syscall.tbl linux-user: update syscall.tbl to Linux v5.13 2021-07-13 13:59:59 +02:00
syscallhdr.sh linux-user, sh4: add syscall table generation support 2020-03-20 16:02:00 +01:00
target_cpu.h linux-user: Introduce cpu_clone_regs_parent 2019-11-06 13:43:25 +01:00
target_elf.h linux-user: Move CPU type name selection to a function 2018-02-25 17:27:41 +01:00
target_errno_defs.h linux-user: Extract target errno to 'target_errno_defs.h' 2021-07-12 21:53:35 +02:00
target_fcntl.h linux-user: move generic fcntl definitions to generic/fcntl.h 2018-06-04 01:30:43 +02:00
target_flat.h linux-user: move target_flat.h to target subdirs 2023-02-03 22:55:12 +01:00
target_mman.h linux-user: Define ELF_ET_DYN_BASE in $guest/target_mman.h 2023-08-08 13:27:15 -07:00
target_prctl.h target/sh4: Implement prctl_unalign_sigbus 2022-01-06 11:40:52 +01:00
target_proc.h linux-user: Split out cpu/target_proc.h 2023-09-01 13:33:09 -07:00
target_resource.h linux-user: Move generic TARGET_RLIMIT* definitions to generic/target_resource.h 2022-02-01 08:01:38 +01:00
target_signal.h linux-user: Move target_signal.h generic definitions to generic/signal.h 2022-01-06 11:40:52 +01:00
target_structs.h linux-user: Move target_struct.h generic definitions to generic/ 2022-01-11 18:40:44 +01:00
target_syscall.h linux-user: target_syscall.h remove definition TARGET_MINSIGSTKSZ 2022-01-06 11:40:52 +01:00
termbits.h linux-user/sh4/termbits: Silence warning about TIOCSER_TEMT double definition 2022-03-31 21:27:02 +02:00