1e4c468ec7
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> (cherry picked from commit 3b894b699c9a9c064466e128c18be80a3f2113bc) Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> |
||
---|---|---|
.. | ||
aarch64 | ||
alpha | ||
arm | ||
cris | ||
generic | ||
hexagon | ||
hppa | ||
i386 | ||
include | ||
loongarch64 | ||
m68k | ||
microblaze | ||
mips | ||
mips64 | ||
nios2 | ||
openrisc | ||
ppc | ||
riscv | ||
s390x | ||
sh4 | ||
sparc | ||
x86_64 | ||
xtensa | ||
cpu_loop-common.h | ||
elfload.c | ||
errnos.c.inc | ||
exit.c | ||
fd-trans.c | ||
fd-trans.h | ||
flat.h | ||
flatload.c | ||
ioctls.h | ||
linux_loop.h | ||
linuxload.c | ||
loader.h | ||
main.c | ||
meson.build | ||
mmap.c | ||
qemu.h | ||
semihost.c | ||
signal-common.h | ||
signal.c | ||
socket.h | ||
strace.c | ||
strace.h | ||
strace.list | ||
syscall.c | ||
syscall_defs.h | ||
syscall_types.h | ||
thunk.c | ||
trace-events | ||
trace.h | ||
uaccess.c | ||
uname.c | ||
uname.h | ||
user-internals.h | ||
user-mmap.h | ||
vm86.c |