Merge branch 'akpm' (fixes from Andrew Morton)
[deliverable/linux.git] / arch / parisc / kernel / signal32.c
CommitLineData
1da177e4
LT
1/* Signal support for 32-bit kernel builds
2 *
3 * Copyright (C) 2001 Matthew Wilcox <willy at parisc-linux.org>
d104f11c
KM
4 * Copyright (C) 2006 Kyle McMartin <kyle at parisc-linux.org>
5 *
1da177e4
LT
6 * 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>
1da177e4
LT
26#include <linux/module.h>
27#include <linux/unistd.h>
1da177e4
LT
28#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
1da177e4
LT
34#include <asm/uaccess.h>
35
36#include "signal32.h"
1da177e4
LT
37
38#define DEBUG_COMPAT_SIG 0
39#define DEBUG_COMPAT_SIG_LEVEL 2
40
41#if DEBUG_COMPAT_SIG
42#define DBG(LEVEL, ...) \
43 ((DEBUG_COMPAT_SIG_LEVEL >= LEVEL) \
44 ? printk(__VA_ARGS__) : (void) 0)
45#else
46#define DBG(LEVEL, ...)
47#endif
48
1da177e4
LT
49inline void
50sigset_32to64(sigset_t *s64, compat_sigset_t *s32)
51{
52 s64->sig[0] = s32->sig[0] | ((unsigned long)s32->sig[1] << 32);
53}
54
55inline void
56sigset_64to32(compat_sigset_t *s32, sigset_t *s64)
57{
58 s32->sig[0] = s64->sig[0] & 0xffffffffUL;
59 s32->sig[1] = (s64->sig[0] >> 32) & 0xffffffffUL;
60}
61
1da177e4
LT
62long
63restore_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf,
64 struct pt_regs *regs)
65{
66 long err = 0;
67 compat_uint_t compat_reg;
68 compat_uint_t compat_regt;
69 int regn;
70
71 /* When loading 32-bit values into 64-bit registers make
72 sure to clear the upper 32-bits */
73 DBG(2,"restore_sigcontext32: PER_LINUX32 process\n");
74 DBG(2,"restore_sigcontext32: sc = 0x%p, rf = 0x%p, regs = 0x%p\n", sc, rf, regs);
75 DBG(2,"restore_sigcontext32: compat_sigcontext is %#lx bytes\n", sizeof(*sc));
76 for(regn=0; regn < 32; regn++){
77 err |= __get_user(compat_reg,&sc->sc_gr[regn]);
78 regs->gr[regn] = compat_reg;
79 /* Load upper half */
80 err |= __get_user(compat_regt,&rf->rf_gr[regn]);
81 regs->gr[regn] = ((u64)compat_regt << 32) | (u64)compat_reg;
82 DBG(3,"restore_sigcontext32: gr%02d = %#lx (%#x / %#x)\n",
83 regn, regs->gr[regn], compat_regt, compat_reg);
84 }
85 DBG(2,"restore_sigcontext32: sc->sc_fr = 0x%p (%#lx)\n",sc->sc_fr, sizeof(sc->sc_fr));
86 /* XXX: BE WARNED FR's are 64-BIT! */
87 err |= __copy_from_user(regs->fr, sc->sc_fr, sizeof(regs->fr));
88
89 /* Better safe than sorry, pass __get_user two things of
90 the same size and let gcc do the upward conversion to
91 64-bits */
92 err |= __get_user(compat_reg, &sc->sc_iaoq[0]);
93 /* Load upper half */
94 err |= __get_user(compat_regt, &rf->rf_iaoq[0]);
95 regs->iaoq[0] = ((u64)compat_regt << 32) | (u64)compat_reg;
96 DBG(2,"restore_sigcontext32: upper half of iaoq[0] = %#lx\n", compat_regt);
97 DBG(2,"restore_sigcontext32: sc->sc_iaoq[0] = %p => %#x\n",
98 &sc->sc_iaoq[0], compat_reg);
99
100 err |= __get_user(compat_reg, &sc->sc_iaoq[1]);
101 /* Load upper half */
102 err |= __get_user(compat_regt, &rf->rf_iaoq[1]);
103 regs->iaoq[1] = ((u64)compat_regt << 32) | (u64)compat_reg;
104 DBG(2,"restore_sigcontext32: upper half of iaoq[1] = %#lx\n", compat_regt);
105 DBG(2,"restore_sigcontext32: sc->sc_iaoq[1] = %p => %#x\n",
106 &sc->sc_iaoq[1],compat_reg);
107 DBG(2,"restore_sigcontext32: iaoq is %#lx / %#lx\n",
108 regs->iaoq[0],regs->iaoq[1]);
109
110 err |= __get_user(compat_reg, &sc->sc_iasq[0]);
111 /* Load the upper half for iasq */
112 err |= __get_user(compat_regt, &rf->rf_iasq[0]);
113 regs->iasq[0] = ((u64)compat_regt << 32) | (u64)compat_reg;
114 DBG(2,"restore_sigcontext32: upper half of iasq[0] = %#lx\n", compat_regt);
115
116 err |= __get_user(compat_reg, &sc->sc_iasq[1]);
117 /* Load the upper half for iasq */
118 err |= __get_user(compat_regt, &rf->rf_iasq[1]);
119 regs->iasq[1] = ((u64)compat_regt << 32) | (u64)compat_reg;
120 DBG(2,"restore_sigcontext32: upper half of iasq[1] = %#lx\n", compat_regt);
121 DBG(2,"restore_sigcontext32: iasq is %#lx / %#lx\n",
122 regs->iasq[0],regs->iasq[1]);
123
124 err |= __get_user(compat_reg, &sc->sc_sar);
125 /* Load the upper half for sar */
126 err |= __get_user(compat_regt, &rf->rf_sar);
127 regs->sar = ((u64)compat_regt << 32) | (u64)compat_reg;
128 DBG(2,"restore_sigcontext32: upper_half & sar = %#lx\n", compat_regt);
129 DBG(2,"restore_sigcontext32: sar is %#lx\n", regs->sar);
130 DBG(2,"restore_sigcontext32: r28 is %ld\n", regs->gr[28]);
131
132 return err;
133}
134
135/*
136 * Set up the sigcontext structure for this process.
137 * This is not an easy task if the kernel is 64-bit, it will require
138 * that we examine the process personality to determine if we need to
139 * truncate for a 32-bit userspace.
140 */
141long
142setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf,
143 struct pt_regs *regs, int in_syscall)
144{
145 compat_int_t flags = 0;
146 long err = 0;
147 compat_uint_t compat_reg;
148 compat_uint_t compat_regb;
149 int regn;
150
151 if (on_sig_stack((unsigned long) sc))
152 flags |= PARISC_SC_FLAG_ONSTACK;
153
154 if (in_syscall) {
155
156 DBG(1,"setup_sigcontext32: in_syscall\n");
157
158 flags |= PARISC_SC_FLAG_IN_SYSCALL;
159 /* Truncate gr31 */
160 compat_reg = (compat_uint_t)(regs->gr[31]);
161 /* regs->iaoq is undefined in the syscall return path */
162 err |= __put_user(compat_reg, &sc->sc_iaoq[0]);
163 DBG(2,"setup_sigcontext32: sc->sc_iaoq[0] = %p <= %#x\n",
164 &sc->sc_iaoq[0], compat_reg);
165
166 /* Store upper half */
f4441b62 167 compat_reg = (compat_uint_t)(regs->gr[31] >> 32);
1da177e4
LT
168 err |= __put_user(compat_reg, &rf->rf_iaoq[0]);
169 DBG(2,"setup_sigcontext32: upper half iaoq[0] = %#x\n", compat_reg);
170
171
172 compat_reg = (compat_uint_t)(regs->gr[31]+4);
173 err |= __put_user(compat_reg, &sc->sc_iaoq[1]);
174 DBG(2,"setup_sigcontext32: sc->sc_iaoq[1] = %p <= %#x\n",
175 &sc->sc_iaoq[1], compat_reg);
176 /* Store upper half */
f4441b62 177 compat_reg = (compat_uint_t)((regs->gr[31]+4) >> 32);
1da177e4
LT
178 err |= __put_user(compat_reg, &rf->rf_iaoq[1]);
179 DBG(2,"setup_sigcontext32: upper half iaoq[1] = %#x\n", compat_reg);
180
181 /* Truncate sr3 */
182 compat_reg = (compat_uint_t)(regs->sr[3]);
183 err |= __put_user(compat_reg, &sc->sc_iasq[0]);
184 err |= __put_user(compat_reg, &sc->sc_iasq[1]);
185
186 /* Store upper half */
187 compat_reg = (compat_uint_t)(regs->sr[3] >> 32);
188 err |= __put_user(compat_reg, &rf->rf_iasq[0]);
189 err |= __put_user(compat_reg, &rf->rf_iasq[1]);
190
191 DBG(2,"setup_sigcontext32: upper half iasq[0] = %#x\n", compat_reg);
192 DBG(2,"setup_sigcontext32: upper half iasq[1] = %#x\n", compat_reg);
193 DBG(1,"setup_sigcontext32: iaoq %#lx / %#lx\n",
194 regs->gr[31], regs->gr[31]+4);
195
196 } else {
197
198 compat_reg = (compat_uint_t)(regs->iaoq[0]);
199 err |= __put_user(compat_reg, &sc->sc_iaoq[0]);
200 DBG(2,"setup_sigcontext32: sc->sc_iaoq[0] = %p <= %#x\n",
201 &sc->sc_iaoq[0], compat_reg);
202 /* Store upper half */
203 compat_reg = (compat_uint_t)(regs->iaoq[0] >> 32);
204 err |= __put_user(compat_reg, &rf->rf_iaoq[0]);
205 DBG(2,"setup_sigcontext32: upper half iaoq[0] = %#x\n", compat_reg);
206
207 compat_reg = (compat_uint_t)(regs->iaoq[1]);
208 err |= __put_user(compat_reg, &sc->sc_iaoq[1]);
209 DBG(2,"setup_sigcontext32: sc->sc_iaoq[1] = %p <= %#x\n",
210 &sc->sc_iaoq[1], compat_reg);
211 /* Store upper half */
212 compat_reg = (compat_uint_t)(regs->iaoq[1] >> 32);
213 err |= __put_user(compat_reg, &rf->rf_iaoq[1]);
214 DBG(2,"setup_sigcontext32: upper half iaoq[1] = %#x\n", compat_reg);
215
216
217 compat_reg = (compat_uint_t)(regs->iasq[0]);
218 err |= __put_user(compat_reg, &sc->sc_iasq[0]);
219 DBG(2,"setup_sigcontext32: sc->sc_iasq[0] = %p <= %#x\n",
220 &sc->sc_iasq[0], compat_reg);
221 /* Store upper half */
222 compat_reg = (compat_uint_t)(regs->iasq[0] >> 32);
223 err |= __put_user(compat_reg, &rf->rf_iasq[0]);
224 DBG(2,"setup_sigcontext32: upper half iasq[0] = %#x\n", compat_reg);
225
226
227 compat_reg = (compat_uint_t)(regs->iasq[1]);
228 err |= __put_user(compat_reg, &sc->sc_iasq[1]);
229 DBG(2,"setup_sigcontext32: sc->sc_iasq[1] = %p <= %#x\n",
230 &sc->sc_iasq[1], compat_reg);
231 /* Store upper half */
232 compat_reg = (compat_uint_t)(regs->iasq[1] >> 32);
233 err |= __put_user(compat_reg, &rf->rf_iasq[1]);
234 DBG(2,"setup_sigcontext32: upper half iasq[1] = %#x\n", compat_reg);
235
236 /* Print out the IAOQ for debugging */
237 DBG(1,"setup_sigcontext32: ia0q %#lx / %#lx\n",
238 regs->iaoq[0], regs->iaoq[1]);
239 }
240
241 err |= __put_user(flags, &sc->sc_flags);
242
243 DBG(1,"setup_sigcontext32: Truncating general registers.\n");
244
245 for(regn=0; regn < 32; regn++){
246 /* Truncate a general register */
247 compat_reg = (compat_uint_t)(regs->gr[regn]);
248 err |= __put_user(compat_reg, &sc->sc_gr[regn]);
249 /* Store upper half */
250 compat_regb = (compat_uint_t)(regs->gr[regn] >> 32);
251 err |= __put_user(compat_regb, &rf->rf_gr[regn]);
252
253 /* DEBUG: Write out the "upper / lower" register data */
254 DBG(2,"setup_sigcontext32: gr%02d = %#x / %#x\n", regn,
255 compat_regb, compat_reg);
256 }
257
258 /* Copy the floating point registers (same size)
259 XXX: BE WARNED FR's are 64-BIT! */
260 DBG(1,"setup_sigcontext32: Copying from regs to sc, "
261 "sc->sc_fr size = %#lx, regs->fr size = %#lx\n",
262 sizeof(regs->fr), sizeof(sc->sc_fr));
263 err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs->fr));
264
265 compat_reg = (compat_uint_t)(regs->sar);
266 err |= __put_user(compat_reg, &sc->sc_sar);
267 DBG(2,"setup_sigcontext32: sar is %#x\n", compat_reg);
268 /* Store upper half */
269 compat_reg = (compat_uint_t)(regs->sar >> 32);
270 err |= __put_user(compat_reg, &rf->rf_sar);
271 DBG(2,"setup_sigcontext32: upper half sar = %#x\n", compat_reg);
272 DBG(1,"setup_sigcontext32: r28 is %ld\n", regs->gr[28]);
273
274 return err;
275}
f671c45d
KM
276
277int
278copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from)
279{
f6744bdd 280 compat_uptr_t addr;
f671c45d
KM
281 int err;
282
283 if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
284 return -EFAULT;
285
286 err = __get_user(to->si_signo, &from->si_signo);
287 err |= __get_user(to->si_errno, &from->si_errno);
288 err |= __get_user(to->si_code, &from->si_code);
289
290 if (to->si_code < 0)
291 err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
292 else {
293 switch (to->si_code >> 16) {
294 case __SI_CHLD >> 16:
295 err |= __get_user(to->si_utime, &from->si_utime);
296 err |= __get_user(to->si_stime, &from->si_stime);
297 err |= __get_user(to->si_status, &from->si_status);
298 default:
299 err |= __get_user(to->si_pid, &from->si_pid);
300 err |= __get_user(to->si_uid, &from->si_uid);
301 break;
302 case __SI_FAULT >> 16:
f6744bdd
CDJ
303 err |= __get_user(addr, &from->si_addr);
304 to->si_addr = compat_ptr(addr);
f671c45d
KM
305 break;
306 case __SI_POLL >> 16:
307 err |= __get_user(to->si_band, &from->si_band);
308 err |= __get_user(to->si_fd, &from->si_fd);
309 break;
310 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
311 case __SI_MESGQ >> 16:
312 err |= __get_user(to->si_pid, &from->si_pid);
313 err |= __get_user(to->si_uid, &from->si_uid);
314 err |= __get_user(to->si_int, &from->si_int);
315 break;
316 }
317 }
318 return err;
319}
320
321int
ce395960 322copy_siginfo_to_user32 (compat_siginfo_t __user *to, const siginfo_t *from)
f671c45d 323{
f6744bdd
CDJ
324 compat_uptr_t addr;
325 compat_int_t val;
f671c45d
KM
326 int err;
327
328 if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
329 return -EFAULT;
330
331 /* If you change siginfo_t structure, please be sure
332 this code is fixed accordingly.
333 It should never copy any pad contained in the structure
334 to avoid security leaks, but must copy the generic
335 3 ints plus the relevant union member.
336 This routine must convert siginfo from 64bit to 32bit as well
337 at the same time. */
338 err = __put_user(from->si_signo, &to->si_signo);
339 err |= __put_user(from->si_errno, &to->si_errno);
340 err |= __put_user((short)from->si_code, &to->si_code);
341 if (from->si_code < 0)
342 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
343 else {
344 switch (from->si_code >> 16) {
345 case __SI_CHLD >> 16:
346 err |= __put_user(from->si_utime, &to->si_utime);
347 err |= __put_user(from->si_stime, &to->si_stime);
348 err |= __put_user(from->si_status, &to->si_status);
349 default:
350 err |= __put_user(from->si_pid, &to->si_pid);
351 err |= __put_user(from->si_uid, &to->si_uid);
352 break;
353 case __SI_FAULT >> 16:
f6744bdd
CDJ
354 addr = ptr_to_compat(from->si_addr);
355 err |= __put_user(addr, &to->si_addr);
f671c45d
KM
356 break;
357 case __SI_POLL >> 16:
358 err |= __put_user(from->si_band, &to->si_band);
359 err |= __put_user(from->si_fd, &to->si_fd);
360 break;
361 case __SI_TIMER >> 16:
362 err |= __put_user(from->si_tid, &to->si_tid);
363 err |= __put_user(from->si_overrun, &to->si_overrun);
f6744bdd
CDJ
364 val = (compat_int_t)from->si_int;
365 err |= __put_user(val, &to->si_int);
f671c45d
KM
366 break;
367 case __SI_RT >> 16: /* Not generated by the kernel as of now. */
368 case __SI_MESGQ >> 16:
369 err |= __put_user(from->si_uid, &to->si_uid);
370 err |= __put_user(from->si_pid, &to->si_pid);
f6744bdd
CDJ
371 val = (compat_int_t)from->si_int;
372 err |= __put_user(val, &to->si_int);
f671c45d
KM
373 break;
374 }
375 }
376 return err;
377}
This page took 0.760627 seconds and 5 git commands to generate.