blob: 7769f9333e0c455248ac923408c76993925dbc93 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* Signal support for 32-bit kernel builds
2 *
3 * Copyright (C) 2001 Matthew Wilcox <willy at parisc-linux.org>
Kyle McMartind104f112007-02-08 19:38:54 -05004 * Copyright (C) 2006 Kyle McMartin <kyle at parisc-linux.org>
5 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * Code was mostly borrowed from kernel/signal.c.
7 * See kernel/signal.c for additional Copyrights.
8 *
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24
25#include <linux/compat.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/module.h>
27#include <linux/unistd.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/init.h>
29#include <linux/sched.h>
30#include <linux/syscalls.h>
31#include <linux/types.h>
32#include <linux/errno.h>
33
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <asm/uaccess.h>
35
36#include "signal32.h"
37#include "sys32.h"
38
39#define DEBUG_COMPAT_SIG 0
40#define DEBUG_COMPAT_SIG_LEVEL 2
41
42#if DEBUG_COMPAT_SIG
43#define DBG(LEVEL, ...) \
44 ((DEBUG_COMPAT_SIG_LEVEL >= LEVEL) \
45 ? printk(__VA_ARGS__) : (void) 0)
46#else
47#define DBG(LEVEL, ...)
48#endif
49
Linus Torvalds1da177e2005-04-16 15:20:36 -070050inline void
51sigset_32to64(sigset_t *s64, compat_sigset_t *s32)
52{
53 s64->sig[0] = s32->sig[0] | ((unsigned long)s32->sig[1] << 32);
54}
55
56inline void
57sigset_64to32(compat_sigset_t *s32, sigset_t *s64)
58{
59 s32->sig[0] = s64->sig[0] & 0xffffffffUL;
60 s32->sig[1] = (s64->sig[0] >> 32) & 0xffffffffUL;
61}
62
Linus Torvalds1da177e2005-04-16 15:20:36 -070063long
64sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, struct sigaction32 __user *oact,
65 size_t sigsetsize)
66{
67 struct k_sigaction32 new_sa32, old_sa32;
68 struct k_sigaction new_sa, old_sa;
69 int ret = -EINVAL;
70
71 if (act) {
72 if (copy_from_user(&new_sa32.sa, act, sizeof new_sa32.sa))
73 return -EFAULT;
74 new_sa.sa.sa_handler = (__sighandler_t)(unsigned long)new_sa32.sa.sa_handler;
75 new_sa.sa.sa_flags = new_sa32.sa.sa_flags;
76 sigset_32to64(&new_sa.sa.sa_mask, &new_sa32.sa.sa_mask);
77 }
78
79 ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
80
81 if (!ret && oact) {
82 sigset_64to32(&old_sa32.sa.sa_mask, &old_sa.sa.sa_mask);
83 old_sa32.sa.sa_flags = old_sa.sa.sa_flags;
84 old_sa32.sa.sa_handler = (__sighandler_t32)(unsigned long)old_sa.sa.sa_handler;
85 if (copy_to_user(oact, &old_sa32.sa, sizeof old_sa32.sa))
86 return -EFAULT;
87 }
88 return ret;
89}
90
Linus Torvalds1da177e2005-04-16 15:20:36 -070091long
92restore_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf,
93 struct pt_regs *regs)
94{
95 long err = 0;
96 compat_uint_t compat_reg;
97 compat_uint_t compat_regt;
98 int regn;
99
100 /* When loading 32-bit values into 64-bit registers make
101 sure to clear the upper 32-bits */
102 DBG(2,"restore_sigcontext32: PER_LINUX32 process\n");
103 DBG(2,"restore_sigcontext32: sc = 0x%p, rf = 0x%p, regs = 0x%p\n", sc, rf, regs);
104 DBG(2,"restore_sigcontext32: compat_sigcontext is %#lx bytes\n", sizeof(*sc));
105 for(regn=0; regn < 32; regn++){
106 err |= __get_user(compat_reg,&sc->sc_gr[regn]);
107 regs->gr[regn] = compat_reg;
108 /* Load upper half */
109 err |= __get_user(compat_regt,&rf->rf_gr[regn]);
110 regs->gr[regn] = ((u64)compat_regt << 32) | (u64)compat_reg;
111 DBG(3,"restore_sigcontext32: gr%02d = %#lx (%#x / %#x)\n",
112 regn, regs->gr[regn], compat_regt, compat_reg);
113 }
114 DBG(2,"restore_sigcontext32: sc->sc_fr = 0x%p (%#lx)\n",sc->sc_fr, sizeof(sc->sc_fr));
115 /* XXX: BE WARNED FR's are 64-BIT! */
116 err |= __copy_from_user(regs->fr, sc->sc_fr, sizeof(regs->fr));
117
118 /* Better safe than sorry, pass __get_user two things of
119 the same size and let gcc do the upward conversion to
120 64-bits */
121 err |= __get_user(compat_reg, &sc->sc_iaoq[0]);
122 /* Load upper half */
123 err |= __get_user(compat_regt, &rf->rf_iaoq[0]);
124 regs->iaoq[0] = ((u64)compat_regt << 32) | (u64)compat_reg;
125 DBG(2,"restore_sigcontext32: upper half of iaoq[0] = %#lx\n", compat_regt);
126 DBG(2,"restore_sigcontext32: sc->sc_iaoq[0] = %p => %#x\n",
127 &sc->sc_iaoq[0], compat_reg);
128
129 err |= __get_user(compat_reg, &sc->sc_iaoq[1]);
130 /* Load upper half */
131 err |= __get_user(compat_regt, &rf->rf_iaoq[1]);
132 regs->iaoq[1] = ((u64)compat_regt << 32) | (u64)compat_reg;
133 DBG(2,"restore_sigcontext32: upper half of iaoq[1] = %#lx\n", compat_regt);
134 DBG(2,"restore_sigcontext32: sc->sc_iaoq[1] = %p => %#x\n",
135 &sc->sc_iaoq[1],compat_reg);
136 DBG(2,"restore_sigcontext32: iaoq is %#lx / %#lx\n",
137 regs->iaoq[0],regs->iaoq[1]);
138
139 err |= __get_user(compat_reg, &sc->sc_iasq[0]);
140 /* Load the upper half for iasq */
141 err |= __get_user(compat_regt, &rf->rf_iasq[0]);
142 regs->iasq[0] = ((u64)compat_regt << 32) | (u64)compat_reg;
143 DBG(2,"restore_sigcontext32: upper half of iasq[0] = %#lx\n", compat_regt);
144
145 err |= __get_user(compat_reg, &sc->sc_iasq[1]);
146 /* Load the upper half for iasq */
147 err |= __get_user(compat_regt, &rf->rf_iasq[1]);
148 regs->iasq[1] = ((u64)compat_regt << 32) | (u64)compat_reg;
149 DBG(2,"restore_sigcontext32: upper half of iasq[1] = %#lx\n", compat_regt);
150 DBG(2,"restore_sigcontext32: iasq is %#lx / %#lx\n",
151 regs->iasq[0],regs->iasq[1]);
152
153 err |= __get_user(compat_reg, &sc->sc_sar);
154 /* Load the upper half for sar */
155 err |= __get_user(compat_regt, &rf->rf_sar);
156 regs->sar = ((u64)compat_regt << 32) | (u64)compat_reg;
157 DBG(2,"restore_sigcontext32: upper_half & sar = %#lx\n", compat_regt);
158 DBG(2,"restore_sigcontext32: sar is %#lx\n", regs->sar);
159 DBG(2,"restore_sigcontext32: r28 is %ld\n", regs->gr[28]);
160
161 return err;
162}
163
164/*
165 * Set up the sigcontext structure for this process.
166 * This is not an easy task if the kernel is 64-bit, it will require
167 * that we examine the process personality to determine if we need to
168 * truncate for a 32-bit userspace.
169 */
170long
171setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf,
172 struct pt_regs *regs, int in_syscall)
173{
174 compat_int_t flags = 0;
175 long err = 0;
176 compat_uint_t compat_reg;
177 compat_uint_t compat_regb;
178 int regn;
179
180 if (on_sig_stack((unsigned long) sc))
181 flags |= PARISC_SC_FLAG_ONSTACK;
182
183 if (in_syscall) {
184
185 DBG(1,"setup_sigcontext32: in_syscall\n");
186
187 flags |= PARISC_SC_FLAG_IN_SYSCALL;
188 /* Truncate gr31 */
189 compat_reg = (compat_uint_t)(regs->gr[31]);
190 /* regs->iaoq is undefined in the syscall return path */
191 err |= __put_user(compat_reg, &sc->sc_iaoq[0]);
192 DBG(2,"setup_sigcontext32: sc->sc_iaoq[0] = %p <= %#x\n",
193 &sc->sc_iaoq[0], compat_reg);
194
195 /* Store upper half */
Kyle McMartinf4441b62008-05-27 01:56:29 -0400196 compat_reg = (compat_uint_t)(regs->gr[31] >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 err |= __put_user(compat_reg, &rf->rf_iaoq[0]);
198 DBG(2,"setup_sigcontext32: upper half iaoq[0] = %#x\n", compat_reg);
199
200
201 compat_reg = (compat_uint_t)(regs->gr[31]+4);
202 err |= __put_user(compat_reg, &sc->sc_iaoq[1]);
203 DBG(2,"setup_sigcontext32: sc->sc_iaoq[1] = %p <= %#x\n",
204 &sc->sc_iaoq[1], compat_reg);
205 /* Store upper half */
Kyle McMartinf4441b62008-05-27 01:56:29 -0400206 compat_reg = (compat_uint_t)((regs->gr[31]+4) >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 err |= __put_user(compat_reg, &rf->rf_iaoq[1]);
208 DBG(2,"setup_sigcontext32: upper half iaoq[1] = %#x\n", compat_reg);
209
210 /* Truncate sr3 */
211 compat_reg = (compat_uint_t)(regs->sr[3]);
212 err |= __put_user(compat_reg, &sc->sc_iasq[0]);
213 err |= __put_user(compat_reg, &sc->sc_iasq[1]);
214
215 /* Store upper half */
216 compat_reg = (compat_uint_t)(regs->sr[3] >> 32);
217 err |= __put_user(compat_reg, &rf->rf_iasq[0]);
218 err |= __put_user(compat_reg, &rf->rf_iasq[1]);
219
220 DBG(2,"setup_sigcontext32: upper half iasq[0] = %#x\n", compat_reg);
221 DBG(2,"setup_sigcontext32: upper half iasq[1] = %#x\n", compat_reg);
222 DBG(1,"setup_sigcontext32: iaoq %#lx / %#lx\n",
223 regs->gr[31], regs->gr[31]+4);
224
225 } else {
226
227 compat_reg = (compat_uint_t)(regs->iaoq[0]);
228 err |= __put_user(compat_reg, &sc->sc_iaoq[0]);
229 DBG(2,"setup_sigcontext32: sc->sc_iaoq[0] = %p <= %#x\n",
230 &sc->sc_iaoq[0], compat_reg);
231 /* Store upper half */
232 compat_reg = (compat_uint_t)(regs->iaoq[0] >> 32);
233 err |= __put_user(compat_reg, &rf->rf_iaoq[0]);
234 DBG(2,"setup_sigcontext32: upper half iaoq[0] = %#x\n", compat_reg);
235
236 compat_reg = (compat_uint_t)(regs->iaoq[1]);
237 err |= __put_user(compat_reg, &sc->sc_iaoq[1]);
238 DBG(2,"setup_sigcontext32: sc->sc_iaoq[1] = %p <= %#x\n",
239 &sc->sc_iaoq[1], compat_reg);
240 /* Store upper half */
241 compat_reg = (compat_uint_t)(regs->iaoq[1] >> 32);
242 err |= __put_user(compat_reg, &rf->rf_iaoq[1]);
243 DBG(2,"setup_sigcontext32: upper half iaoq[1] = %#x\n", compat_reg);
244
245
246 compat_reg = (compat_uint_t)(regs->iasq[0]);
247 err |= __put_user(compat_reg, &sc->sc_iasq[0]);
248 DBG(2,"setup_sigcontext32: sc->sc_iasq[0] = %p <= %#x\n",
249 &sc->sc_iasq[0], compat_reg);
250 /* Store upper half */
251 compat_reg = (compat_uint_t)(regs->iasq[0] >> 32);
252 err |= __put_user(compat_reg, &rf->rf_iasq[0]);
253 DBG(2,"setup_sigcontext32: upper half iasq[0] = %#x\n", compat_reg);
254
255
256 compat_reg = (compat_uint_t)(regs->iasq[1]);
257 err |= __put_user(compat_reg, &sc->sc_iasq[1]);
258 DBG(2,"setup_sigcontext32: sc->sc_iasq[1] = %p <= %#x\n",
259 &sc->sc_iasq[1], compat_reg);
260 /* Store upper half */
261 compat_reg = (compat_uint_t)(regs->iasq[1] >> 32);
262 err |= __put_user(compat_reg, &rf->rf_iasq[1]);
263 DBG(2,"setup_sigcontext32: upper half iasq[1] = %#x\n", compat_reg);
264
265 /* Print out the IAOQ for debugging */
266 DBG(1,"setup_sigcontext32: ia0q %#lx / %#lx\n",
267 regs->iaoq[0], regs->iaoq[1]);
268 }
269
270 err |= __put_user(flags, &sc->sc_flags);
271
272 DBG(1,"setup_sigcontext32: Truncating general registers.\n");
273
274 for(regn=0; regn < 32; regn++){
275 /* Truncate a general register */
276 compat_reg = (compat_uint_t)(regs->gr[regn]);
277 err |= __put_user(compat_reg, &sc->sc_gr[regn]);
278 /* Store upper half */
279 compat_regb = (compat_uint_t)(regs->gr[regn] >> 32);
280 err |= __put_user(compat_regb, &rf->rf_gr[regn]);
281
282 /* DEBUG: Write out the "upper / lower" register data */
283 DBG(2,"setup_sigcontext32: gr%02d = %#x / %#x\n", regn,
284 compat_regb, compat_reg);
285 }
286
287 /* Copy the floating point registers (same size)
288 XXX: BE WARNED FR's are 64-BIT! */
289 DBG(1,"setup_sigcontext32: Copying from regs to sc, "
290 "sc->sc_fr size = %#lx, regs->fr size = %#lx\n",
291 sizeof(regs->fr), sizeof(sc->sc_fr));
292 err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs->fr));
293
294 compat_reg = (compat_uint_t)(regs->sar);
295 err |= __put_user(compat_reg, &sc->sc_sar);
296 DBG(2,"setup_sigcontext32: sar is %#x\n", compat_reg);
297 /* Store upper half */
298 compat_reg = (compat_uint_t)(regs->sar >> 32);
299 err |= __put_user(compat_reg, &rf->rf_sar);
300 DBG(2,"setup_sigcontext32: upper half sar = %#x\n", compat_reg);
301 DBG(1,"setup_sigcontext32: r28 is %ld\n", regs->gr[28]);
302
303 return err;
304}
Kyle McMartinf671c452006-01-15 14:10:29 -0500305
306int
307copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from)
308{
Carlos O'Donell Jrf6744bd2007-02-16 10:54:10 -0500309 compat_uptr_t addr;
Kyle McMartinf671c452006-01-15 14:10:29 -0500310 int err;
311
312 if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
313 return -EFAULT;
314
315 err = __get_user(to->si_signo, &from->si_signo);
316 err |= __get_user(to->si_errno, &from->si_errno);
317 err |= __get_user(to->si_code, &from->si_code);
318
319 if (to->si_code < 0)
320 err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
321 else {
322 switch (to->si_code >> 16) {
323 case __SI_CHLD >> 16:
324 err |= __get_user(to->si_utime, &from->si_utime);
325 err |= __get_user(to->si_stime, &from->si_stime);
326 err |= __get_user(to->si_status, &from->si_status);
327 default:
328 err |= __get_user(to->si_pid, &from->si_pid);
329 err |= __get_user(to->si_uid, &from->si_uid);
330 break;
331 case __SI_FAULT >> 16:
Carlos O'Donell Jrf6744bd2007-02-16 10:54:10 -0500332 err |= __get_user(addr, &from->si_addr);
333 to->si_addr = compat_ptr(addr);
Kyle McMartinf671c452006-01-15 14:10:29 -0500334 break;
335 case __SI_POLL >> 16:
336 err |= __get_user(to->si_band, &from->si_band);
337 err |= __get_user(to->si_fd, &from->si_fd);
338 break;
339 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
340 case __SI_MESGQ >> 16:
341 err |= __get_user(to->si_pid, &from->si_pid);
342 err |= __get_user(to->si_uid, &from->si_uid);
343 err |= __get_user(to->si_int, &from->si_int);
344 break;
345 }
346 }
347 return err;
348}
349
350int
351copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from)
352{
Carlos O'Donell Jrf6744bd2007-02-16 10:54:10 -0500353 compat_uptr_t addr;
354 compat_int_t val;
Kyle McMartinf671c452006-01-15 14:10:29 -0500355 int err;
356
357 if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
358 return -EFAULT;
359
360 /* If you change siginfo_t structure, please be sure
361 this code is fixed accordingly.
362 It should never copy any pad contained in the structure
363 to avoid security leaks, but must copy the generic
364 3 ints plus the relevant union member.
365 This routine must convert siginfo from 64bit to 32bit as well
366 at the same time. */
367 err = __put_user(from->si_signo, &to->si_signo);
368 err |= __put_user(from->si_errno, &to->si_errno);
369 err |= __put_user((short)from->si_code, &to->si_code);
370 if (from->si_code < 0)
371 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
372 else {
373 switch (from->si_code >> 16) {
374 case __SI_CHLD >> 16:
375 err |= __put_user(from->si_utime, &to->si_utime);
376 err |= __put_user(from->si_stime, &to->si_stime);
377 err |= __put_user(from->si_status, &to->si_status);
378 default:
379 err |= __put_user(from->si_pid, &to->si_pid);
380 err |= __put_user(from->si_uid, &to->si_uid);
381 break;
382 case __SI_FAULT >> 16:
Carlos O'Donell Jrf6744bd2007-02-16 10:54:10 -0500383 addr = ptr_to_compat(from->si_addr);
384 err |= __put_user(addr, &to->si_addr);
Kyle McMartinf671c452006-01-15 14:10:29 -0500385 break;
386 case __SI_POLL >> 16:
387 err |= __put_user(from->si_band, &to->si_band);
388 err |= __put_user(from->si_fd, &to->si_fd);
389 break;
390 case __SI_TIMER >> 16:
391 err |= __put_user(from->si_tid, &to->si_tid);
392 err |= __put_user(from->si_overrun, &to->si_overrun);
Carlos O'Donell Jrf6744bd2007-02-16 10:54:10 -0500393 val = (compat_int_t)from->si_int;
394 err |= __put_user(val, &to->si_int);
Kyle McMartinf671c452006-01-15 14:10:29 -0500395 break;
396 case __SI_RT >> 16: /* Not generated by the kernel as of now. */
397 case __SI_MESGQ >> 16:
398 err |= __put_user(from->si_uid, &to->si_uid);
399 err |= __put_user(from->si_pid, &to->si_pid);
Carlos O'Donell Jrf6744bd2007-02-16 10:54:10 -0500400 val = (compat_int_t)from->si_int;
401 err |= __put_user(val, &to->si_int);
Kyle McMartinf671c452006-01-15 14:10:29 -0500402 break;
403 }
404 }
405 return err;
406}