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