xref: /openbmc/qemu/linux-user/sh4/signal.c (revision 89854803)
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     sp = target_sigsp(sp, ka);
82 
83     return (sp - frame_size) & -8ul;
84 }
85 
86 /* Notice when we're in the middle of a gUSA region and reset.
87    Note that this will only occur for !parallel_cpus, as we will
88    translate such sequences differently in a parallel context.  */
89 static void unwind_gusa(CPUSH4State *regs)
90 {
91     /* If the stack pointer is sufficiently negative, and we haven't
92        completed the sequence, then reset to the entry to the region.  */
93     /* ??? The SH4 kernel checks for and address above 0xC0000000.
94        However, the page mappings in qemu linux-user aren't as restricted
95        and we wind up with the normal stack mapped above 0xF0000000.
96        That said, there is no reason why the kernel should be allowing
97        a gUSA region that spans 1GB.  Use a tighter check here, for what
98        can actually be enabled by the immediate move.  */
99     if (regs->gregs[15] >= -128u && regs->pc < regs->gregs[0]) {
100         /* Reset the PC to before the gUSA region, as computed from
101            R0 = region end, SP = -(region size), plus one more for the
102            insn that actually initializes SP to the region size.  */
103         regs->pc = regs->gregs[0] + regs->gregs[15] - 2;
104 
105         /* Reset the SP to the saved version in R1.  */
106         regs->gregs[15] = regs->gregs[1];
107     }
108 }
109 
110 static void setup_sigcontext(struct target_sigcontext *sc,
111                              CPUSH4State *regs, unsigned long mask)
112 {
113     int i;
114 
115 #define COPY(x)         __put_user(regs->x, &sc->sc_##x)
116     COPY(gregs[0]); COPY(gregs[1]);
117     COPY(gregs[2]); COPY(gregs[3]);
118     COPY(gregs[4]); COPY(gregs[5]);
119     COPY(gregs[6]); COPY(gregs[7]);
120     COPY(gregs[8]); COPY(gregs[9]);
121     COPY(gregs[10]); COPY(gregs[11]);
122     COPY(gregs[12]); COPY(gregs[13]);
123     COPY(gregs[14]); COPY(gregs[15]);
124     COPY(gbr); COPY(mach);
125     COPY(macl); COPY(pr);
126     COPY(sr); COPY(pc);
127 #undef COPY
128 
129     for (i=0; i<16; i++) {
130         __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
131     }
132     __put_user(regs->fpscr, &sc->sc_fpscr);
133     __put_user(regs->fpul, &sc->sc_fpul);
134 
135     /* non-iBCS2 extensions.. */
136     __put_user(mask, &sc->oldmask);
137 }
138 
139 static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc)
140 {
141     int i;
142 
143 #define COPY(x)         __get_user(regs->x, &sc->sc_##x)
144     COPY(gregs[0]); COPY(gregs[1]);
145     COPY(gregs[2]); COPY(gregs[3]);
146     COPY(gregs[4]); COPY(gregs[5]);
147     COPY(gregs[6]); COPY(gregs[7]);
148     COPY(gregs[8]); COPY(gregs[9]);
149     COPY(gregs[10]); COPY(gregs[11]);
150     COPY(gregs[12]); COPY(gregs[13]);
151     COPY(gregs[14]); COPY(gregs[15]);
152     COPY(gbr); COPY(mach);
153     COPY(macl); COPY(pr);
154     COPY(sr); COPY(pc);
155 #undef COPY
156 
157     for (i=0; i<16; i++) {
158         __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
159     }
160     __get_user(regs->fpscr, &sc->sc_fpscr);
161     __get_user(regs->fpul, &sc->sc_fpul);
162 
163     regs->tra = -1;         /* disable syscall checks */
164     regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
165 }
166 
167 void setup_frame(int sig, struct target_sigaction *ka,
168                  target_sigset_t *set, CPUSH4State *regs)
169 {
170     struct target_sigframe *frame;
171     abi_ulong frame_addr;
172     int i;
173 
174     unwind_gusa(regs);
175 
176     frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
177     trace_user_setup_frame(regs, frame_addr);
178     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
179         goto give_sigsegv;
180     }
181 
182     setup_sigcontext(&frame->sc, regs, set->sig[0]);
183 
184     for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
185         __put_user(set->sig[i + 1], &frame->extramask[i]);
186     }
187 
188     /* Set up to return from userspace.  If provided, use a stub
189        already in userspace.  */
190     if (ka->sa_flags & TARGET_SA_RESTORER) {
191         regs->pr = (unsigned long) ka->sa_restorer;
192     } else {
193         /* Generate return code (system call to sigreturn) */
194         abi_ulong retcode_addr = frame_addr +
195                                  offsetof(struct target_sigframe, retcode);
196         __put_user(MOVW(2), &frame->retcode[0]);
197         __put_user(TRAP_NOARG, &frame->retcode[1]);
198         __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
199         regs->pr = (unsigned long) retcode_addr;
200     }
201 
202     /* Set up registers for signal handler */
203     regs->gregs[15] = frame_addr;
204     regs->gregs[4] = sig; /* Arg for signal handler */
205     regs->gregs[5] = 0;
206     regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
207     regs->pc = (unsigned long) ka->_sa_handler;
208     regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
209 
210     unlock_user_struct(frame, frame_addr, 1);
211     return;
212 
213 give_sigsegv:
214     unlock_user_struct(frame, frame_addr, 1);
215     force_sigsegv(sig);
216 }
217 
218 void setup_rt_frame(int sig, struct target_sigaction *ka,
219                     target_siginfo_t *info,
220                     target_sigset_t *set, CPUSH4State *regs)
221 {
222     struct target_rt_sigframe *frame;
223     abi_ulong frame_addr;
224     int i;
225 
226     unwind_gusa(regs);
227 
228     frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
229     trace_user_setup_rt_frame(regs, frame_addr);
230     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
231         goto give_sigsegv;
232     }
233 
234     tswap_siginfo(&frame->info, info);
235 
236     /* Create the ucontext.  */
237     __put_user(0, &frame->uc.tuc_flags);
238     __put_user(0, (unsigned long *)&frame->uc.tuc_link);
239     target_save_altstack(&frame->uc.tuc_stack, regs);
240     setup_sigcontext(&frame->uc.tuc_mcontext,
241                      regs, set->sig[0]);
242     for(i = 0; i < TARGET_NSIG_WORDS; i++) {
243         __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
244     }
245 
246     /* Set up to return from userspace.  If provided, use a stub
247        already in userspace.  */
248     if (ka->sa_flags & TARGET_SA_RESTORER) {
249         regs->pr = (unsigned long) ka->sa_restorer;
250     } else {
251         /* Generate return code (system call to sigreturn) */
252         abi_ulong retcode_addr = frame_addr +
253                                  offsetof(struct target_rt_sigframe, retcode);
254         __put_user(MOVW(2), &frame->retcode[0]);
255         __put_user(TRAP_NOARG, &frame->retcode[1]);
256         __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
257         regs->pr = (unsigned long) retcode_addr;
258     }
259 
260     /* Set up registers for signal handler */
261     regs->gregs[15] = frame_addr;
262     regs->gregs[4] = sig; /* Arg for signal handler */
263     regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
264     regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
265     regs->pc = (unsigned long) ka->_sa_handler;
266     regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
267 
268     unlock_user_struct(frame, frame_addr, 1);
269     return;
270 
271 give_sigsegv:
272     unlock_user_struct(frame, frame_addr, 1);
273     force_sigsegv(sig);
274 }
275 
276 long do_sigreturn(CPUSH4State *regs)
277 {
278     struct target_sigframe *frame;
279     abi_ulong frame_addr;
280     sigset_t blocked;
281     target_sigset_t target_set;
282     int i;
283     int err = 0;
284 
285     frame_addr = regs->gregs[15];
286     trace_user_do_sigreturn(regs, frame_addr);
287     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
288         goto badframe;
289     }
290 
291     __get_user(target_set.sig[0], &frame->sc.oldmask);
292     for(i = 1; i < TARGET_NSIG_WORDS; i++) {
293         __get_user(target_set.sig[i], &frame->extramask[i - 1]);
294     }
295 
296     if (err)
297         goto badframe;
298 
299     target_to_host_sigset_internal(&blocked, &target_set);
300     set_sigmask(&blocked);
301 
302     restore_sigcontext(regs, &frame->sc);
303 
304     unlock_user_struct(frame, frame_addr, 0);
305     return -TARGET_QEMU_ESIGRETURN;
306 
307 badframe:
308     unlock_user_struct(frame, frame_addr, 0);
309     force_sig(TARGET_SIGSEGV);
310     return -TARGET_QEMU_ESIGRETURN;
311 }
312 
313 long do_rt_sigreturn(CPUSH4State *regs)
314 {
315     struct target_rt_sigframe *frame;
316     abi_ulong frame_addr;
317     sigset_t blocked;
318 
319     frame_addr = regs->gregs[15];
320     trace_user_do_rt_sigreturn(regs, frame_addr);
321     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
322         goto badframe;
323     }
324 
325     target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
326     set_sigmask(&blocked);
327 
328     restore_sigcontext(regs, &frame->uc.tuc_mcontext);
329 
330     if (do_sigaltstack(frame_addr +
331                        offsetof(struct target_rt_sigframe, uc.tuc_stack),
332                        0, get_sp_from_cpustate(regs)) == -EFAULT) {
333         goto badframe;
334     }
335 
336     unlock_user_struct(frame, frame_addr, 0);
337     return -TARGET_QEMU_ESIGRETURN;
338 
339 badframe:
340     unlock_user_struct(frame, frame_addr, 0);
341     force_sig(TARGET_SIGSEGV);
342     return -TARGET_QEMU_ESIGRETURN;
343 }
344