1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public |
3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. |
5 | * |
6 | * Copyright (C) 1991, 1992 Linus Torvalds |
7 | * Copyright (C) 1994 - 2000, 2006 Ralf Baechle |
8 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. |
9 | * Copyright (C) 2016, Imagination Technologies Ltd. |
10 | */ |
11 | #include <linux/compiler.h> |
12 | #include <linux/errno.h> |
13 | #include <linux/signal.h> |
14 | #include <linux/sched/signal.h> |
15 | #include <linux/uaccess.h> |
16 | |
17 | #include <asm/abi.h> |
18 | #include <asm/compat-signal.h> |
19 | #include <asm/dsp.h> |
20 | #include <asm/sim.h> |
21 | #include <asm/unistd.h> |
22 | #include <asm/syscalls.h> |
23 | |
24 | #include "signal-common.h" |
25 | |
26 | /* |
27 | * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... |
28 | */ |
29 | #define __NR_O32_restart_syscall 4253 |
30 | |
31 | struct sigframe32 { |
32 | u32 sf_ass[4]; /* argument save space for o32 */ |
33 | u32 sf_pad[2]; /* Was: signal trampoline */ |
34 | struct sigcontext32 sf_sc; |
35 | compat_sigset_t sf_mask; |
36 | }; |
37 | |
38 | struct ucontext32 { |
39 | u32 uc_flags; |
40 | s32 uc_link; |
41 | compat_stack_t uc_stack; |
42 | struct sigcontext32 uc_mcontext; |
43 | compat_sigset_t uc_sigmask; /* mask last for extensibility */ |
44 | }; |
45 | |
46 | struct rt_sigframe32 { |
47 | u32 rs_ass[4]; /* argument save space for o32 */ |
48 | u32 rs_pad[2]; /* Was: signal trampoline */ |
49 | compat_siginfo_t rs_info; |
50 | struct ucontext32 rs_uc; |
51 | }; |
52 | |
53 | static int setup_sigcontext32(struct pt_regs *regs, |
54 | struct sigcontext32 __user *sc) |
55 | { |
56 | int err = 0; |
57 | int i; |
58 | |
59 | err |= __put_user(regs->cp0_epc, &sc->sc_pc); |
60 | |
61 | err |= __put_user(0, &sc->sc_regs[0]); |
62 | for (i = 1; i < 32; i++) |
63 | err |= __put_user(regs->regs[i], &sc->sc_regs[i]); |
64 | |
65 | err |= __put_user(regs->hi, &sc->sc_mdhi); |
66 | err |= __put_user(regs->lo, &sc->sc_mdlo); |
67 | if (cpu_has_dsp) { |
68 | err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); |
69 | err |= __put_user(mfhi1(), &sc->sc_hi1); |
70 | err |= __put_user(mflo1(), &sc->sc_lo1); |
71 | err |= __put_user(mfhi2(), &sc->sc_hi2); |
72 | err |= __put_user(mflo2(), &sc->sc_lo2); |
73 | err |= __put_user(mfhi3(), &sc->sc_hi3); |
74 | err |= __put_user(mflo3(), &sc->sc_lo3); |
75 | } |
76 | |
77 | /* |
78 | * Save FPU state to signal context. Signal handler |
79 | * will "inherit" current FPU state. |
80 | */ |
81 | err |= protected_save_fp_context(sc); |
82 | |
83 | return err; |
84 | } |
85 | |
86 | static int restore_sigcontext32(struct pt_regs *regs, |
87 | struct sigcontext32 __user *sc) |
88 | { |
89 | int err = 0; |
90 | s32 treg; |
91 | int i; |
92 | |
93 | /* Always make any pending restarted system calls return -EINTR */ |
94 | current->restart_block.fn = do_no_restart_syscall; |
95 | |
96 | err |= __get_user(regs->cp0_epc, &sc->sc_pc); |
97 | err |= __get_user(regs->hi, &sc->sc_mdhi); |
98 | err |= __get_user(regs->lo, &sc->sc_mdlo); |
99 | if (cpu_has_dsp) { |
100 | err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); |
101 | err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); |
102 | err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); |
103 | err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); |
104 | err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); |
105 | err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); |
106 | err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); |
107 | } |
108 | |
109 | for (i = 1; i < 32; i++) |
110 | err |= __get_user(regs->regs[i], &sc->sc_regs[i]); |
111 | |
112 | return err ?: protected_restore_fp_context(sc); |
113 | } |
114 | |
115 | static int setup_frame_32(void *sig_return, struct ksignal *ksig, |
116 | struct pt_regs *regs, sigset_t *set) |
117 | { |
118 | struct sigframe32 __user *frame; |
119 | int err = 0; |
120 | |
121 | frame = get_sigframe(ksig, regs, frame_size: sizeof(*frame)); |
122 | if (!access_ok(frame, sizeof (*frame))) |
123 | return -EFAULT; |
124 | |
125 | err |= setup_sigcontext32(regs, sc: &frame->sf_sc); |
126 | err |= __copy_conv_sigset_to_user(&frame->sf_mask, set); |
127 | |
128 | if (err) |
129 | return -EFAULT; |
130 | |
131 | /* |
132 | * Arguments to signal handler: |
133 | * |
134 | * a0 = signal number |
135 | * a1 = 0 (should be cause) |
136 | * a2 = pointer to struct sigcontext |
137 | * |
138 | * $25 and c0_epc point to the signal handler, $29 points to the |
139 | * struct sigframe. |
140 | */ |
141 | regs->regs[ 4] = ksig->sig; |
142 | regs->regs[ 5] = 0; |
143 | regs->regs[ 6] = (unsigned long) &frame->sf_sc; |
144 | regs->regs[29] = (unsigned long) frame; |
145 | regs->regs[31] = (unsigned long) sig_return; |
146 | regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler; |
147 | |
148 | DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n" , |
149 | current->comm, current->pid, |
150 | frame, regs->cp0_epc, regs->regs[31]); |
151 | |
152 | return 0; |
153 | } |
154 | |
155 | asmlinkage void sys32_rt_sigreturn(void) |
156 | { |
157 | struct rt_sigframe32 __user *frame; |
158 | struct pt_regs *regs; |
159 | sigset_t set; |
160 | int sig; |
161 | |
162 | regs = current_pt_regs(); |
163 | frame = (struct rt_sigframe32 __user *)regs->regs[29]; |
164 | if (!access_ok(frame, sizeof(*frame))) |
165 | goto badframe; |
166 | if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask)) |
167 | goto badframe; |
168 | |
169 | set_current_blocked(&set); |
170 | |
171 | sig = restore_sigcontext32(regs, sc: &frame->rs_uc.uc_mcontext); |
172 | if (sig < 0) |
173 | goto badframe; |
174 | else if (sig) |
175 | force_sig(sig); |
176 | |
177 | if (compat_restore_altstack(&frame->rs_uc.uc_stack)) |
178 | goto badframe; |
179 | |
180 | /* |
181 | * Don't let your children do this ... |
182 | */ |
183 | __asm__ __volatile__( |
184 | "move\t$29, %0\n\t" |
185 | "j\tsyscall_exit" |
186 | : /* no outputs */ |
187 | : "r" (regs)); |
188 | /* Unreached */ |
189 | |
190 | badframe: |
191 | force_sig(SIGSEGV); |
192 | } |
193 | |
194 | static int setup_rt_frame_32(void *sig_return, struct ksignal *ksig, |
195 | struct pt_regs *regs, sigset_t *set) |
196 | { |
197 | struct rt_sigframe32 __user *frame; |
198 | int err = 0; |
199 | |
200 | frame = get_sigframe(ksig, regs, frame_size: sizeof(*frame)); |
201 | if (!access_ok(frame, sizeof (*frame))) |
202 | return -EFAULT; |
203 | |
204 | /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */ |
205 | err |= copy_siginfo_to_user32(&frame->rs_info, &ksig->info); |
206 | |
207 | /* Create the ucontext. */ |
208 | err |= __put_user(0, &frame->rs_uc.uc_flags); |
209 | err |= __put_user(0, &frame->rs_uc.uc_link); |
210 | err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]); |
211 | err |= setup_sigcontext32(regs, sc: &frame->rs_uc.uc_mcontext); |
212 | err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set); |
213 | |
214 | if (err) |
215 | return -EFAULT; |
216 | |
217 | /* |
218 | * Arguments to signal handler: |
219 | * |
220 | * a0 = signal number |
221 | * a1 = 0 (should be cause) |
222 | * a2 = pointer to ucontext |
223 | * |
224 | * $25 and c0_epc point to the signal handler, $29 points to |
225 | * the struct rt_sigframe32. |
226 | */ |
227 | regs->regs[ 4] = ksig->sig; |
228 | regs->regs[ 5] = (unsigned long) &frame->rs_info; |
229 | regs->regs[ 6] = (unsigned long) &frame->rs_uc; |
230 | regs->regs[29] = (unsigned long) frame; |
231 | regs->regs[31] = (unsigned long) sig_return; |
232 | regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler; |
233 | |
234 | DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n" , |
235 | current->comm, current->pid, |
236 | frame, regs->cp0_epc, regs->regs[31]); |
237 | |
238 | return 0; |
239 | } |
240 | |
241 | /* |
242 | * o32 compatibility on 64-bit kernels, without DSP ASE |
243 | */ |
244 | struct mips_abi mips_abi_32 = { |
245 | .setup_frame = setup_frame_32, |
246 | .setup_rt_frame = setup_rt_frame_32, |
247 | .restart = __NR_O32_restart_syscall, |
248 | |
249 | .off_sc_fpregs = offsetof(struct sigcontext32, sc_fpregs), |
250 | .off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr), |
251 | .off_sc_used_math = offsetof(struct sigcontext32, sc_used_math), |
252 | |
253 | .vdso = &vdso_image_o32, |
254 | }; |
255 | |
256 | |
257 | asmlinkage void sys32_sigreturn(void) |
258 | { |
259 | struct sigframe32 __user *frame; |
260 | struct pt_regs *regs; |
261 | sigset_t blocked; |
262 | int sig; |
263 | |
264 | regs = current_pt_regs(); |
265 | frame = (struct sigframe32 __user *)regs->regs[29]; |
266 | if (!access_ok(frame, sizeof(*frame))) |
267 | goto badframe; |
268 | if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask)) |
269 | goto badframe; |
270 | |
271 | set_current_blocked(&blocked); |
272 | |
273 | sig = restore_sigcontext32(regs, sc: &frame->sf_sc); |
274 | if (sig < 0) |
275 | goto badframe; |
276 | else if (sig) |
277 | force_sig(sig); |
278 | |
279 | /* |
280 | * Don't let your children do this ... |
281 | */ |
282 | __asm__ __volatile__( |
283 | "move\t$29, %0\n\t" |
284 | "j\tsyscall_exit" |
285 | : /* no outputs */ |
286 | : "r" (regs)); |
287 | /* Unreached */ |
288 | |
289 | badframe: |
290 | force_sig(SIGSEGV); |
291 | } |
292 | |