xref: /openbmc/qemu/linux-user/sh4/signal.c (revision 9f172adb35123a093aec8feb74de0e126ae2138e)
1 /*
2  *  Emulation of Linux signals
3  *
4  *  Copyright (c) 2003 Fabrice Bellard
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 #include "qemu/osdep.h"
20 #include "qemu.h"
21 #include "target_signal.h"
22 #include "signal-common.h"
23 #include "linux-user/trace.h"
24 
25 /*
26  * code and data structures from linux kernel:
27  * include/asm-sh/sigcontext.h
28  * arch/sh/kernel/signal.c
29  */
30 
31 struct target_sigcontext {
32     target_ulong  oldmask;
33 
34     /* CPU registers */
35     target_ulong  sc_gregs[16];
36     target_ulong  sc_pc;
37     target_ulong  sc_pr;
38     target_ulong  sc_sr;
39     target_ulong  sc_gbr;
40     target_ulong  sc_mach;
41     target_ulong  sc_macl;
42 
43     /* FPU registers */
44     target_ulong  sc_fpregs[16];
45     target_ulong  sc_xfpregs[16];
46     unsigned int sc_fpscr;
47     unsigned int sc_fpul;
48     unsigned int sc_ownedfp;
49 };
50 
51 struct target_sigframe
52 {
53     struct target_sigcontext sc;
54     target_ulong extramask[TARGET_NSIG_WORDS-1];
55     uint16_t retcode[3];
56 };
57 
58 
59 struct target_ucontext {
60     target_ulong tuc_flags;
61     struct target_ucontext *tuc_link;
62     target_stack_t tuc_stack;
63     struct target_sigcontext tuc_mcontext;
64     target_sigset_t tuc_sigmask;        /* mask last for extensibility */
65 };
66 
67 struct target_rt_sigframe
68 {
69     struct target_siginfo info;
70     struct target_ucontext uc;
71     uint16_t retcode[3];
72 };
73 
74 
75 #define MOVW(n)  (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
76 #define TRAP_NOARG 0xc310         /* Syscall w/no args (NR in R3) SH3/4 */
77 
78 static abi_ulong get_sigframe(struct target_sigaction *ka,
79                               unsigned long sp, size_t frame_size)
80 {
81     if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
82         sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
83     }
84 
85     return (sp - frame_size) & -8ul;
86 }
87 
88 /* Notice when we're in the middle of a gUSA region and reset.
89    Note that this will only occur for !parallel_cpus, as we will
90    translate such sequences differently in a parallel context.  */
91 static void unwind_gusa(CPUSH4State *regs)
92 {
93     /* If the stack pointer is sufficiently negative, and we haven't
94        completed the sequence, then reset to the entry to the region.  */
95     /* ??? The SH4 kernel checks for and address above 0xC0000000.
96        However, the page mappings in qemu linux-user aren't as restricted
97        and we wind up with the normal stack mapped above 0xF0000000.
98        That said, there is no reason why the kernel should be allowing
99        a gUSA region that spans 1GB.  Use a tighter check here, for what
100        can actually be enabled by the immediate move.  */
101     if (regs->gregs[15] >= -128u && regs->pc < regs->gregs[0]) {
102         /* Reset the PC to before the gUSA region, as computed from
103            R0 = region end, SP = -(region size), plus one more for the
104            insn that actually initializes SP to the region size.  */
105         regs->pc = regs->gregs[0] + regs->gregs[15] - 2;
106 
107         /* Reset the SP to the saved version in R1.  */
108         regs->gregs[15] = regs->gregs[1];
109     }
110 }
111 
112 static void setup_sigcontext(struct target_sigcontext *sc,
113                              CPUSH4State *regs, unsigned long mask)
114 {
115     int i;
116 
117 #define COPY(x)         __put_user(regs->x, &sc->sc_##x)
118     COPY(gregs[0]); COPY(gregs[1]);
119     COPY(gregs[2]); COPY(gregs[3]);
120     COPY(gregs[4]); COPY(gregs[5]);
121     COPY(gregs[6]); COPY(gregs[7]);
122     COPY(gregs[8]); COPY(gregs[9]);
123     COPY(gregs[10]); COPY(gregs[11]);
124     COPY(gregs[12]); COPY(gregs[13]);
125     COPY(gregs[14]); COPY(gregs[15]);
126     COPY(gbr); COPY(mach);
127     COPY(macl); COPY(pr);
128     COPY(sr); COPY(pc);
129 #undef COPY
130 
131     for (i=0; i<16; i++) {
132         __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
133     }
134     __put_user(regs->fpscr, &sc->sc_fpscr);
135     __put_user(regs->fpul, &sc->sc_fpul);
136 
137     /* non-iBCS2 extensions.. */
138     __put_user(mask, &sc->oldmask);
139 }
140 
141 static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc)
142 {
143     int i;
144 
145 #define COPY(x)         __get_user(regs->x, &sc->sc_##x)
146     COPY(gregs[0]); COPY(gregs[1]);
147     COPY(gregs[2]); COPY(gregs[3]);
148     COPY(gregs[4]); COPY(gregs[5]);
149     COPY(gregs[6]); COPY(gregs[7]);
150     COPY(gregs[8]); COPY(gregs[9]);
151     COPY(gregs[10]); COPY(gregs[11]);
152     COPY(gregs[12]); COPY(gregs[13]);
153     COPY(gregs[14]); COPY(gregs[15]);
154     COPY(gbr); COPY(mach);
155     COPY(macl); COPY(pr);
156     COPY(sr); COPY(pc);
157 #undef COPY
158 
159     for (i=0; i<16; i++) {
160         __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
161     }
162     __get_user(regs->fpscr, &sc->sc_fpscr);
163     __get_user(regs->fpul, &sc->sc_fpul);
164 
165     regs->tra = -1;         /* disable syscall checks */
166     regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
167 }
168 
169 void setup_frame(int sig, struct target_sigaction *ka,
170                  target_sigset_t *set, CPUSH4State *regs)
171 {
172     struct target_sigframe *frame;
173     abi_ulong frame_addr;
174     int i;
175 
176     unwind_gusa(regs);
177 
178     frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
179     trace_user_setup_frame(regs, frame_addr);
180     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
181         goto give_sigsegv;
182     }
183 
184     setup_sigcontext(&frame->sc, regs, set->sig[0]);
185 
186     for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
187         __put_user(set->sig[i + 1], &frame->extramask[i]);
188     }
189 
190     /* Set up to return from userspace.  If provided, use a stub
191        already in userspace.  */
192     if (ka->sa_flags & TARGET_SA_RESTORER) {
193         regs->pr = (unsigned long) ka->sa_restorer;
194     } else {
195         /* Generate return code (system call to sigreturn) */
196         abi_ulong retcode_addr = frame_addr +
197                                  offsetof(struct target_sigframe, retcode);
198         __put_user(MOVW(2), &frame->retcode[0]);
199         __put_user(TRAP_NOARG, &frame->retcode[1]);
200         __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
201         regs->pr = (unsigned long) retcode_addr;
202     }
203 
204     /* Set up registers for signal handler */
205     regs->gregs[15] = frame_addr;
206     regs->gregs[4] = sig; /* Arg for signal handler */
207     regs->gregs[5] = 0;
208     regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
209     regs->pc = (unsigned long) ka->_sa_handler;
210     regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
211 
212     unlock_user_struct(frame, frame_addr, 1);
213     return;
214 
215 give_sigsegv:
216     unlock_user_struct(frame, frame_addr, 1);
217     force_sigsegv(sig);
218 }
219 
220 void setup_rt_frame(int sig, struct target_sigaction *ka,
221                     target_siginfo_t *info,
222                     target_sigset_t *set, CPUSH4State *regs)
223 {
224     struct target_rt_sigframe *frame;
225     abi_ulong frame_addr;
226     int i;
227 
228     unwind_gusa(regs);
229 
230     frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
231     trace_user_setup_rt_frame(regs, frame_addr);
232     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
233         goto give_sigsegv;
234     }
235 
236     tswap_siginfo(&frame->info, info);
237 
238     /* Create the ucontext.  */
239     __put_user(0, &frame->uc.tuc_flags);
240     __put_user(0, (unsigned long *)&frame->uc.tuc_link);
241     __put_user((unsigned long)target_sigaltstack_used.ss_sp,
242                &frame->uc.tuc_stack.ss_sp);
243     __put_user(sas_ss_flags(regs->gregs[15]),
244                &frame->uc.tuc_stack.ss_flags);
245     __put_user(target_sigaltstack_used.ss_size,
246                &frame->uc.tuc_stack.ss_size);
247     setup_sigcontext(&frame->uc.tuc_mcontext,
248                      regs, set->sig[0]);
249     for(i = 0; i < TARGET_NSIG_WORDS; i++) {
250         __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
251     }
252 
253     /* Set up to return from userspace.  If provided, use a stub
254        already in userspace.  */
255     if (ka->sa_flags & TARGET_SA_RESTORER) {
256         regs->pr = (unsigned long) ka->sa_restorer;
257     } else {
258         /* Generate return code (system call to sigreturn) */
259         abi_ulong retcode_addr = frame_addr +
260                                  offsetof(struct target_rt_sigframe, retcode);
261         __put_user(MOVW(2), &frame->retcode[0]);
262         __put_user(TRAP_NOARG, &frame->retcode[1]);
263         __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
264         regs->pr = (unsigned long) retcode_addr;
265     }
266 
267     /* Set up registers for signal handler */
268     regs->gregs[15] = frame_addr;
269     regs->gregs[4] = sig; /* Arg for signal handler */
270     regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
271     regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
272     regs->pc = (unsigned long) ka->_sa_handler;
273     regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
274 
275     unlock_user_struct(frame, frame_addr, 1);
276     return;
277 
278 give_sigsegv:
279     unlock_user_struct(frame, frame_addr, 1);
280     force_sigsegv(sig);
281 }
282 
283 long do_sigreturn(CPUSH4State *regs)
284 {
285     struct target_sigframe *frame;
286     abi_ulong frame_addr;
287     sigset_t blocked;
288     target_sigset_t target_set;
289     int i;
290     int err = 0;
291 
292     frame_addr = regs->gregs[15];
293     trace_user_do_sigreturn(regs, frame_addr);
294     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
295         goto badframe;
296     }
297 
298     __get_user(target_set.sig[0], &frame->sc.oldmask);
299     for(i = 1; i < TARGET_NSIG_WORDS; i++) {
300         __get_user(target_set.sig[i], &frame->extramask[i - 1]);
301     }
302 
303     if (err)
304         goto badframe;
305 
306     target_to_host_sigset_internal(&blocked, &target_set);
307     set_sigmask(&blocked);
308 
309     restore_sigcontext(regs, &frame->sc);
310 
311     unlock_user_struct(frame, frame_addr, 0);
312     return -TARGET_QEMU_ESIGRETURN;
313 
314 badframe:
315     unlock_user_struct(frame, frame_addr, 0);
316     force_sig(TARGET_SIGSEGV);
317     return -TARGET_QEMU_ESIGRETURN;
318 }
319 
320 long do_rt_sigreturn(CPUSH4State *regs)
321 {
322     struct target_rt_sigframe *frame;
323     abi_ulong frame_addr;
324     sigset_t blocked;
325 
326     frame_addr = regs->gregs[15];
327     trace_user_do_rt_sigreturn(regs, frame_addr);
328     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
329         goto badframe;
330     }
331 
332     target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
333     set_sigmask(&blocked);
334 
335     restore_sigcontext(regs, &frame->uc.tuc_mcontext);
336 
337     if (do_sigaltstack(frame_addr +
338                        offsetof(struct target_rt_sigframe, uc.tuc_stack),
339                        0, get_sp_from_cpustate(regs)) == -EFAULT) {
340         goto badframe;
341     }
342 
343     unlock_user_struct(frame, frame_addr, 0);
344     return -TARGET_QEMU_ESIGRETURN;
345 
346 badframe:
347     unlock_user_struct(frame, frame_addr, 0);
348     force_sig(TARGET_SIGSEGV);
349     return -TARGET_QEMU_ESIGRETURN;
350 }
351