blob: 53e48f721ce3e0ceb122ac42550178e74886ad0e [file] [log] [blame]
David S. Miller5526b7e2008-04-27 02:26:36 -07001/* arch/sparc64/kernel/signal32.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
5 * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
6 * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
7 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
8 */
9
10#include <linux/sched.h>
11#include <linux/kernel.h>
12#include <linux/signal.h>
13#include <linux/errno.h>
14#include <linux/wait.h>
15#include <linux/ptrace.h>
16#include <linux/unistd.h>
17#include <linux/mm.h>
18#include <linux/tty.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/binfmts.h>
20#include <linux/compat.h>
21#include <linux/bitops.h>
Roland McGrath95698462008-07-27 01:08:02 -070022#include <linux/tracehook.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
24#include <asm/uaccess.h>
25#include <asm/ptrace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <asm/pgtable.h>
27#include <asm/psrcompat.h>
28#include <asm/fpumacro.h>
29#include <asm/visasm.h>
David S. Miller14cc6ab2006-10-02 14:17:57 -070030#include <asm/compat_signal.h>
David Howellsd550bbd2012-03-28 18:30:03 +010031#include <asm/switch_to.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
David S. Miller55984732011-08-20 17:14:54 -070033#include "sigutil.h"
34
Linus Torvalds1da177e2005-04-16 15:20:36 -070035/* This magic should be in g_upper[0] for all upper parts
36 * to be valid.
37 */
38#define SIGINFO_EXTRA_V8PLUS_MAGIC 0x130e269
39typedef struct {
40 unsigned int g_upper[8];
41 unsigned int o_upper[8];
42 unsigned int asi;
43} siginfo_extra_v8plus_t;
44
David S. Miller5526b7e2008-04-27 02:26:36 -070045struct signal_frame32 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 struct sparc_stackf32 ss;
47 __siginfo32_t info;
David S. Miller55984732011-08-20 17:14:54 -070048 /* __siginfo_fpu_t * */ u32 fpu_save;
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 unsigned int insns[2];
50 unsigned int extramask[_COMPAT_NSIG_WORDS - 1];
51 unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
52 /* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
53 siginfo_extra_v8plus_t v8plus;
David S. Miller55984732011-08-20 17:14:54 -070054 /* __siginfo_rwin_t * */u32 rwin_save;
55} __attribute__((aligned(8)));
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Linus Torvalds1da177e2005-04-16 15:20:36 -070057struct rt_signal_frame32 {
58 struct sparc_stackf32 ss;
59 compat_siginfo_t info;
60 struct pt_regs32 regs;
61 compat_sigset_t mask;
David S. Miller55984732011-08-20 17:14:54 -070062 /* __siginfo_fpu_t * */ u32 fpu_save;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 unsigned int insns[2];
64 stack_t32 stack;
65 unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
66 /* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
67 siginfo_extra_v8plus_t v8plus;
David S. Miller55984732011-08-20 17:14:54 -070068 /* __siginfo_rwin_t * */u32 rwin_save;
69} __attribute__((aligned(8)));
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
72{
73 int err;
74
75 if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
76 return -EFAULT;
77
78 /* If you change siginfo_t structure, please be sure
79 this code is fixed accordingly.
80 It should never copy any pad contained in the structure
81 to avoid security leaks, but must copy the generic
82 3 ints plus the relevant union member.
83 This routine must convert siginfo from 64bit to 32bit as well
84 at the same time. */
85 err = __put_user(from->si_signo, &to->si_signo);
86 err |= __put_user(from->si_errno, &to->si_errno);
87 err |= __put_user((short)from->si_code, &to->si_code);
88 if (from->si_code < 0)
89 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
90 else {
91 switch (from->si_code >> 16) {
92 case __SI_TIMER >> 16:
93 err |= __put_user(from->si_tid, &to->si_tid);
94 err |= __put_user(from->si_overrun, &to->si_overrun);
95 err |= __put_user(from->si_int, &to->si_int);
96 break;
97 case __SI_CHLD >> 16:
98 err |= __put_user(from->si_utime, &to->si_utime);
99 err |= __put_user(from->si_stime, &to->si_stime);
100 err |= __put_user(from->si_status, &to->si_status);
101 default:
102 err |= __put_user(from->si_pid, &to->si_pid);
103 err |= __put_user(from->si_uid, &to->si_uid);
104 break;
105 case __SI_FAULT >> 16:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 err |= __put_user(from->si_trapno, &to->si_trapno);
107 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
108 break;
Jurij Smakov9c7d3b32005-04-17 18:03:12 -0700109 case __SI_POLL >> 16:
110 err |= __put_user(from->si_band, &to->si_band);
111 err |= __put_user(from->si_fd, &to->si_fd);
112 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
114 case __SI_MESGQ >> 16:
115 err |= __put_user(from->si_pid, &to->si_pid);
116 err |= __put_user(from->si_uid, &to->si_uid);
117 err |= __put_user(from->si_int, &to->si_int);
118 break;
119 }
120 }
121 return err;
122}
123
124/* CAUTION: This is just a very minimalist implementation for the
125 * sake of compat_sys_rt_sigqueueinfo()
126 */
127int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
128{
129 if (!access_ok(VERIFY_WRITE, from, sizeof(compat_siginfo_t)))
130 return -EFAULT;
131
132 if (copy_from_user(to, from, 3*sizeof(int)) ||
133 copy_from_user(to->_sifields._pad, from->_sifields._pad,
134 SI_PAD_SIZE))
135 return -EFAULT;
136
137 return 0;
138}
139
David S. Miller5526b7e2008-04-27 02:26:36 -0700140void do_sigreturn32(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141{
David S. Miller5526b7e2008-04-27 02:26:36 -0700142 struct signal_frame32 __user *sf;
David S. Miller55984732011-08-20 17:14:54 -0700143 compat_uptr_t fpu_save;
144 compat_uptr_t rwin_save;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 unsigned int psr;
David S. Miller55984732011-08-20 17:14:54 -0700146 unsigned pc, npc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 sigset_t set;
148 unsigned seta[_COMPAT_NSIG_WORDS];
149 int err, i;
150
David S. Miller5526b7e2008-04-27 02:26:36 -0700151 /* Always make any pending restarted system calls return -EINTR */
152 current_thread_info()->restart_block.fn = do_no_restart_syscall;
153
154 synchronize_user_stack();
155
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
David S. Miller5526b7e2008-04-27 02:26:36 -0700157 sf = (struct signal_frame32 __user *) regs->u_regs[UREG_FP];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
159 /* 1. Make sure we are not getting garbage from the user */
160 if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
161 (((unsigned long) sf) & 3))
162 goto segv;
163
Al Viro187cd442012-04-22 16:51:36 -0400164 if (get_user(pc, &sf->info.si_regs.pc) ||
165 __get_user(npc, &sf->info.si_regs.npc))
166 goto segv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
168 if ((pc | npc) & 3)
169 goto segv;
170
171 if (test_thread_flag(TIF_32BIT)) {
172 pc &= 0xffffffff;
173 npc &= 0xffffffff;
174 }
175 regs->tpc = pc;
176 regs->tnpc = npc;
177
178 /* 2. Restore the state */
179 err = __get_user(regs->y, &sf->info.si_regs.y);
180 err |= __get_user(psr, &sf->info.si_regs.psr);
181
182 for (i = UREG_G1; i <= UREG_I7; i++)
183 err |= __get_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
184 if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) {
185 err |= __get_user(i, &sf->v8plus.g_upper[0]);
186 if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) {
187 unsigned long asi;
188
189 for (i = UREG_G1; i <= UREG_I7; i++)
190 err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
191 err |= __get_user(asi, &sf->v8plus.asi);
192 regs->tstate &= ~TSTATE_ASI;
193 regs->tstate |= ((asi & 0xffUL) << 24UL);
194 }
195 }
196
197 /* User can only change condition codes in %tstate. */
198 regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
199 regs->tstate |= psr_to_tstate_icc(psr);
200
David S. Miller2678fef2008-05-01 03:30:22 -0700201 /* Prevent syscall restart. */
David S. Miller28e61032008-05-11 02:07:19 -0700202 pt_regs_clear_syscall(regs);
David S. Miller2678fef2008-05-01 03:30:22 -0700203
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 err |= __get_user(fpu_save, &sf->fpu_save);
David S. Miller55984732011-08-20 17:14:54 -0700205 if (!err && fpu_save)
206 err |= restore_fpu_state(regs, compat_ptr(fpu_save));
207 err |= __get_user(rwin_save, &sf->rwin_save);
208 if (!err && rwin_save) {
209 if (restore_rwin_state(compat_ptr(rwin_save)))
210 goto segv;
211 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 err |= __get_user(seta[0], &sf->info.si_mask);
213 err |= copy_from_user(seta+1, &sf->extramask,
214 (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
215 if (err)
216 goto segv;
217 switch (_NSIG_WORDS) {
218 case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32);
219 case 3: set.sig[2] = seta[4] + (((long)seta[5]) << 32);
220 case 2: set.sig[1] = seta[2] + (((long)seta[3]) << 32);
221 case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32);
222 }
Matt Flemingfaddf592011-08-11 14:57:02 +0100223 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 return;
225
226segv:
227 force_sig(SIGSEGV, current);
228}
229
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
231{
232 struct rt_signal_frame32 __user *sf;
David S. Miller55984732011-08-20 17:14:54 -0700233 unsigned int psr, pc, npc, u_ss_sp;
234 compat_uptr_t fpu_save;
235 compat_uptr_t rwin_save;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 mm_segment_t old_fs;
237 sigset_t set;
238 compat_sigset_t seta;
239 stack_t st;
240 int err, i;
241
242 /* Always make any pending restarted system calls return -EINTR */
243 current_thread_info()->restart_block.fn = do_no_restart_syscall;
244
245 synchronize_user_stack();
246 regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
247 sf = (struct rt_signal_frame32 __user *) regs->u_regs[UREG_FP];
248
249 /* 1. Make sure we are not getting garbage from the user */
250 if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
251 (((unsigned long) sf) & 3))
252 goto segv;
253
Al Viro187cd442012-04-22 16:51:36 -0400254 if (get_user(pc, &sf->regs.pc) ||
255 __get_user(npc, &sf->regs.npc))
256 goto segv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
258 if ((pc | npc) & 3)
259 goto segv;
260
261 if (test_thread_flag(TIF_32BIT)) {
262 pc &= 0xffffffff;
263 npc &= 0xffffffff;
264 }
265 regs->tpc = pc;
266 regs->tnpc = npc;
267
268 /* 2. Restore the state */
269 err = __get_user(regs->y, &sf->regs.y);
270 err |= __get_user(psr, &sf->regs.psr);
271
272 for (i = UREG_G1; i <= UREG_I7; i++)
273 err |= __get_user(regs->u_regs[i], &sf->regs.u_regs[i]);
274 if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) {
275 err |= __get_user(i, &sf->v8plus.g_upper[0]);
276 if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) {
277 unsigned long asi;
278
279 for (i = UREG_G1; i <= UREG_I7; i++)
280 err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
281 err |= __get_user(asi, &sf->v8plus.asi);
282 regs->tstate &= ~TSTATE_ASI;
283 regs->tstate |= ((asi & 0xffUL) << 24UL);
284 }
285 }
286
287 /* User can only change condition codes in %tstate. */
288 regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
289 regs->tstate |= psr_to_tstate_icc(psr);
290
David S. Miller2678fef2008-05-01 03:30:22 -0700291 /* Prevent syscall restart. */
David S. Miller28e61032008-05-11 02:07:19 -0700292 pt_regs_clear_syscall(regs);
David S. Miller2678fef2008-05-01 03:30:22 -0700293
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 err |= __get_user(fpu_save, &sf->fpu_save);
David S. Miller55984732011-08-20 17:14:54 -0700295 if (!err && fpu_save)
296 err |= restore_fpu_state(regs, compat_ptr(fpu_save));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t));
298 err |= __get_user(u_ss_sp, &sf->stack.ss_sp);
299 st.ss_sp = compat_ptr(u_ss_sp);
300 err |= __get_user(st.ss_flags, &sf->stack.ss_flags);
301 err |= __get_user(st.ss_size, &sf->stack.ss_size);
302 if (err)
303 goto segv;
304
305 /* It is more difficult to avoid calling this function than to
306 call it and ignore errors. */
307 old_fs = get_fs();
308 set_fs(KERNEL_DS);
309 do_sigaltstack((stack_t __user *) &st, NULL, (unsigned long)sf);
310 set_fs(old_fs);
311
David S. Miller55984732011-08-20 17:14:54 -0700312 err |= __get_user(rwin_save, &sf->rwin_save);
313 if (!err && rwin_save) {
314 if (restore_rwin_state(compat_ptr(rwin_save)))
315 goto segv;
316 }
317
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 switch (_NSIG_WORDS) {
319 case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32);
320 case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32);
321 case 2: set.sig[1] = seta.sig[2] + (((long)seta.sig[3]) << 32);
322 case 1: set.sig[0] = seta.sig[0] + (((long)seta.sig[1]) << 32);
323 }
Matt Flemingfaddf592011-08-11 14:57:02 +0100324 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 return;
326segv:
327 force_sig(SIGSEGV, current);
328}
329
330/* Checks if the fp is valid */
331static int invalid_frame_pointer(void __user *fp, int fplen)
332{
333 if ((((unsigned long) fp) & 7) || ((unsigned long)fp) > 0x100000000ULL - fplen)
334 return 1;
335 return 0;
336}
337
338static void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize)
339{
340 unsigned long sp;
341
342 regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
343 sp = regs->u_regs[UREG_FP];
344
David S. Millerdc5dc7e2008-05-07 18:54:05 -0700345 /*
346 * If we are on the alternate signal stack and would overflow it, don't.
347 * Return an always-bogus address instead so we will die with SIGSEGV.
348 */
349 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize)))
350 return (void __user *) -1L;
351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 /* This is the X/Open sanctioned signal stack switching. */
353 if (sa->sa_flags & SA_ONSTACK) {
David S. Millerdc5dc7e2008-05-07 18:54:05 -0700354 if (sas_ss_flags(sp) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 sp = current->sas_ss_sp + current->sas_ss_size;
356 }
David S. Millerdc5dc7e2008-05-07 18:54:05 -0700357
David S. Millerf036d9f2010-02-09 16:18:40 -0800358 sp -= framesize;
359
David S. Millerdc5dc7e2008-05-07 18:54:05 -0700360 /* Always align the stack frame. This handles two cases. First,
361 * sigaltstack need not be mindful of platform specific stack
362 * alignment. Second, if we took this signal because the stack
363 * is not aligned properly, we'd like to take the signal cleanly
364 * and report that.
365 */
David S. Millerf036d9f2010-02-09 16:18:40 -0800366 sp &= ~15UL;
David S. Millerdc5dc7e2008-05-07 18:54:05 -0700367
David S. Millerf036d9f2010-02-09 16:18:40 -0800368 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369}
370
David S. Miller05c5e762010-09-20 23:24:52 -0700371/* The I-cache flush instruction only works in the primary ASI, which
372 * right now is the nucleus, aka. kernel space.
373 *
374 * Therefore we have to kick the instructions out using the kernel
375 * side linear mapping of the physical address backing the user
376 * instructions.
377 */
378static void flush_signal_insns(unsigned long address)
379{
380 unsigned long pstate, paddr;
381 pte_t *ptep, pte;
382 pgd_t *pgdp;
383 pud_t *pudp;
384 pmd_t *pmdp;
385
386 /* Commit all stores of the instructions we are about to flush. */
387 wmb();
388
389 /* Disable cross-call reception. In this way even a very wide
390 * munmap() on another cpu can't tear down the page table
391 * hierarchy from underneath us, since that can't complete
392 * until the IPI tlb flush returns.
393 */
394
395 __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
396 __asm__ __volatile__("wrpr %0, %1, %%pstate"
397 : : "r" (pstate), "i" (PSTATE_IE));
398
399 pgdp = pgd_offset(current->mm, address);
400 if (pgd_none(*pgdp))
401 goto out_irqs_on;
402 pudp = pud_offset(pgdp, address);
403 if (pud_none(*pudp))
404 goto out_irqs_on;
405 pmdp = pmd_offset(pudp, address);
406 if (pmd_none(*pmdp))
407 goto out_irqs_on;
408
409 ptep = pte_offset_map(pmdp, address);
410 pte = *ptep;
411 if (!pte_present(pte))
412 goto out_unmap;
413
414 paddr = (unsigned long) page_address(pte_page(pte));
415
416 __asm__ __volatile__("flush %0 + %1"
417 : /* no outputs */
418 : "r" (paddr),
419 "r" (address & (PAGE_SIZE - 1))
420 : "memory");
421
422out_unmap:
423 pte_unmap(ptep);
424out_irqs_on:
425 __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate));
426
427}
428
David S. Miller392c2182010-09-21 21:41:12 -0700429static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
430 int signo, sigset_t *oldset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431{
David S. Miller5526b7e2008-04-27 02:26:36 -0700432 struct signal_frame32 __user *sf;
David S. Miller55984732011-08-20 17:14:54 -0700433 int i, err, wsaved;
434 void __user *tail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 int sigframe_size;
436 u32 psr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 unsigned int seta[_COMPAT_NSIG_WORDS];
438
439 /* 1. Make sure everything is clean */
440 synchronize_user_stack();
441 save_and_clear_fpu();
442
David S. Miller55984732011-08-20 17:14:54 -0700443 wsaved = get_thread_wsaved();
444
445 sigframe_size = sizeof(*sf);
446 if (current_thread_info()->fpsaved[0] & FPRS_FEF)
447 sigframe_size += sizeof(__siginfo_fpu_t);
448 if (wsaved)
449 sigframe_size += sizeof(__siginfo_rwin_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
David S. Miller5526b7e2008-04-27 02:26:36 -0700451 sf = (struct signal_frame32 __user *)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 get_sigframe(&ka->sa, regs, sigframe_size);
453
454 if (invalid_frame_pointer(sf, sigframe_size))
455 goto sigill;
456
David S. Miller55984732011-08-20 17:14:54 -0700457 tail = (sf + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
459 /* 2. Save the current process state */
460 if (test_thread_flag(TIF_32BIT)) {
461 regs->tpc &= 0xffffffff;
462 regs->tnpc &= 0xffffffff;
463 }
464 err = put_user(regs->tpc, &sf->info.si_regs.pc);
465 err |= __put_user(regs->tnpc, &sf->info.si_regs.npc);
466 err |= __put_user(regs->y, &sf->info.si_regs.y);
467 psr = tstate_to_psr(regs->tstate);
468 if (current_thread_info()->fpsaved[0] & FPRS_FEF)
469 psr |= PSR_EF;
470 err |= __put_user(psr, &sf->info.si_regs.psr);
471 for (i = 0; i < 16; i++)
472 err |= __put_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
473 err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size);
474 err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]);
475 for (i = 1; i < 16; i++)
476 err |= __put_user(((u32 *)regs->u_regs)[2*i],
477 &sf->v8plus.g_upper[i]);
478 err |= __put_user((regs->tstate & TSTATE_ASI) >> 24UL,
479 &sf->v8plus.asi);
480
481 if (psr & PSR_EF) {
David S. Miller55984732011-08-20 17:14:54 -0700482 __siginfo_fpu_t __user *fp = tail;
483 tail += sizeof(*fp);
484 err |= save_fpu_state(regs, fp);
485 err |= __put_user((u64)fp, &sf->fpu_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 } else {
487 err |= __put_user(0, &sf->fpu_save);
488 }
David S. Miller55984732011-08-20 17:14:54 -0700489 if (wsaved) {
490 __siginfo_rwin_t __user *rwp = tail;
491 tail += sizeof(*rwp);
492 err |= save_rwin_state(wsaved, rwp);
493 err |= __put_user((u64)rwp, &sf->rwin_save);
494 set_thread_wsaved(0);
495 } else {
496 err |= __put_user(0, &sf->rwin_save);
497 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 switch (_NSIG_WORDS) {
500 case 4: seta[7] = (oldset->sig[3] >> 32);
501 seta[6] = oldset->sig[3];
502 case 3: seta[5] = (oldset->sig[2] >> 32);
503 seta[4] = oldset->sig[2];
504 case 2: seta[3] = (oldset->sig[1] >> 32);
505 seta[2] = oldset->sig[1];
506 case 1: seta[1] = (oldset->sig[0] >> 32);
507 seta[0] = oldset->sig[0];
508 }
509 err |= __put_user(seta[0], &sf->info.si_mask);
510 err |= __copy_to_user(sf->extramask, seta + 1,
511 (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
512
David S. Miller55984732011-08-20 17:14:54 -0700513 if (!wsaved) {
514 err |= copy_in_user((u32 __user *)sf,
515 (u32 __user *)(regs->u_regs[UREG_FP]),
516 sizeof(struct reg_window32));
517 } else {
518 struct reg_window *rp;
519
520 rp = &current_thread_info()->reg_window[wsaved - 1];
521 for (i = 0; i < 8; i++)
522 err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
523 for (i = 0; i < 6; i++)
524 err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
525 err |= __put_user(rp->ins[6], &sf->ss.fp);
526 err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
527 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 if (err)
529 goto sigsegv;
530
531 /* 3. signal handler back-trampoline and parameters */
532 regs->u_regs[UREG_FP] = (unsigned long) sf;
533 regs->u_regs[UREG_I0] = signo;
534 regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
535 regs->u_regs[UREG_I2] = (unsigned long) &sf->info;
536
537 /* 4. signal handler */
538 regs->tpc = (unsigned long) ka->sa.sa_handler;
539 regs->tnpc = (regs->tpc + 4);
540 if (test_thread_flag(TIF_32BIT)) {
541 regs->tpc &= 0xffffffff;
542 regs->tnpc &= 0xffffffff;
543 }
544
545 /* 5. return to kernel instructions */
546 if (ka->ka_restorer) {
547 regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
548 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 unsigned long address = ((unsigned long)&(sf->insns[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
551 regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
552
553 err = __put_user(0x821020d8, &sf->insns[0]); /*mov __NR_sigreturn, %g1*/
554 err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/
555 if (err)
556 goto sigsegv;
David S. Miller05c5e762010-09-20 23:24:52 -0700557 flush_signal_insns(address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 }
David S. Millerc2785252010-09-21 22:30:13 -0700559 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560
561sigill:
562 do_exit(SIGILL);
David S. Miller392c2182010-09-21 21:41:12 -0700563 return -EINVAL;
564
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565sigsegv:
566 force_sigsegv(signo, current);
David S. Miller392c2182010-09-21 21:41:12 -0700567 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568}
569
David S. Miller392c2182010-09-21 21:41:12 -0700570static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
571 unsigned long signr, sigset_t *oldset,
572 siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573{
574 struct rt_signal_frame32 __user *sf;
David S. Miller55984732011-08-20 17:14:54 -0700575 int i, err, wsaved;
576 void __user *tail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 int sigframe_size;
578 u32 psr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 compat_sigset_t seta;
580
581 /* 1. Make sure everything is clean */
582 synchronize_user_stack();
583 save_and_clear_fpu();
584
David S. Miller55984732011-08-20 17:14:54 -0700585 wsaved = get_thread_wsaved();
586
587 sigframe_size = sizeof(*sf);
588 if (current_thread_info()->fpsaved[0] & FPRS_FEF)
589 sigframe_size += sizeof(__siginfo_fpu_t);
590 if (wsaved)
591 sigframe_size += sizeof(__siginfo_rwin_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
593 sf = (struct rt_signal_frame32 __user *)
594 get_sigframe(&ka->sa, regs, sigframe_size);
595
596 if (invalid_frame_pointer(sf, sigframe_size))
597 goto sigill;
598
David S. Miller55984732011-08-20 17:14:54 -0700599 tail = (sf + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
601 /* 2. Save the current process state */
602 if (test_thread_flag(TIF_32BIT)) {
603 regs->tpc &= 0xffffffff;
604 regs->tnpc &= 0xffffffff;
605 }
606 err = put_user(regs->tpc, &sf->regs.pc);
607 err |= __put_user(regs->tnpc, &sf->regs.npc);
608 err |= __put_user(regs->y, &sf->regs.y);
609 psr = tstate_to_psr(regs->tstate);
610 if (current_thread_info()->fpsaved[0] & FPRS_FEF)
611 psr |= PSR_EF;
612 err |= __put_user(psr, &sf->regs.psr);
613 for (i = 0; i < 16; i++)
614 err |= __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
615 err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size);
616 err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]);
617 for (i = 1; i < 16; i++)
618 err |= __put_user(((u32 *)regs->u_regs)[2*i],
619 &sf->v8plus.g_upper[i]);
620 err |= __put_user((regs->tstate & TSTATE_ASI) >> 24UL,
621 &sf->v8plus.asi);
622
623 if (psr & PSR_EF) {
David S. Miller55984732011-08-20 17:14:54 -0700624 __siginfo_fpu_t __user *fp = tail;
625 tail += sizeof(*fp);
626 err |= save_fpu_state(regs, fp);
627 err |= __put_user((u64)fp, &sf->fpu_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 } else {
629 err |= __put_user(0, &sf->fpu_save);
630 }
David S. Miller55984732011-08-20 17:14:54 -0700631 if (wsaved) {
632 __siginfo_rwin_t __user *rwp = tail;
633 tail += sizeof(*rwp);
634 err |= save_rwin_state(wsaved, rwp);
635 err |= __put_user((u64)rwp, &sf->rwin_save);
636 set_thread_wsaved(0);
637 } else {
638 err |= __put_user(0, &sf->rwin_save);
639 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
641 /* Update the siginfo structure. */
642 err |= copy_siginfo_to_user32(&sf->info, info);
643
644 /* Setup sigaltstack */
645 err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
646 err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
647 err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
648
649 switch (_NSIG_WORDS) {
650 case 4: seta.sig[7] = (oldset->sig[3] >> 32);
651 seta.sig[6] = oldset->sig[3];
652 case 3: seta.sig[5] = (oldset->sig[2] >> 32);
653 seta.sig[4] = oldset->sig[2];
654 case 2: seta.sig[3] = (oldset->sig[1] >> 32);
655 seta.sig[2] = oldset->sig[1];
656 case 1: seta.sig[1] = (oldset->sig[0] >> 32);
657 seta.sig[0] = oldset->sig[0];
658 }
659 err |= __copy_to_user(&sf->mask, &seta, sizeof(compat_sigset_t));
660
David S. Miller55984732011-08-20 17:14:54 -0700661 if (!wsaved) {
662 err |= copy_in_user((u32 __user *)sf,
663 (u32 __user *)(regs->u_regs[UREG_FP]),
664 sizeof(struct reg_window32));
665 } else {
666 struct reg_window *rp;
667
668 rp = &current_thread_info()->reg_window[wsaved - 1];
669 for (i = 0; i < 8; i++)
670 err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
671 for (i = 0; i < 6; i++)
672 err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
673 err |= __put_user(rp->ins[6], &sf->ss.fp);
674 err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
675 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 if (err)
677 goto sigsegv;
678
679 /* 3. signal handler back-trampoline and parameters */
680 regs->u_regs[UREG_FP] = (unsigned long) sf;
681 regs->u_regs[UREG_I0] = signr;
682 regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
683 regs->u_regs[UREG_I2] = (unsigned long) &sf->regs;
684
685 /* 4. signal handler */
686 regs->tpc = (unsigned long) ka->sa.sa_handler;
687 regs->tnpc = (regs->tpc + 4);
688 if (test_thread_flag(TIF_32BIT)) {
689 regs->tpc &= 0xffffffff;
690 regs->tnpc &= 0xffffffff;
691 }
692
693 /* 5. return to kernel instructions */
694 if (ka->ka_restorer)
695 regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
696 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 unsigned long address = ((unsigned long)&(sf->insns[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
699 regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
700
701 /* mov __NR_rt_sigreturn, %g1 */
702 err |= __put_user(0x82102065, &sf->insns[0]);
703
704 /* t 0x10 */
705 err |= __put_user(0x91d02010, &sf->insns[1]);
706 if (err)
707 goto sigsegv;
708
David S. Miller05c5e762010-09-20 23:24:52 -0700709 flush_signal_insns(address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 }
David S. Miller392c2182010-09-21 21:41:12 -0700711 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
713sigill:
714 do_exit(SIGILL);
David S. Miller392c2182010-09-21 21:41:12 -0700715 return -EINVAL;
716
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717sigsegv:
718 force_sigsegv(signr, current);
David S. Miller392c2182010-09-21 21:41:12 -0700719 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720}
721
Al Viroa610d6e2012-05-21 23:42:15 -0400722static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
David S. Miller392c2182010-09-21 21:41:12 -0700723 siginfo_t *info,
724 sigset_t *oldset, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725{
David S. Miller392c2182010-09-21 21:41:12 -0700726 int err;
727
David S. Millerec98c6b2008-04-20 02:14:23 -0700728 if (ka->sa.sa_flags & SA_SIGINFO)
David S. Miller392c2182010-09-21 21:41:12 -0700729 err = setup_rt_frame32(ka, regs, signr, oldset, info);
David S. Millerec98c6b2008-04-20 02:14:23 -0700730 else
David S. Miller392c2182010-09-21 21:41:12 -0700731 err = setup_frame32(ka, regs, signr, oldset);
732
733 if (err)
Al Viroa610d6e2012-05-21 23:42:15 -0400734 return;
David S. Miller5526b7e2008-04-27 02:26:36 -0700735
Al Viroefee9842012-04-28 02:04:15 -0400736 signal_delivered(signr, info, ka, regs, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737}
738
739static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs,
740 struct sigaction *sa)
741{
742 switch (regs->u_regs[UREG_I0]) {
743 case ERESTART_RESTARTBLOCK:
744 case ERESTARTNOHAND:
745 no_system_call_restart:
746 regs->u_regs[UREG_I0] = EINTR;
747 regs->tstate |= TSTATE_ICARRY;
748 break;
749 case ERESTARTSYS:
750 if (!(sa->sa_flags & SA_RESTART))
751 goto no_system_call_restart;
752 /* fallthrough */
753 case ERESTARTNOINTR:
754 regs->u_regs[UREG_I0] = orig_i0;
755 regs->tpc -= 4;
756 regs->tnpc -= 4;
757 }
758}
759
760/* Note that 'init' is a special process: it doesn't get signals it doesn't
761 * want to handle. Thus you cannot kill init even with a SIGKILL even by
762 * mistake.
763 */
David S. Miller1d299bc2011-11-14 20:32:16 -0800764void do_signal32(sigset_t *oldset, struct pt_regs * regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 struct k_sigaction ka;
David S. Miller1d299bc2011-11-14 20:32:16 -0800767 unsigned long orig_i0;
768 int restart_syscall;
David S. Miller238468b2008-04-24 03:01:48 -0700769 siginfo_t info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 int signr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
David S. Miller28e61032008-05-11 02:07:19 -0700772 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
773
David S. Miller1d299bc2011-11-14 20:32:16 -0800774 restart_syscall = 0;
775 orig_i0 = 0;
776 if (pt_regs_is_syscall(regs) &&
777 (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
778 restart_syscall = 1;
David S. Millere88d2462011-11-15 12:57:00 -0800779 orig_i0 = regs->u_regs[UREG_G6];
David S. Miller1d299bc2011-11-14 20:32:16 -0800780 }
David S. Miller28e61032008-05-11 02:07:19 -0700781
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (signr > 0) {
David S. Miller28e61032008-05-11 02:07:19 -0700783 if (restart_syscall)
784 syscall_restart32(orig_i0, regs, &ka.sa);
Al Viroa610d6e2012-05-21 23:42:15 -0400785 handle_signal32(signr, &ka, &info, oldset, regs);
David S. Miller2d7d5f02006-01-19 02:42:49 -0800786 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 }
David S. Miller28e61032008-05-11 02:07:19 -0700788 if (restart_syscall &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
790 regs->u_regs[UREG_I0] == ERESTARTSYS ||
791 regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
792 /* replay the system call when we are done */
David S. Miller28e61032008-05-11 02:07:19 -0700793 regs->u_regs[UREG_I0] = orig_i0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 regs->tpc -= 4;
795 regs->tnpc -= 4;
David S. Millerc2785252010-09-21 22:30:13 -0700796 pt_regs_clear_syscall(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 }
David S. Miller28e61032008-05-11 02:07:19 -0700798 if (restart_syscall &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
800 regs->u_regs[UREG_G1] = __NR_restart_syscall;
801 regs->tpc -= 4;
802 regs->tnpc -= 4;
David S. Millerc2785252010-09-21 22:30:13 -0700803 pt_regs_clear_syscall(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 }
David S. Miller2d7d5f02006-01-19 02:42:49 -0800805
David S. Miller9a28dbf2008-05-12 22:45:15 -0700806 /* If there's no signal to deliver, we just put the saved sigmask
David S. Miller2d7d5f02006-01-19 02:42:49 -0800807 * back
808 */
Al Viro51a7b442012-05-21 23:33:55 -0400809 restore_saved_sigmask();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810}
811
812struct sigstack32 {
813 u32 the_stack;
814 int cur_status;
815};
816
817asmlinkage int do_sys32_sigstack(u32 u_ssptr, u32 u_ossptr, unsigned long sp)
818{
819 struct sigstack32 __user *ssptr =
820 (struct sigstack32 __user *)((unsigned long)(u_ssptr));
821 struct sigstack32 __user *ossptr =
822 (struct sigstack32 __user *)((unsigned long)(u_ossptr));
823 int ret = -EFAULT;
824
825 /* First see if old state is wanted. */
826 if (ossptr) {
827 if (put_user(current->sas_ss_sp + current->sas_ss_size,
828 &ossptr->the_stack) ||
829 __put_user(on_sig_stack(sp), &ossptr->cur_status))
830 goto out;
831 }
832
833 /* Now see if we want to update the new state. */
834 if (ssptr) {
835 u32 ss_sp;
836
837 if (get_user(ss_sp, &ssptr->the_stack))
838 goto out;
839
840 /* If the current stack was set with sigaltstack, don't
841 * swap stacks while we are on it.
842 */
843 ret = -EPERM;
844 if (current->sas_ss_sp && on_sig_stack(sp))
845 goto out;
846
847 /* Since we don't know the extent of the stack, and we don't
848 * track onstack-ness, but rather calculate it, we must
849 * presume a size. Ho hum this interface is lossy.
850 */
851 current->sas_ss_sp = (unsigned long)ss_sp - SIGSTKSZ;
852 current->sas_ss_size = SIGSTKSZ;
853 }
854
855 ret = 0;
856out:
857 return ret;
858}
859
860asmlinkage long do_sys32_sigaltstack(u32 ussa, u32 uossa, unsigned long sp)
861{
862 stack_t uss, uoss;
863 u32 u_ss_sp = 0;
864 int ret;
865 mm_segment_t old_fs;
866 stack_t32 __user *uss32 = compat_ptr(ussa);
867 stack_t32 __user *uoss32 = compat_ptr(uossa);
868
869 if (ussa && (get_user(u_ss_sp, &uss32->ss_sp) ||
870 __get_user(uss.ss_flags, &uss32->ss_flags) ||
871 __get_user(uss.ss_size, &uss32->ss_size)))
872 return -EFAULT;
873 uss.ss_sp = compat_ptr(u_ss_sp);
874 old_fs = get_fs();
875 set_fs(KERNEL_DS);
876 ret = do_sigaltstack(ussa ? (stack_t __user *) &uss : NULL,
877 uossa ? (stack_t __user *) &uoss : NULL, sp);
878 set_fs(old_fs);
879 if (!ret && uossa && (put_user(ptr_to_compat(uoss.ss_sp), &uoss32->ss_sp) ||
880 __put_user(uoss.ss_flags, &uoss32->ss_flags) ||
881 __put_user(uoss.ss_size, &uoss32->ss_size)))
882 return -EFAULT;
883 return ret;
884}