Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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: [email protected] Signed-off-by: Mikulas Patocka <[email protected]> Reviewed-by: Yoshinori Sato <[email protected]> Message-Id: <[email protected]> Reviewed-by: Richard Henderson <[email protected]> Signed-off-by: Richard Henderson <[email protected]> (cherry picked from commit 3b894b6) Signed-off-by: Michael Tokarev <[email protected]>
- Loading branch information