xref: /qemu/linux-user/sh4/signal.c (revision 4d6d8a05)
1befb7447SLaurent Vivier /*
2befb7447SLaurent Vivier  *  Emulation of Linux signals
3befb7447SLaurent Vivier  *
4befb7447SLaurent Vivier  *  Copyright (c) 2003 Fabrice Bellard
5befb7447SLaurent Vivier  *
6befb7447SLaurent Vivier  *  This program is free software; you can redistribute it and/or modify
7befb7447SLaurent Vivier  *  it under the terms of the GNU General Public License as published by
8befb7447SLaurent Vivier  *  the Free Software Foundation; either version 2 of the License, or
9befb7447SLaurent Vivier  *  (at your option) any later version.
10befb7447SLaurent Vivier  *
11befb7447SLaurent Vivier  *  This program is distributed in the hope that it will be useful,
12befb7447SLaurent Vivier  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13befb7447SLaurent Vivier  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14befb7447SLaurent Vivier  *  GNU General Public License for more details.
15befb7447SLaurent Vivier  *
16befb7447SLaurent Vivier  *  You should have received a copy of the GNU General Public License
17befb7447SLaurent Vivier  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18befb7447SLaurent Vivier  */
190f22162aSLaurent Vivier #include "qemu/osdep.h"
200f22162aSLaurent Vivier #include "qemu.h"
213b249d26SPeter Maydell #include "user-internals.h"
220f22162aSLaurent Vivier #include "signal-common.h"
230f22162aSLaurent Vivier #include "linux-user/trace.h"
240f22162aSLaurent Vivier 
250f22162aSLaurent Vivier /*
260f22162aSLaurent Vivier  * code and data structures from linux kernel:
270f22162aSLaurent Vivier  * include/asm-sh/sigcontext.h
280f22162aSLaurent Vivier  * arch/sh/kernel/signal.c
290f22162aSLaurent Vivier  */
300f22162aSLaurent Vivier 
310f22162aSLaurent Vivier struct target_sigcontext {
320f22162aSLaurent Vivier     target_ulong  oldmask;
330f22162aSLaurent Vivier 
340f22162aSLaurent Vivier     /* CPU registers */
350f22162aSLaurent Vivier     target_ulong  sc_gregs[16];
360f22162aSLaurent Vivier     target_ulong  sc_pc;
370f22162aSLaurent Vivier     target_ulong  sc_pr;
380f22162aSLaurent Vivier     target_ulong  sc_sr;
390f22162aSLaurent Vivier     target_ulong  sc_gbr;
400f22162aSLaurent Vivier     target_ulong  sc_mach;
410f22162aSLaurent Vivier     target_ulong  sc_macl;
420f22162aSLaurent Vivier 
430f22162aSLaurent Vivier     /* FPU registers */
440f22162aSLaurent Vivier     target_ulong  sc_fpregs[16];
450f22162aSLaurent Vivier     target_ulong  sc_xfpregs[16];
460f22162aSLaurent Vivier     unsigned int sc_fpscr;
470f22162aSLaurent Vivier     unsigned int sc_fpul;
480f22162aSLaurent Vivier     unsigned int sc_ownedfp;
490f22162aSLaurent Vivier };
500f22162aSLaurent Vivier 
510f22162aSLaurent Vivier struct target_sigframe
520f22162aSLaurent Vivier {
530f22162aSLaurent Vivier     struct target_sigcontext sc;
540f22162aSLaurent Vivier     target_ulong extramask[TARGET_NSIG_WORDS-1];
550f22162aSLaurent Vivier };
560f22162aSLaurent Vivier 
570f22162aSLaurent Vivier 
580f22162aSLaurent Vivier struct target_ucontext {
590f22162aSLaurent Vivier     target_ulong tuc_flags;
600f22162aSLaurent Vivier     struct target_ucontext *tuc_link;
610f22162aSLaurent Vivier     target_stack_t tuc_stack;
620f22162aSLaurent Vivier     struct target_sigcontext tuc_mcontext;
630f22162aSLaurent Vivier     target_sigset_t tuc_sigmask;        /* mask last for extensibility */
640f22162aSLaurent Vivier };
650f22162aSLaurent Vivier 
660f22162aSLaurent Vivier struct target_rt_sigframe
670f22162aSLaurent Vivier {
680f22162aSLaurent Vivier     struct target_siginfo info;
690f22162aSLaurent Vivier     struct target_ucontext uc;
700f22162aSLaurent Vivier };
710f22162aSLaurent Vivier 
720f22162aSLaurent Vivier 
730f22162aSLaurent Vivier #define MOVW(n)  (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
740f22162aSLaurent Vivier #define TRAP_NOARG 0xc310         /* Syscall w/no args (NR in R3) SH3/4 */
750f22162aSLaurent Vivier 
get_sigframe(struct target_sigaction * ka,unsigned long sp,size_t frame_size)760f22162aSLaurent Vivier static abi_ulong get_sigframe(struct target_sigaction *ka,
770f22162aSLaurent Vivier                               unsigned long sp, size_t frame_size)
780f22162aSLaurent Vivier {
79465e237bSLaurent Vivier     sp = target_sigsp(sp, ka);
800f22162aSLaurent Vivier 
810f22162aSLaurent Vivier     return (sp - frame_size) & -8ul;
820f22162aSLaurent Vivier }
830f22162aSLaurent Vivier 
846cc9d67cSRichard Henderson /*
856cc9d67cSRichard Henderson  * Notice when we're in the middle of a gUSA region and reset.
866cc9d67cSRichard Henderson  * Note that this will only occur when #CF_PARALLEL is unset, as we
876cc9d67cSRichard Henderson  * will translate such sequences differently in a parallel context.
886cc9d67cSRichard Henderson  */
unwind_gusa(CPUSH4State * regs)890f22162aSLaurent Vivier static void unwind_gusa(CPUSH4State *regs)
900f22162aSLaurent Vivier {
910f22162aSLaurent Vivier     /* If the stack pointer is sufficiently negative, and we haven't
920f22162aSLaurent Vivier        completed the sequence, then reset to the entry to the region.  */
930f22162aSLaurent Vivier     /* ??? The SH4 kernel checks for and address above 0xC0000000.
940f22162aSLaurent Vivier        However, the page mappings in qemu linux-user aren't as restricted
950f22162aSLaurent Vivier        and we wind up with the normal stack mapped above 0xF0000000.
960f22162aSLaurent Vivier        That said, there is no reason why the kernel should be allowing
970f22162aSLaurent Vivier        a gUSA region that spans 1GB.  Use a tighter check here, for what
980f22162aSLaurent Vivier        can actually be enabled by the immediate move.  */
990f22162aSLaurent Vivier     if (regs->gregs[15] >= -128u && regs->pc < regs->gregs[0]) {
1000f22162aSLaurent Vivier         /* Reset the PC to before the gUSA region, as computed from
1010f22162aSLaurent Vivier            R0 = region end, SP = -(region size), plus one more for the
1020f22162aSLaurent Vivier            insn that actually initializes SP to the region size.  */
1030f22162aSLaurent Vivier         regs->pc = regs->gregs[0] + regs->gregs[15] - 2;
1040f22162aSLaurent Vivier 
1050f22162aSLaurent Vivier         /* Reset the SP to the saved version in R1.  */
1060f22162aSLaurent Vivier         regs->gregs[15] = regs->gregs[1];
1073b894b69SMikulas Patocka     } else if (regs->gregs[15] >= -128u && regs->pc == regs->gregs[0]) {
1083b894b69SMikulas Patocka         /* If we are on the last instruction of a gUSA region, we must reset
1093b894b69SMikulas Patocka            the SP, otherwise we would be pushing the signal context to
1103b894b69SMikulas Patocka            invalid memory.  */
1113b894b69SMikulas Patocka         regs->gregs[15] = regs->gregs[1];
1123b894b69SMikulas Patocka     } else if (regs->flags & TB_FLAG_DELAY_SLOT) {
1133b894b69SMikulas Patocka         /* If we are in a delay slot, push the previous instruction.  */
1143b894b69SMikulas Patocka         regs->pc -= 2;
1150f22162aSLaurent Vivier     }
1160f22162aSLaurent Vivier }
1170f22162aSLaurent Vivier 
setup_sigcontext(struct target_sigcontext * sc,CPUSH4State * regs,unsigned long mask)1180f22162aSLaurent Vivier static void setup_sigcontext(struct target_sigcontext *sc,
1190f22162aSLaurent Vivier                              CPUSH4State *regs, unsigned long mask)
1200f22162aSLaurent Vivier {
1210f22162aSLaurent Vivier     int i;
1220f22162aSLaurent Vivier 
1230f22162aSLaurent Vivier #define COPY(x)         __put_user(regs->x, &sc->sc_##x)
1240f22162aSLaurent Vivier     COPY(gregs[0]); COPY(gregs[1]);
1250f22162aSLaurent Vivier     COPY(gregs[2]); COPY(gregs[3]);
1260f22162aSLaurent Vivier     COPY(gregs[4]); COPY(gregs[5]);
1270f22162aSLaurent Vivier     COPY(gregs[6]); COPY(gregs[7]);
1280f22162aSLaurent Vivier     COPY(gregs[8]); COPY(gregs[9]);
1290f22162aSLaurent Vivier     COPY(gregs[10]); COPY(gregs[11]);
1300f22162aSLaurent Vivier     COPY(gregs[12]); COPY(gregs[13]);
1310f22162aSLaurent Vivier     COPY(gregs[14]); COPY(gregs[15]);
1320f22162aSLaurent Vivier     COPY(gbr); COPY(mach);
1330f22162aSLaurent Vivier     COPY(macl); COPY(pr);
1340f22162aSLaurent Vivier     COPY(sr); COPY(pc);
1350f22162aSLaurent Vivier #undef COPY
1360f22162aSLaurent Vivier 
1370f22162aSLaurent Vivier     for (i=0; i<16; i++) {
1380f22162aSLaurent Vivier         __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
1390f22162aSLaurent Vivier     }
1400f22162aSLaurent Vivier     __put_user(regs->fpscr, &sc->sc_fpscr);
1410f22162aSLaurent Vivier     __put_user(regs->fpul, &sc->sc_fpul);
1420f22162aSLaurent Vivier 
1430f22162aSLaurent Vivier     /* non-iBCS2 extensions.. */
1440f22162aSLaurent Vivier     __put_user(mask, &sc->oldmask);
1450f22162aSLaurent Vivier }
1460f22162aSLaurent Vivier 
restore_sigcontext(CPUSH4State * regs,struct target_sigcontext * sc)1470f22162aSLaurent Vivier static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc)
1480f22162aSLaurent Vivier {
1490f22162aSLaurent Vivier     int i;
1500f22162aSLaurent Vivier 
1510f22162aSLaurent Vivier #define COPY(x)         __get_user(regs->x, &sc->sc_##x)
1520f22162aSLaurent Vivier     COPY(gregs[0]); COPY(gregs[1]);
1530f22162aSLaurent Vivier     COPY(gregs[2]); COPY(gregs[3]);
1540f22162aSLaurent Vivier     COPY(gregs[4]); COPY(gregs[5]);
1550f22162aSLaurent Vivier     COPY(gregs[6]); COPY(gregs[7]);
1560f22162aSLaurent Vivier     COPY(gregs[8]); COPY(gregs[9]);
1570f22162aSLaurent Vivier     COPY(gregs[10]); COPY(gregs[11]);
1580f22162aSLaurent Vivier     COPY(gregs[12]); COPY(gregs[13]);
1590f22162aSLaurent Vivier     COPY(gregs[14]); COPY(gregs[15]);
1600f22162aSLaurent Vivier     COPY(gbr); COPY(mach);
1610f22162aSLaurent Vivier     COPY(macl); COPY(pr);
1620f22162aSLaurent Vivier     COPY(sr); COPY(pc);
1630f22162aSLaurent Vivier #undef COPY
1640f22162aSLaurent Vivier 
1650f22162aSLaurent Vivier     for (i=0; i<16; i++) {
1660f22162aSLaurent Vivier         __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
1670f22162aSLaurent Vivier     }
1680f22162aSLaurent Vivier     __get_user(regs->fpscr, &sc->sc_fpscr);
1690f22162aSLaurent Vivier     __get_user(regs->fpul, &sc->sc_fpul);
1700f22162aSLaurent Vivier 
1710f22162aSLaurent Vivier     regs->tra = -1;         /* disable syscall checks */
172ab419fd8SRichard Henderson     regs->flags = 0;
1730f22162aSLaurent Vivier }
1740f22162aSLaurent Vivier 
setup_frame(int sig,struct target_sigaction * ka,target_sigset_t * set,CPUSH4State * regs)1750f22162aSLaurent Vivier void setup_frame(int sig, struct target_sigaction *ka,
1760f22162aSLaurent Vivier                  target_sigset_t *set, CPUSH4State *regs)
1770f22162aSLaurent Vivier {
1780f22162aSLaurent Vivier     struct target_sigframe *frame;
1790f22162aSLaurent Vivier     abi_ulong frame_addr;
1800f22162aSLaurent Vivier     int i;
1810f22162aSLaurent Vivier 
1820f22162aSLaurent Vivier     unwind_gusa(regs);
1830f22162aSLaurent Vivier 
1840f22162aSLaurent Vivier     frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
1850f22162aSLaurent Vivier     trace_user_setup_frame(regs, frame_addr);
1860f22162aSLaurent Vivier     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1870f22162aSLaurent Vivier         goto give_sigsegv;
1880f22162aSLaurent Vivier     }
1890f22162aSLaurent Vivier 
1900f22162aSLaurent Vivier     setup_sigcontext(&frame->sc, regs, set->sig[0]);
1910f22162aSLaurent Vivier 
1920f22162aSLaurent Vivier     for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
1930f22162aSLaurent Vivier         __put_user(set->sig[i + 1], &frame->extramask[i]);
1940f22162aSLaurent Vivier     }
1950f22162aSLaurent Vivier 
1960f22162aSLaurent Vivier     /* Set up to return from userspace.  If provided, use a stub
1970f22162aSLaurent Vivier        already in userspace.  */
1980f22162aSLaurent Vivier     if (ka->sa_flags & TARGET_SA_RESTORER) {
199b9188f9cSRichard Henderson         regs->pr = ka->sa_restorer;
2000f22162aSLaurent Vivier     } else {
201b9188f9cSRichard Henderson         regs->pr = default_sigreturn;
2020f22162aSLaurent Vivier     }
2030f22162aSLaurent Vivier 
2040f22162aSLaurent Vivier     /* Set up registers for signal handler */
2050f22162aSLaurent Vivier     regs->gregs[15] = frame_addr;
2060f22162aSLaurent Vivier     regs->gregs[4] = sig; /* Arg for signal handler */
2070f22162aSLaurent Vivier     regs->gregs[5] = 0;
2080f22162aSLaurent Vivier     regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
2090f22162aSLaurent Vivier     regs->pc = (unsigned long) ka->_sa_handler;
210ab419fd8SRichard Henderson     regs->flags &= ~(TB_FLAG_DELAY_SLOT_MASK | TB_FLAG_GUSA_MASK);
2110f22162aSLaurent Vivier 
2120f22162aSLaurent Vivier     unlock_user_struct(frame, frame_addr, 1);
2130f22162aSLaurent Vivier     return;
2140f22162aSLaurent Vivier 
2150f22162aSLaurent Vivier give_sigsegv:
2160f22162aSLaurent Vivier     unlock_user_struct(frame, frame_addr, 1);
2170f22162aSLaurent Vivier     force_sigsegv(sig);
2180f22162aSLaurent Vivier }
2190f22162aSLaurent Vivier 
setup_rt_frame(int sig,struct target_sigaction * ka,target_siginfo_t * info,target_sigset_t * set,CPUSH4State * regs)2200f22162aSLaurent Vivier void setup_rt_frame(int sig, struct target_sigaction *ka,
2210f22162aSLaurent Vivier                     target_siginfo_t *info,
2220f22162aSLaurent Vivier                     target_sigset_t *set, CPUSH4State *regs)
2230f22162aSLaurent Vivier {
2240f22162aSLaurent Vivier     struct target_rt_sigframe *frame;
2250f22162aSLaurent Vivier     abi_ulong frame_addr;
2260f22162aSLaurent Vivier     int i;
2270f22162aSLaurent Vivier 
2280f22162aSLaurent Vivier     unwind_gusa(regs);
2290f22162aSLaurent Vivier 
2300f22162aSLaurent Vivier     frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
2310f22162aSLaurent Vivier     trace_user_setup_rt_frame(regs, frame_addr);
2320f22162aSLaurent Vivier     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
2330f22162aSLaurent Vivier         goto give_sigsegv;
2340f22162aSLaurent Vivier     }
2350f22162aSLaurent Vivier 
2364d6d8a05SGustavo Romero     frame->info = *info;
2370f22162aSLaurent Vivier 
2380f22162aSLaurent Vivier     /* Create the ucontext.  */
2390f22162aSLaurent Vivier     __put_user(0, &frame->uc.tuc_flags);
2400f22162aSLaurent Vivier     __put_user(0, (unsigned long *)&frame->uc.tuc_link);
241465e237bSLaurent Vivier     target_save_altstack(&frame->uc.tuc_stack, regs);
2420f22162aSLaurent Vivier     setup_sigcontext(&frame->uc.tuc_mcontext,
2430f22162aSLaurent Vivier                      regs, set->sig[0]);
2440f22162aSLaurent Vivier     for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2450f22162aSLaurent Vivier         __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
2460f22162aSLaurent Vivier     }
2470f22162aSLaurent Vivier 
2480f22162aSLaurent Vivier     /* Set up to return from userspace.  If provided, use a stub
2490f22162aSLaurent Vivier        already in userspace.  */
2500f22162aSLaurent Vivier     if (ka->sa_flags & TARGET_SA_RESTORER) {
251b9188f9cSRichard Henderson         regs->pr = ka->sa_restorer;
2520f22162aSLaurent Vivier     } else {
253b9188f9cSRichard Henderson         regs->pr = default_rt_sigreturn;
2540f22162aSLaurent Vivier     }
2550f22162aSLaurent Vivier 
2560f22162aSLaurent Vivier     /* Set up registers for signal handler */
2570f22162aSLaurent Vivier     regs->gregs[15] = frame_addr;
2580f22162aSLaurent Vivier     regs->gregs[4] = sig; /* Arg for signal handler */
2590f22162aSLaurent Vivier     regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
2600f22162aSLaurent Vivier     regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
2610f22162aSLaurent Vivier     regs->pc = (unsigned long) ka->_sa_handler;
262ab419fd8SRichard Henderson     regs->flags &= ~(TB_FLAG_DELAY_SLOT_MASK | TB_FLAG_GUSA_MASK);
2630f22162aSLaurent Vivier 
2640f22162aSLaurent Vivier     unlock_user_struct(frame, frame_addr, 1);
2650f22162aSLaurent Vivier     return;
2660f22162aSLaurent Vivier 
2670f22162aSLaurent Vivier give_sigsegv:
2680f22162aSLaurent Vivier     unlock_user_struct(frame, frame_addr, 1);
2690f22162aSLaurent Vivier     force_sigsegv(sig);
2700f22162aSLaurent Vivier }
2710f22162aSLaurent Vivier 
do_sigreturn(CPUSH4State * regs)2720f22162aSLaurent Vivier long do_sigreturn(CPUSH4State *regs)
2730f22162aSLaurent Vivier {
2740f22162aSLaurent Vivier     struct target_sigframe *frame;
2750f22162aSLaurent Vivier     abi_ulong frame_addr;
2760f22162aSLaurent Vivier     sigset_t blocked;
2770f22162aSLaurent Vivier     target_sigset_t target_set;
2780f22162aSLaurent Vivier     int i;
2790f22162aSLaurent Vivier 
2800f22162aSLaurent Vivier     frame_addr = regs->gregs[15];
2810f22162aSLaurent Vivier     trace_user_do_sigreturn(regs, frame_addr);
2820f22162aSLaurent Vivier     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2830f22162aSLaurent Vivier         goto badframe;
2840f22162aSLaurent Vivier     }
2850f22162aSLaurent Vivier 
2860f22162aSLaurent Vivier     __get_user(target_set.sig[0], &frame->sc.oldmask);
2870f22162aSLaurent Vivier     for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2880f22162aSLaurent Vivier         __get_user(target_set.sig[i], &frame->extramask[i - 1]);
2890f22162aSLaurent Vivier     }
2900f22162aSLaurent Vivier 
2910f22162aSLaurent Vivier     target_to_host_sigset_internal(&blocked, &target_set);
2920f22162aSLaurent Vivier     set_sigmask(&blocked);
2930f22162aSLaurent Vivier 
2940f22162aSLaurent Vivier     restore_sigcontext(regs, &frame->sc);
2950f22162aSLaurent Vivier 
2960f22162aSLaurent Vivier     unlock_user_struct(frame, frame_addr, 0);
29757a0c938SRichard Henderson     return -QEMU_ESIGRETURN;
2980f22162aSLaurent Vivier 
2990f22162aSLaurent Vivier badframe:
3000f22162aSLaurent Vivier     unlock_user_struct(frame, frame_addr, 0);
3010f22162aSLaurent Vivier     force_sig(TARGET_SIGSEGV);
30257a0c938SRichard Henderson     return -QEMU_ESIGRETURN;
3030f22162aSLaurent Vivier }
3040f22162aSLaurent Vivier 
do_rt_sigreturn(CPUSH4State * regs)3050f22162aSLaurent Vivier long do_rt_sigreturn(CPUSH4State *regs)
3060f22162aSLaurent Vivier {
3070f22162aSLaurent Vivier     struct target_rt_sigframe *frame;
3080f22162aSLaurent Vivier     abi_ulong frame_addr;
3090f22162aSLaurent Vivier     sigset_t blocked;
3100f22162aSLaurent Vivier 
3110f22162aSLaurent Vivier     frame_addr = regs->gregs[15];
3120f22162aSLaurent Vivier     trace_user_do_rt_sigreturn(regs, frame_addr);
3130f22162aSLaurent Vivier     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3140f22162aSLaurent Vivier         goto badframe;
3150f22162aSLaurent Vivier     }
3160f22162aSLaurent Vivier 
3170f22162aSLaurent Vivier     target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
3180f22162aSLaurent Vivier     set_sigmask(&blocked);
3190f22162aSLaurent Vivier 
3200f22162aSLaurent Vivier     restore_sigcontext(regs, &frame->uc.tuc_mcontext);
321ddc3e74dSRichard Henderson     target_restore_altstack(&frame->uc.tuc_stack, regs);
3220f22162aSLaurent Vivier 
3230f22162aSLaurent Vivier     unlock_user_struct(frame, frame_addr, 0);
32457a0c938SRichard Henderson     return -QEMU_ESIGRETURN;
3250f22162aSLaurent Vivier 
3260f22162aSLaurent Vivier badframe:
3270f22162aSLaurent Vivier     unlock_user_struct(frame, frame_addr, 0);
3280f22162aSLaurent Vivier     force_sig(TARGET_SIGSEGV);
32957a0c938SRichard Henderson     return -QEMU_ESIGRETURN;
3300f22162aSLaurent Vivier }
331b9188f9cSRichard Henderson 
setup_sigtramp(abi_ulong sigtramp_page)332b9188f9cSRichard Henderson void setup_sigtramp(abi_ulong sigtramp_page)
333b9188f9cSRichard Henderson {
334b9188f9cSRichard Henderson     uint16_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 6, 0);
335b9188f9cSRichard Henderson     assert(tramp != NULL);
336b9188f9cSRichard Henderson 
337b9188f9cSRichard Henderson     default_sigreturn = sigtramp_page;
338b9188f9cSRichard Henderson     __put_user(MOVW(2), &tramp[0]);
339b9188f9cSRichard Henderson     __put_user(TRAP_NOARG, &tramp[1]);
340b9188f9cSRichard Henderson     __put_user(TARGET_NR_sigreturn, &tramp[2]);
341b9188f9cSRichard Henderson 
342b9188f9cSRichard Henderson     default_rt_sigreturn = sigtramp_page + 6;
343b9188f9cSRichard Henderson     __put_user(MOVW(2), &tramp[3]);
344b9188f9cSRichard Henderson     __put_user(TRAP_NOARG, &tramp[4]);
345b9188f9cSRichard Henderson     __put_user(TARGET_NR_rt_sigreturn, &tramp[5]);
346b9188f9cSRichard Henderson 
347b9188f9cSRichard Henderson     unlock_user(tramp, sigtramp_page, 2 * 6);
348b9188f9cSRichard Henderson }
349