xref: /openbmc/qemu/linux-user/sh4/signal.c (revision 2f44bea9)
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 "user-internals.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     sp = target_sigsp(sp, ka);
82 
83     return (sp - frame_size) & -8ul;
84 }
85 
86 /*
87  * Notice when we're in the middle of a gUSA region and reset.
88  * Note that this will only occur when #CF_PARALLEL is unset, as we
89  * will translate such sequences differently in a parallel context.
90  */
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     target_save_altstack(&frame->uc.tuc_stack, regs);
242     setup_sigcontext(&frame->uc.tuc_mcontext,
243                      regs, set->sig[0]);
244     for(i = 0; i < TARGET_NSIG_WORDS; i++) {
245         __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
246     }
247 
248     /* Set up to return from userspace.  If provided, use a stub
249        already in userspace.  */
250     if (ka->sa_flags & TARGET_SA_RESTORER) {
251         regs->pr = (unsigned long) ka->sa_restorer;
252     } else {
253         /* Generate return code (system call to sigreturn) */
254         abi_ulong retcode_addr = frame_addr +
255                                  offsetof(struct target_rt_sigframe, retcode);
256         __put_user(MOVW(2), &frame->retcode[0]);
257         __put_user(TRAP_NOARG, &frame->retcode[1]);
258         __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
259         regs->pr = (unsigned long) retcode_addr;
260     }
261 
262     /* Set up registers for signal handler */
263     regs->gregs[15] = frame_addr;
264     regs->gregs[4] = sig; /* Arg for signal handler */
265     regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
266     regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
267     regs->pc = (unsigned long) ka->_sa_handler;
268     regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
269 
270     unlock_user_struct(frame, frame_addr, 1);
271     return;
272 
273 give_sigsegv:
274     unlock_user_struct(frame, frame_addr, 1);
275     force_sigsegv(sig);
276 }
277 
278 long do_sigreturn(CPUSH4State *regs)
279 {
280     struct target_sigframe *frame;
281     abi_ulong frame_addr;
282     sigset_t blocked;
283     target_sigset_t target_set;
284     int i;
285 
286     frame_addr = regs->gregs[15];
287     trace_user_do_sigreturn(regs, frame_addr);
288     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
289         goto badframe;
290     }
291 
292     __get_user(target_set.sig[0], &frame->sc.oldmask);
293     for(i = 1; i < TARGET_NSIG_WORDS; i++) {
294         __get_user(target_set.sig[i], &frame->extramask[i - 1]);
295     }
296 
297     target_to_host_sigset_internal(&blocked, &target_set);
298     set_sigmask(&blocked);
299 
300     restore_sigcontext(regs, &frame->sc);
301 
302     unlock_user_struct(frame, frame_addr, 0);
303     return -TARGET_QEMU_ESIGRETURN;
304 
305 badframe:
306     unlock_user_struct(frame, frame_addr, 0);
307     force_sig(TARGET_SIGSEGV);
308     return -TARGET_QEMU_ESIGRETURN;
309 }
310 
311 long do_rt_sigreturn(CPUSH4State *regs)
312 {
313     struct target_rt_sigframe *frame;
314     abi_ulong frame_addr;
315     sigset_t blocked;
316 
317     frame_addr = regs->gregs[15];
318     trace_user_do_rt_sigreturn(regs, frame_addr);
319     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
320         goto badframe;
321     }
322 
323     target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
324     set_sigmask(&blocked);
325 
326     restore_sigcontext(regs, &frame->uc.tuc_mcontext);
327     target_restore_altstack(&frame->uc.tuc_stack, regs);
328 
329     unlock_user_struct(frame, frame_addr, 0);
330     return -TARGET_QEMU_ESIGRETURN;
331 
332 badframe:
333     unlock_user_struct(frame, frame_addr, 0);
334     force_sig(TARGET_SIGSEGV);
335     return -TARGET_QEMU_ESIGRETURN;
336 }
337