]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * IA32 Architecture-specific signal handling support. | |
3 | * | |
4 | * Copyright (C) 1999, 2001-2002, 2005 Hewlett-Packard Co | |
5 | * David Mosberger-Tang <davidm@hpl.hp.com> | |
6 | * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> | |
7 | * Copyright (C) 2000 VA Linux Co | |
8 | * Copyright (C) 2000 Don Dugger <n0ano@valinux.com> | |
9 | * | |
10 | * Derived from i386 and Alpha versions. | |
11 | */ | |
12 | ||
13 | #include <linux/errno.h> | |
14 | #include <linux/kernel.h> | |
15 | #include <linux/mm.h> | |
16 | #include <linux/personality.h> | |
17 | #include <linux/ptrace.h> | |
18 | #include <linux/sched.h> | |
19 | #include <linux/signal.h> | |
20 | #include <linux/smp.h> | |
1da177e4 LT |
21 | #include <linux/stddef.h> |
22 | #include <linux/syscalls.h> | |
23 | #include <linux/unistd.h> | |
24 | #include <linux/wait.h> | |
25 | #include <linux/compat.h> | |
26 | ||
27 | #include <asm/intrinsics.h> | |
28 | #include <asm/uaccess.h> | |
29 | #include <asm/rse.h> | |
30 | #include <asm/sigcontext.h> | |
1da177e4 LT |
31 | |
32 | #include "ia32priv.h" | |
33 | ||
34 | #include "../kernel/sigframe.h" | |
35 | ||
36 | #define A(__x) ((unsigned long)(__x)) | |
37 | ||
38 | #define DEBUG_SIG 0 | |
39 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | |
40 | ||
41 | #define __IA32_NR_sigreturn 119 | |
42 | #define __IA32_NR_rt_sigreturn 173 | |
43 | ||
44 | struct sigframe_ia32 | |
45 | { | |
46 | int pretcode; | |
47 | int sig; | |
48 | struct sigcontext_ia32 sc; | |
49 | struct _fpstate_ia32 fpstate; | |
50 | unsigned int extramask[_COMPAT_NSIG_WORDS-1]; | |
51 | char retcode[8]; | |
52 | }; | |
53 | ||
54 | struct rt_sigframe_ia32 | |
55 | { | |
56 | int pretcode; | |
57 | int sig; | |
58 | int pinfo; | |
59 | int puc; | |
60 | compat_siginfo_t info; | |
61 | struct ucontext_ia32 uc; | |
62 | struct _fpstate_ia32 fpstate; | |
63 | char retcode[8]; | |
64 | }; | |
65 | ||
66 | int | |
67 | copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from) | |
68 | { | |
69 | unsigned long tmp; | |
70 | int err; | |
71 | ||
72 | if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t))) | |
73 | return -EFAULT; | |
74 | ||
75 | err = __get_user(to->si_signo, &from->si_signo); | |
76 | err |= __get_user(to->si_errno, &from->si_errno); | |
77 | err |= __get_user(to->si_code, &from->si_code); | |
78 | ||
79 | if (to->si_code < 0) | |
80 | err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); | |
81 | else { | |
82 | switch (to->si_code >> 16) { | |
83 | case __SI_CHLD >> 16: | |
84 | err |= __get_user(to->si_utime, &from->si_utime); | |
85 | err |= __get_user(to->si_stime, &from->si_stime); | |
86 | err |= __get_user(to->si_status, &from->si_status); | |
87 | default: | |
88 | err |= __get_user(to->si_pid, &from->si_pid); | |
89 | err |= __get_user(to->si_uid, &from->si_uid); | |
90 | break; | |
91 | case __SI_FAULT >> 16: | |
92 | err |= __get_user(tmp, &from->si_addr); | |
93 | to->si_addr = (void __user *) tmp; | |
94 | break; | |
95 | case __SI_POLL >> 16: | |
96 | err |= __get_user(to->si_band, &from->si_band); | |
97 | err |= __get_user(to->si_fd, &from->si_fd); | |
98 | break; | |
99 | case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ | |
100 | case __SI_MESGQ >> 16: | |
101 | err |= __get_user(to->si_pid, &from->si_pid); | |
102 | err |= __get_user(to->si_uid, &from->si_uid); | |
103 | err |= __get_user(to->si_int, &from->si_int); | |
104 | break; | |
105 | } | |
106 | } | |
107 | return err; | |
108 | } | |
109 | ||
110 | int | |
111 | copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from) | |
112 | { | |
113 | unsigned int addr; | |
114 | int err; | |
115 | ||
116 | if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t))) | |
117 | return -EFAULT; | |
118 | ||
119 | /* If you change siginfo_t structure, please be sure | |
120 | this code is fixed accordingly. | |
121 | It should never copy any pad contained in the structure | |
122 | to avoid security leaks, but must copy the generic | |
123 | 3 ints plus the relevant union member. | |
124 | This routine must convert siginfo from 64bit to 32bit as well | |
125 | at the same time. */ | |
126 | err = __put_user(from->si_signo, &to->si_signo); | |
127 | err |= __put_user(from->si_errno, &to->si_errno); | |
128 | err |= __put_user((short)from->si_code, &to->si_code); | |
129 | if (from->si_code < 0) | |
130 | err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); | |
131 | else { | |
132 | switch (from->si_code >> 16) { | |
133 | case __SI_CHLD >> 16: | |
134 | err |= __put_user(from->si_utime, &to->si_utime); | |
135 | err |= __put_user(from->si_stime, &to->si_stime); | |
136 | err |= __put_user(from->si_status, &to->si_status); | |
137 | default: | |
138 | err |= __put_user(from->si_pid, &to->si_pid); | |
139 | err |= __put_user(from->si_uid, &to->si_uid); | |
140 | break; | |
141 | case __SI_FAULT >> 16: | |
142 | /* avoid type-checking warnings by copying _pad[0] in lieu of si_addr... */ | |
143 | err |= __put_user(from->_sifields._pad[0], &to->si_addr); | |
144 | break; | |
145 | case __SI_POLL >> 16: | |
146 | err |= __put_user(from->si_band, &to->si_band); | |
147 | err |= __put_user(from->si_fd, &to->si_fd); | |
148 | break; | |
149 | case __SI_TIMER >> 16: | |
150 | err |= __put_user(from->si_tid, &to->si_tid); | |
151 | err |= __put_user(from->si_overrun, &to->si_overrun); | |
152 | addr = (unsigned long) from->si_ptr; | |
153 | err |= __put_user(addr, &to->si_ptr); | |
154 | break; | |
155 | case __SI_RT >> 16: /* Not generated by the kernel as of now. */ | |
156 | case __SI_MESGQ >> 16: | |
157 | err |= __put_user(from->si_uid, &to->si_uid); | |
158 | err |= __put_user(from->si_pid, &to->si_pid); | |
159 | addr = (unsigned long) from->si_ptr; | |
160 | err |= __put_user(addr, &to->si_ptr); | |
161 | break; | |
162 | } | |
163 | } | |
164 | return err; | |
165 | } | |
166 | ||
167 | ||
168 | /* | |
169 | * SAVE and RESTORE of ia32 fpstate info, from ia64 current state | |
170 | * Used in exception handler to pass the fpstate to the user, and restore | |
171 | * the fpstate while returning from the exception handler. | |
172 | * | |
173 | * fpstate info and their mapping to IA64 regs: | |
174 | * fpstate REG(BITS) Attribute Comments | |
175 | * cw ar.fcr(0:12) with bits 7 and 6 not used | |
176 | * sw ar.fsr(0:15) | |
177 | * tag ar.fsr(16:31) with odd numbered bits not used | |
178 | * (read returns 0, writes ignored) | |
179 | * ipoff ar.fir(0:31) | |
180 | * cssel ar.fir(32:47) | |
181 | * dataoff ar.fdr(0:31) | |
182 | * datasel ar.fdr(32:47) | |
183 | * | |
184 | * _st[(0+TOS)%8] f8 | |
185 | * _st[(1+TOS)%8] f9 | |
186 | * _st[(2+TOS)%8] f10 | |
187 | * _st[(3+TOS)%8] f11 (f8..f11 from ptregs) | |
188 | * : : : (f12..f15 from live reg) | |
189 | * : : : | |
190 | * _st[(7+TOS)%8] f15 TOS=sw.top(bits11:13) | |
191 | * | |
192 | * status Same as sw RO | |
193 | * magic 0 as X86_FXSR_MAGIC in ia32 | |
194 | * mxcsr Bits(7:15)=ar.fcr(39:47) | |
195 | * Bits(0:5) =ar.fsr(32:37) with bit 6 reserved | |
196 | * _xmm[0..7] f16..f31 (live registers) | |
197 | * with _xmm[0] | |
198 | * Bit(64:127)=f17(0:63) | |
199 | * Bit(0:63)=f16(0:63) | |
200 | * All other fields unused... | |
201 | */ | |
202 | ||
203 | static int | |
204 | save_ia32_fpstate_live (struct _fpstate_ia32 __user *save) | |
205 | { | |
206 | struct task_struct *tsk = current; | |
207 | struct pt_regs *ptp; | |
208 | struct _fpreg_ia32 *fpregp; | |
209 | char buf[32]; | |
210 | unsigned long fsr, fcr, fir, fdr; | |
211 | unsigned long new_fsr; | |
212 | unsigned long num128[2]; | |
213 | unsigned long mxcsr=0; | |
214 | int fp_tos, fr8_st_map; | |
215 | ||
216 | if (!access_ok(VERIFY_WRITE, save, sizeof(*save))) | |
217 | return -EFAULT; | |
218 | ||
219 | /* Read in fsr, fcr, fir, fdr and copy onto fpstate */ | |
220 | fsr = ia64_getreg(_IA64_REG_AR_FSR); | |
221 | fcr = ia64_getreg(_IA64_REG_AR_FCR); | |
222 | fir = ia64_getreg(_IA64_REG_AR_FIR); | |
223 | fdr = ia64_getreg(_IA64_REG_AR_FDR); | |
224 | ||
225 | /* | |
226 | * We need to clear the exception state before calling the signal handler. Clear | |
227 | * the bits 15, bits 0-7 in fp status word. Similar to the functionality of fnclex | |
228 | * instruction. | |
229 | */ | |
230 | new_fsr = fsr & ~0x80ff; | |
231 | ia64_setreg(_IA64_REG_AR_FSR, new_fsr); | |
232 | ||
233 | __put_user(fcr & 0xffff, &save->cw); | |
234 | __put_user(fsr & 0xffff, &save->sw); | |
235 | __put_user((fsr>>16) & 0xffff, &save->tag); | |
236 | __put_user(fir, &save->ipoff); | |
237 | __put_user((fir>>32) & 0xffff, &save->cssel); | |
238 | __put_user(fdr, &save->dataoff); | |
239 | __put_user((fdr>>32) & 0xffff, &save->datasel); | |
240 | __put_user(fsr & 0xffff, &save->status); | |
241 | ||
242 | mxcsr = ((fcr>>32) & 0xff80) | ((fsr>>32) & 0x3f); | |
243 | __put_user(mxcsr & 0xffff, &save->mxcsr); | |
244 | __put_user( 0, &save->magic); //#define X86_FXSR_MAGIC 0x0000 | |
245 | ||
246 | /* | |
247 | * save f8..f11 from pt_regs | |
248 | * save f12..f15 from live register set | |
249 | */ | |
250 | /* | |
251 | * Find the location where f8 has to go in fp reg stack. This depends on | |
252 | * TOP(11:13) field of sw. Other f reg continue sequentially from where f8 maps | |
253 | * to. | |
254 | */ | |
255 | fp_tos = (fsr>>11)&0x7; | |
256 | fr8_st_map = (8-fp_tos)&0x7; | |
6450578f | 257 | ptp = task_pt_regs(tsk); |
1da177e4 LT |
258 | fpregp = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15); |
259 | ia64f2ia32f(fpregp, &ptp->f8); | |
260 | copy_to_user(&save->_st[(0+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); | |
261 | ia64f2ia32f(fpregp, &ptp->f9); | |
262 | copy_to_user(&save->_st[(1+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); | |
263 | ia64f2ia32f(fpregp, &ptp->f10); | |
264 | copy_to_user(&save->_st[(2+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); | |
265 | ia64f2ia32f(fpregp, &ptp->f11); | |
266 | copy_to_user(&save->_st[(3+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); | |
267 | ||
268 | ia64_stfe(fpregp, 12); | |
269 | copy_to_user(&save->_st[(4+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); | |
270 | ia64_stfe(fpregp, 13); | |
271 | copy_to_user(&save->_st[(5+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); | |
272 | ia64_stfe(fpregp, 14); | |
273 | copy_to_user(&save->_st[(6+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); | |
274 | ia64_stfe(fpregp, 15); | |
275 | copy_to_user(&save->_st[(7+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); | |
276 | ||
277 | ia64_stf8(&num128[0], 16); | |
278 | ia64_stf8(&num128[1], 17); | |
279 | copy_to_user(&save->_xmm[0], num128, sizeof(struct _xmmreg_ia32)); | |
280 | ||
281 | ia64_stf8(&num128[0], 18); | |
282 | ia64_stf8(&num128[1], 19); | |
283 | copy_to_user(&save->_xmm[1], num128, sizeof(struct _xmmreg_ia32)); | |
284 | ||
285 | ia64_stf8(&num128[0], 20); | |
286 | ia64_stf8(&num128[1], 21); | |
287 | copy_to_user(&save->_xmm[2], num128, sizeof(struct _xmmreg_ia32)); | |
288 | ||
289 | ia64_stf8(&num128[0], 22); | |
290 | ia64_stf8(&num128[1], 23); | |
291 | copy_to_user(&save->_xmm[3], num128, sizeof(struct _xmmreg_ia32)); | |
292 | ||
293 | ia64_stf8(&num128[0], 24); | |
294 | ia64_stf8(&num128[1], 25); | |
295 | copy_to_user(&save->_xmm[4], num128, sizeof(struct _xmmreg_ia32)); | |
296 | ||
297 | ia64_stf8(&num128[0], 26); | |
298 | ia64_stf8(&num128[1], 27); | |
299 | copy_to_user(&save->_xmm[5], num128, sizeof(struct _xmmreg_ia32)); | |
300 | ||
301 | ia64_stf8(&num128[0], 28); | |
302 | ia64_stf8(&num128[1], 29); | |
303 | copy_to_user(&save->_xmm[6], num128, sizeof(struct _xmmreg_ia32)); | |
304 | ||
305 | ia64_stf8(&num128[0], 30); | |
306 | ia64_stf8(&num128[1], 31); | |
307 | copy_to_user(&save->_xmm[7], num128, sizeof(struct _xmmreg_ia32)); | |
308 | return 0; | |
309 | } | |
310 | ||
311 | static int | |
312 | restore_ia32_fpstate_live (struct _fpstate_ia32 __user *save) | |
313 | { | |
314 | struct task_struct *tsk = current; | |
315 | struct pt_regs *ptp; | |
316 | unsigned int lo, hi; | |
317 | unsigned long num128[2]; | |
318 | unsigned long num64, mxcsr; | |
319 | struct _fpreg_ia32 *fpregp; | |
320 | char buf[32]; | |
321 | unsigned long fsr, fcr, fir, fdr; | |
322 | int fp_tos, fr8_st_map; | |
323 | ||
324 | if (!access_ok(VERIFY_READ, save, sizeof(*save))) | |
325 | return(-EFAULT); | |
326 | ||
327 | /* | |
328 | * Updating fsr, fcr, fir, fdr. | |
329 | * Just a bit more complicated than save. | |
330 | * - Need to make sure that we don't write any value other than the | |
331 | * specific fpstate info | |
332 | * - Need to make sure that the untouched part of frs, fdr, fir, fcr | |
333 | * should remain same while writing. | |
334 | * So, we do a read, change specific fields and write. | |
335 | */ | |
336 | fsr = ia64_getreg(_IA64_REG_AR_FSR); | |
337 | fcr = ia64_getreg(_IA64_REG_AR_FCR); | |
338 | fir = ia64_getreg(_IA64_REG_AR_FIR); | |
339 | fdr = ia64_getreg(_IA64_REG_AR_FDR); | |
340 | ||
341 | __get_user(mxcsr, (unsigned int __user *)&save->mxcsr); | |
342 | /* setting bits 0..5 8..12 with cw and 39..47 from mxcsr */ | |
343 | __get_user(lo, (unsigned int __user *)&save->cw); | |
344 | num64 = mxcsr & 0xff10; | |
345 | num64 = (num64 << 32) | (lo & 0x1f3f); | |
346 | fcr = (fcr & (~0xff1000001f3fUL)) | num64; | |
347 | ||
348 | /* setting bits 0..31 with sw and tag and 32..37 from mxcsr */ | |
349 | __get_user(lo, (unsigned int __user *)&save->sw); | |
350 | /* set bits 15,7 (fsw.b, fsw.es) to reflect the current error status */ | |
351 | if ( !(lo & 0x7f) ) | |
352 | lo &= (~0x8080); | |
353 | __get_user(hi, (unsigned int __user *)&save->tag); | |
354 | num64 = mxcsr & 0x3f; | |
355 | num64 = (num64 << 16) | (hi & 0xffff); | |
356 | num64 = (num64 << 16) | (lo & 0xffff); | |
357 | fsr = (fsr & (~0x3fffffffffUL)) | num64; | |
358 | ||
359 | /* setting bits 0..47 with cssel and ipoff */ | |
360 | __get_user(lo, (unsigned int __user *)&save->ipoff); | |
361 | __get_user(hi, (unsigned int __user *)&save->cssel); | |
362 | num64 = hi & 0xffff; | |
363 | num64 = (num64 << 32) | lo; | |
364 | fir = (fir & (~0xffffffffffffUL)) | num64; | |
365 | ||
366 | /* setting bits 0..47 with datasel and dataoff */ | |
367 | __get_user(lo, (unsigned int __user *)&save->dataoff); | |
368 | __get_user(hi, (unsigned int __user *)&save->datasel); | |
369 | num64 = hi & 0xffff; | |
370 | num64 = (num64 << 32) | lo; | |
371 | fdr = (fdr & (~0xffffffffffffUL)) | num64; | |
372 | ||
373 | ia64_setreg(_IA64_REG_AR_FSR, fsr); | |
374 | ia64_setreg(_IA64_REG_AR_FCR, fcr); | |
375 | ia64_setreg(_IA64_REG_AR_FIR, fir); | |
376 | ia64_setreg(_IA64_REG_AR_FDR, fdr); | |
377 | ||
378 | /* | |
379 | * restore f8..f11 onto pt_regs | |
380 | * restore f12..f15 onto live registers | |
381 | */ | |
382 | /* | |
383 | * Find the location where f8 has to go in fp reg stack. This depends on | |
384 | * TOP(11:13) field of sw. Other f reg continue sequentially from where f8 maps | |
385 | * to. | |
386 | */ | |
387 | fp_tos = (fsr>>11)&0x7; | |
388 | fr8_st_map = (8-fp_tos)&0x7; | |
389 | fpregp = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15); | |
390 | ||
6450578f | 391 | ptp = task_pt_regs(tsk); |
1da177e4 LT |
392 | copy_from_user(fpregp, &save->_st[(0+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); |
393 | ia32f2ia64f(&ptp->f8, fpregp); | |
394 | copy_from_user(fpregp, &save->_st[(1+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); | |
395 | ia32f2ia64f(&ptp->f9, fpregp); | |
396 | copy_from_user(fpregp, &save->_st[(2+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); | |
397 | ia32f2ia64f(&ptp->f10, fpregp); | |
398 | copy_from_user(fpregp, &save->_st[(3+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); | |
399 | ia32f2ia64f(&ptp->f11, fpregp); | |
400 | ||
401 | copy_from_user(fpregp, &save->_st[(4+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); | |
402 | ia64_ldfe(12, fpregp); | |
403 | copy_from_user(fpregp, &save->_st[(5+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); | |
404 | ia64_ldfe(13, fpregp); | |
405 | copy_from_user(fpregp, &save->_st[(6+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); | |
406 | ia64_ldfe(14, fpregp); | |
407 | copy_from_user(fpregp, &save->_st[(7+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); | |
408 | ia64_ldfe(15, fpregp); | |
409 | ||
410 | copy_from_user(num128, &save->_xmm[0], sizeof(struct _xmmreg_ia32)); | |
411 | ia64_ldf8(16, &num128[0]); | |
412 | ia64_ldf8(17, &num128[1]); | |
413 | ||
414 | copy_from_user(num128, &save->_xmm[1], sizeof(struct _xmmreg_ia32)); | |
415 | ia64_ldf8(18, &num128[0]); | |
416 | ia64_ldf8(19, &num128[1]); | |
417 | ||
418 | copy_from_user(num128, &save->_xmm[2], sizeof(struct _xmmreg_ia32)); | |
419 | ia64_ldf8(20, &num128[0]); | |
420 | ia64_ldf8(21, &num128[1]); | |
421 | ||
422 | copy_from_user(num128, &save->_xmm[3], sizeof(struct _xmmreg_ia32)); | |
423 | ia64_ldf8(22, &num128[0]); | |
424 | ia64_ldf8(23, &num128[1]); | |
425 | ||
426 | copy_from_user(num128, &save->_xmm[4], sizeof(struct _xmmreg_ia32)); | |
427 | ia64_ldf8(24, &num128[0]); | |
428 | ia64_ldf8(25, &num128[1]); | |
429 | ||
430 | copy_from_user(num128, &save->_xmm[5], sizeof(struct _xmmreg_ia32)); | |
431 | ia64_ldf8(26, &num128[0]); | |
432 | ia64_ldf8(27, &num128[1]); | |
433 | ||
434 | copy_from_user(num128, &save->_xmm[6], sizeof(struct _xmmreg_ia32)); | |
435 | ia64_ldf8(28, &num128[0]); | |
436 | ia64_ldf8(29, &num128[1]); | |
437 | ||
438 | copy_from_user(num128, &save->_xmm[7], sizeof(struct _xmmreg_ia32)); | |
439 | ia64_ldf8(30, &num128[0]); | |
440 | ia64_ldf8(31, &num128[1]); | |
441 | return 0; | |
442 | } | |
443 | ||
444 | static inline void | |
445 | sigact_set_handler (struct k_sigaction *sa, unsigned int handler, unsigned int restorer) | |
446 | { | |
447 | if (handler + 1 <= 2) | |
448 | /* SIG_DFL, SIG_IGN, or SIG_ERR: must sign-extend to 64-bits */ | |
449 | sa->sa.sa_handler = (__sighandler_t) A((int) handler); | |
450 | else | |
451 | sa->sa.sa_handler = (__sighandler_t) (((unsigned long) restorer << 32) | handler); | |
452 | } | |
453 | ||
454 | long | |
455 | __ia32_rt_sigsuspend (compat_sigset_t *sset, unsigned int sigsetsize, struct sigscratch *scr) | |
456 | { | |
457 | extern long ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall); | |
458 | sigset_t oldset, set; | |
459 | ||
460 | scr->scratch_unat = 0; /* avoid leaking kernel bits to user level */ | |
71306671 | 461 | memset(&set, 0, sizeof(set)); |
1da177e4 | 462 | |
71306671 | 463 | memcpy(&set.sig, &sset->sig, sigsetsize); |
1da177e4 LT |
464 | |
465 | sigdelsetmask(&set, ~_BLOCKABLE); | |
466 | ||
467 | spin_lock_irq(¤t->sighand->siglock); | |
468 | { | |
469 | oldset = current->blocked; | |
470 | current->blocked = set; | |
471 | recalc_sigpending(); | |
472 | } | |
473 | spin_unlock_irq(¤t->sighand->siglock); | |
474 | ||
475 | /* | |
476 | * The return below usually returns to the signal handler. We need to pre-set the | |
477 | * correct error code here to ensure that the right values get saved in sigcontext | |
478 | * by ia64_do_signal. | |
479 | */ | |
480 | scr->pt.r8 = -EINTR; | |
481 | while (1) { | |
482 | current->state = TASK_INTERRUPTIBLE; | |
483 | schedule(); | |
484 | if (ia64_do_signal(&oldset, scr, 1)) | |
485 | return -EINTR; | |
486 | } | |
487 | } | |
488 | ||
489 | asmlinkage long | |
490 | ia32_rt_sigsuspend (compat_sigset_t __user *uset, unsigned int sigsetsize, struct sigscratch *scr) | |
491 | { | |
492 | compat_sigset_t set; | |
493 | ||
494 | if (sigsetsize > sizeof(compat_sigset_t)) | |
495 | return -EINVAL; | |
496 | ||
497 | if (copy_from_user(&set.sig, &uset->sig, sigsetsize)) | |
498 | return -EFAULT; | |
499 | ||
500 | return __ia32_rt_sigsuspend(&set, sigsetsize, scr); | |
501 | } | |
502 | ||
503 | asmlinkage long | |
504 | ia32_sigsuspend (unsigned int mask, struct sigscratch *scr) | |
505 | { | |
506 | return __ia32_rt_sigsuspend((compat_sigset_t *) &mask, sizeof(mask), scr); | |
507 | } | |
508 | ||
509 | asmlinkage long | |
510 | sys32_signal (int sig, unsigned int handler) | |
511 | { | |
512 | struct k_sigaction new_sa, old_sa; | |
513 | int ret; | |
514 | ||
515 | sigact_set_handler(&new_sa, handler, 0); | |
516 | new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK; | |
1ff0be15 | 517 | sigemptyset(&new_sa.sa.sa_mask); |
1da177e4 LT |
518 | |
519 | ret = do_sigaction(sig, &new_sa, &old_sa); | |
520 | ||
521 | return ret ? ret : IA32_SA_HANDLER(&old_sa); | |
522 | } | |
523 | ||
524 | asmlinkage long | |
525 | sys32_rt_sigaction (int sig, struct sigaction32 __user *act, | |
526 | struct sigaction32 __user *oact, unsigned int sigsetsize) | |
527 | { | |
528 | struct k_sigaction new_ka, old_ka; | |
529 | unsigned int handler, restorer; | |
530 | int ret; | |
531 | ||
532 | /* XXX: Don't preclude handling different sized sigset_t's. */ | |
533 | if (sigsetsize != sizeof(compat_sigset_t)) | |
534 | return -EINVAL; | |
535 | ||
536 | if (act) { | |
537 | ret = get_user(handler, &act->sa_handler); | |
538 | ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags); | |
539 | ret |= get_user(restorer, &act->sa_restorer); | |
540 | ret |= copy_from_user(&new_ka.sa.sa_mask, &act->sa_mask, sizeof(compat_sigset_t)); | |
541 | if (ret) | |
542 | return -EFAULT; | |
543 | ||
544 | sigact_set_handler(&new_ka, handler, restorer); | |
545 | } | |
546 | ||
547 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | |
548 | ||
549 | if (!ret && oact) { | |
550 | ret = put_user(IA32_SA_HANDLER(&old_ka), &oact->sa_handler); | |
551 | ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags); | |
552 | ret |= put_user(IA32_SA_RESTORER(&old_ka), &oact->sa_restorer); | |
553 | ret |= copy_to_user(&oact->sa_mask, &old_ka.sa.sa_mask, sizeof(compat_sigset_t)); | |
554 | } | |
555 | return ret; | |
556 | } | |
557 | ||
558 | ||
559 | asmlinkage long | |
560 | sys32_rt_sigprocmask (int how, compat_sigset_t __user *set, compat_sigset_t __user *oset, | |
561 | unsigned int sigsetsize) | |
562 | { | |
563 | mm_segment_t old_fs = get_fs(); | |
564 | sigset_t s; | |
565 | long ret; | |
566 | ||
567 | if (sigsetsize > sizeof(s)) | |
568 | return -EINVAL; | |
569 | ||
570 | if (set) { | |
571 | memset(&s, 0, sizeof(s)); | |
572 | if (copy_from_user(&s.sig, set, sigsetsize)) | |
573 | return -EFAULT; | |
574 | } | |
575 | set_fs(KERNEL_DS); | |
576 | ret = sys_rt_sigprocmask(how, | |
577 | set ? (sigset_t __user *) &s : NULL, | |
578 | oset ? (sigset_t __user *) &s : NULL, sizeof(s)); | |
579 | set_fs(old_fs); | |
580 | if (ret) | |
581 | return ret; | |
582 | if (oset) { | |
583 | if (copy_to_user(oset, &s.sig, sigsetsize)) | |
584 | return -EFAULT; | |
585 | } | |
586 | return 0; | |
587 | } | |
588 | ||
589 | asmlinkage long | |
590 | sys32_rt_sigqueueinfo (int pid, int sig, compat_siginfo_t __user *uinfo) | |
591 | { | |
592 | mm_segment_t old_fs = get_fs(); | |
593 | siginfo_t info; | |
594 | int ret; | |
595 | ||
596 | if (copy_siginfo_from_user32(&info, uinfo)) | |
597 | return -EFAULT; | |
598 | set_fs(KERNEL_DS); | |
599 | ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info); | |
600 | set_fs(old_fs); | |
601 | return ret; | |
602 | } | |
603 | ||
604 | asmlinkage long | |
605 | sys32_sigaction (int sig, struct old_sigaction32 __user *act, struct old_sigaction32 __user *oact) | |
606 | { | |
607 | struct k_sigaction new_ka, old_ka; | |
608 | unsigned int handler, restorer; | |
609 | int ret; | |
610 | ||
611 | if (act) { | |
612 | compat_old_sigset_t mask; | |
613 | ||
614 | ret = get_user(handler, &act->sa_handler); | |
615 | ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags); | |
616 | ret |= get_user(restorer, &act->sa_restorer); | |
617 | ret |= get_user(mask, &act->sa_mask); | |
618 | if (ret) | |
619 | return ret; | |
620 | ||
621 | sigact_set_handler(&new_ka, handler, restorer); | |
622 | siginitset(&new_ka.sa.sa_mask, mask); | |
623 | } | |
624 | ||
625 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | |
626 | ||
627 | if (!ret && oact) { | |
628 | ret = put_user(IA32_SA_HANDLER(&old_ka), &oact->sa_handler); | |
629 | ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags); | |
630 | ret |= put_user(IA32_SA_RESTORER(&old_ka), &oact->sa_restorer); | |
631 | ret |= put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | |
632 | } | |
633 | ||
634 | return ret; | |
635 | } | |
636 | ||
637 | static int | |
638 | setup_sigcontext_ia32 (struct sigcontext_ia32 __user *sc, struct _fpstate_ia32 __user *fpstate, | |
639 | struct pt_regs *regs, unsigned long mask) | |
640 | { | |
641 | int err = 0; | |
642 | unsigned long flag; | |
643 | ||
644 | if (!access_ok(VERIFY_WRITE, sc, sizeof(*sc))) | |
645 | return -EFAULT; | |
646 | ||
647 | err |= __put_user((regs->r16 >> 32) & 0xffff, (unsigned int __user *)&sc->fs); | |
648 | err |= __put_user((regs->r16 >> 48) & 0xffff, (unsigned int __user *)&sc->gs); | |
649 | err |= __put_user((regs->r16 >> 16) & 0xffff, (unsigned int __user *)&sc->es); | |
650 | err |= __put_user(regs->r16 & 0xffff, (unsigned int __user *)&sc->ds); | |
651 | err |= __put_user(regs->r15, &sc->edi); | |
652 | err |= __put_user(regs->r14, &sc->esi); | |
653 | err |= __put_user(regs->r13, &sc->ebp); | |
654 | err |= __put_user(regs->r12, &sc->esp); | |
655 | err |= __put_user(regs->r11, &sc->ebx); | |
656 | err |= __put_user(regs->r10, &sc->edx); | |
657 | err |= __put_user(regs->r9, &sc->ecx); | |
658 | err |= __put_user(regs->r8, &sc->eax); | |
659 | #if 0 | |
660 | err |= __put_user(current->tss.trap_no, &sc->trapno); | |
661 | err |= __put_user(current->tss.error_code, &sc->err); | |
662 | #endif | |
663 | err |= __put_user(regs->cr_iip, &sc->eip); | |
664 | err |= __put_user(regs->r17 & 0xffff, (unsigned int __user *)&sc->cs); | |
665 | /* | |
666 | * `eflags' is in an ar register for this context | |
667 | */ | |
668 | flag = ia64_getreg(_IA64_REG_AR_EFLAG); | |
669 | err |= __put_user((unsigned int)flag, &sc->eflags); | |
670 | err |= __put_user(regs->r12, &sc->esp_at_signal); | |
671 | err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int __user *)&sc->ss); | |
672 | ||
673 | if ( save_ia32_fpstate_live(fpstate) < 0 ) | |
674 | err = -EFAULT; | |
675 | else | |
676 | err |= __put_user((u32)(u64)fpstate, &sc->fpstate); | |
677 | ||
678 | #if 0 | |
679 | tmp = save_i387(fpstate); | |
680 | if (tmp < 0) | |
681 | err = 1; | |
682 | else | |
683 | err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate); | |
684 | ||
685 | /* non-iBCS2 extensions.. */ | |
686 | #endif | |
687 | err |= __put_user(mask, &sc->oldmask); | |
688 | #if 0 | |
689 | err |= __put_user(current->tss.cr2, &sc->cr2); | |
690 | #endif | |
691 | return err; | |
692 | } | |
693 | ||
694 | static int | |
695 | restore_sigcontext_ia32 (struct pt_regs *regs, struct sigcontext_ia32 __user *sc, int *peax) | |
696 | { | |
697 | unsigned int err = 0; | |
698 | ||
699 | /* Always make any pending restarted system calls return -EINTR */ | |
700 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | |
701 | ||
702 | if (!access_ok(VERIFY_READ, sc, sizeof(*sc))) | |
703 | return(-EFAULT); | |
704 | ||
705 | #define COPY(ia64x, ia32x) err |= __get_user(regs->ia64x, &sc->ia32x) | |
706 | ||
707 | #define copyseg_gs(tmp) (regs->r16 |= (unsigned long) (tmp) << 48) | |
708 | #define copyseg_fs(tmp) (regs->r16 |= (unsigned long) (tmp) << 32) | |
709 | #define copyseg_cs(tmp) (regs->r17 |= tmp) | |
710 | #define copyseg_ss(tmp) (regs->r17 |= (unsigned long) (tmp) << 16) | |
711 | #define copyseg_es(tmp) (regs->r16 |= (unsigned long) (tmp) << 16) | |
712 | #define copyseg_ds(tmp) (regs->r16 |= tmp) | |
713 | ||
714 | #define COPY_SEG(seg) \ | |
715 | { \ | |
716 | unsigned short tmp; \ | |
717 | err |= __get_user(tmp, &sc->seg); \ | |
718 | copyseg_##seg(tmp); \ | |
719 | } | |
720 | #define COPY_SEG_STRICT(seg) \ | |
721 | { \ | |
722 | unsigned short tmp; \ | |
723 | err |= __get_user(tmp, &sc->seg); \ | |
724 | copyseg_##seg(tmp|3); \ | |
725 | } | |
726 | ||
727 | /* To make COPY_SEGs easier, we zero r16, r17 */ | |
728 | regs->r16 = 0; | |
729 | regs->r17 = 0; | |
730 | ||
731 | COPY_SEG(gs); | |
732 | COPY_SEG(fs); | |
733 | COPY_SEG(es); | |
734 | COPY_SEG(ds); | |
735 | COPY(r15, edi); | |
736 | COPY(r14, esi); | |
737 | COPY(r13, ebp); | |
738 | COPY(r12, esp); | |
739 | COPY(r11, ebx); | |
740 | COPY(r10, edx); | |
741 | COPY(r9, ecx); | |
742 | COPY(cr_iip, eip); | |
743 | COPY_SEG_STRICT(cs); | |
744 | COPY_SEG_STRICT(ss); | |
745 | ia32_load_segment_descriptors(current); | |
746 | { | |
747 | unsigned int tmpflags; | |
748 | unsigned long flag; | |
749 | ||
750 | /* | |
751 | * IA32 `eflags' is not part of `pt_regs', it's in an ar register which | |
752 | * is part of the thread context. Fortunately, we are executing in the | |
753 | * IA32 process's context. | |
754 | */ | |
755 | err |= __get_user(tmpflags, &sc->eflags); | |
756 | flag = ia64_getreg(_IA64_REG_AR_EFLAG); | |
757 | flag &= ~0x40DD5; | |
758 | flag |= (tmpflags & 0x40DD5); | |
759 | ia64_setreg(_IA64_REG_AR_EFLAG, flag); | |
760 | ||
761 | regs->r1 = -1; /* disable syscall checks, r1 is orig_eax */ | |
762 | } | |
763 | ||
764 | { | |
765 | struct _fpstate_ia32 __user *buf = NULL; | |
766 | u32 fpstate_ptr; | |
767 | err |= get_user(fpstate_ptr, &(sc->fpstate)); | |
768 | buf = compat_ptr(fpstate_ptr); | |
769 | if (buf) { | |
770 | err |= restore_ia32_fpstate_live(buf); | |
771 | } | |
772 | } | |
773 | ||
774 | #if 0 | |
775 | { | |
776 | struct _fpstate * buf; | |
777 | err |= __get_user(buf, &sc->fpstate); | |
778 | if (buf) { | |
779 | if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) | |
780 | goto badframe; | |
781 | err |= restore_i387(buf); | |
782 | } | |
783 | } | |
784 | #endif | |
785 | ||
786 | err |= __get_user(*peax, &sc->eax); | |
787 | return err; | |
788 | ||
789 | #if 0 | |
790 | badframe: | |
791 | return 1; | |
792 | #endif | |
793 | } | |
794 | ||
795 | /* | |
796 | * Determine which stack to use.. | |
797 | */ | |
798 | static inline void __user * | |
799 | get_sigframe (struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) | |
800 | { | |
801 | unsigned long esp; | |
802 | ||
803 | /* Default to using normal stack (truncate off sign-extension of bit 31: */ | |
804 | esp = (unsigned int) regs->r12; | |
805 | ||
806 | /* This is the X/Open sanctioned signal stack switching. */ | |
807 | if (ka->sa.sa_flags & SA_ONSTACK) { | |
808 | if (!on_sig_stack(esp)) | |
809 | esp = current->sas_ss_sp + current->sas_ss_size; | |
810 | } | |
811 | /* Legacy stack switching not supported */ | |
812 | ||
813 | return (void __user *)((esp - frame_size) & -8ul); | |
814 | } | |
815 | ||
816 | static int | |
817 | setup_frame_ia32 (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) | |
818 | { | |
819 | struct exec_domain *ed = current_thread_info()->exec_domain; | |
820 | struct sigframe_ia32 __user *frame; | |
821 | int err = 0; | |
822 | ||
823 | frame = get_sigframe(ka, regs, sizeof(*frame)); | |
824 | ||
825 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | |
826 | goto give_sigsegv; | |
827 | ||
828 | err |= __put_user((ed && ed->signal_invmap && sig < 32 | |
829 | ? (int)(ed->signal_invmap[sig]) : sig), &frame->sig); | |
830 | ||
831 | err |= setup_sigcontext_ia32(&frame->sc, &frame->fpstate, regs, set->sig[0]); | |
832 | ||
833 | if (_COMPAT_NSIG_WORDS > 1) | |
834 | err |= __copy_to_user(frame->extramask, (char *) &set->sig + 4, | |
835 | sizeof(frame->extramask)); | |
836 | ||
837 | /* Set up to return from userspace. If provided, use a stub | |
838 | already in userspace. */ | |
839 | if (ka->sa.sa_flags & SA_RESTORER) { | |
840 | unsigned int restorer = IA32_SA_RESTORER(ka); | |
841 | err |= __put_user(restorer, &frame->pretcode); | |
842 | } else { | |
843 | /* Pointing to restorer in ia32 gate page */ | |
844 | err |= __put_user(IA32_GATE_OFFSET, &frame->pretcode); | |
845 | } | |
846 | ||
847 | /* This is popl %eax ; movl $,%eax ; int $0x80 | |
848 | * and there for historical reasons only. | |
849 | * See arch/i386/kernel/signal.c | |
850 | */ | |
851 | ||
852 | err |= __put_user(0xb858, (short __user *)(frame->retcode+0)); | |
853 | err |= __put_user(__IA32_NR_sigreturn, (int __user *)(frame->retcode+2)); | |
854 | err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); | |
855 | ||
856 | if (err) | |
857 | goto give_sigsegv; | |
858 | ||
859 | /* Set up registers for signal handler */ | |
860 | regs->r12 = (unsigned long) frame; | |
861 | regs->cr_iip = IA32_SA_HANDLER(ka); | |
862 | ||
863 | set_fs(USER_DS); | |
864 | ||
865 | #if 0 | |
866 | regs->eflags &= ~TF_MASK; | |
867 | #endif | |
868 | ||
869 | #if 0 | |
870 | printk("SIG deliver (%s:%d): sig=%d sp=%p pc=%lx ra=%x\n", | |
871 | current->comm, current->pid, sig, (void *) frame, regs->cr_iip, frame->pretcode); | |
872 | #endif | |
873 | ||
874 | return 1; | |
875 | ||
876 | give_sigsegv: | |
877 | force_sigsegv(sig, current); | |
878 | return 0; | |
879 | } | |
880 | ||
881 | static int | |
882 | setup_rt_frame_ia32 (int sig, struct k_sigaction *ka, siginfo_t *info, | |
883 | sigset_t *set, struct pt_regs * regs) | |
884 | { | |
885 | struct exec_domain *ed = current_thread_info()->exec_domain; | |
886 | compat_uptr_t pinfo, puc; | |
887 | struct rt_sigframe_ia32 __user *frame; | |
888 | int err = 0; | |
889 | ||
890 | frame = get_sigframe(ka, regs, sizeof(*frame)); | |
891 | ||
892 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | |
893 | goto give_sigsegv; | |
894 | ||
895 | err |= __put_user((ed && ed->signal_invmap | |
896 | && sig < 32 ? ed->signal_invmap[sig] : sig), &frame->sig); | |
897 | ||
898 | pinfo = (long __user) &frame->info; | |
899 | puc = (long __user) &frame->uc; | |
900 | err |= __put_user(pinfo, &frame->pinfo); | |
901 | err |= __put_user(puc, &frame->puc); | |
902 | err |= copy_siginfo_to_user32(&frame->info, info); | |
903 | ||
904 | /* Create the ucontext. */ | |
905 | err |= __put_user(0, &frame->uc.uc_flags); | |
906 | err |= __put_user(0, &frame->uc.uc_link); | |
907 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | |
908 | err |= __put_user(sas_ss_flags(regs->r12), &frame->uc.uc_stack.ss_flags); | |
909 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | |
910 | err |= setup_sigcontext_ia32(&frame->uc.uc_mcontext, &frame->fpstate, regs, set->sig[0]); | |
911 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | |
912 | if (err) | |
913 | goto give_sigsegv; | |
914 | ||
915 | /* Set up to return from userspace. If provided, use a stub | |
916 | already in userspace. */ | |
917 | if (ka->sa.sa_flags & SA_RESTORER) { | |
918 | unsigned int restorer = IA32_SA_RESTORER(ka); | |
919 | err |= __put_user(restorer, &frame->pretcode); | |
920 | } else { | |
921 | /* Pointing to rt_restorer in ia32 gate page */ | |
922 | err |= __put_user(IA32_GATE_OFFSET + 8, &frame->pretcode); | |
923 | } | |
924 | ||
925 | /* This is movl $,%eax ; int $0x80 | |
926 | * and there for historical reasons only. | |
927 | * See arch/i386/kernel/signal.c | |
928 | */ | |
929 | ||
930 | err |= __put_user(0xb8, (char __user *)(frame->retcode+0)); | |
931 | err |= __put_user(__IA32_NR_rt_sigreturn, (int __user *)(frame->retcode+1)); | |
932 | err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); | |
933 | ||
934 | if (err) | |
935 | goto give_sigsegv; | |
936 | ||
937 | /* Set up registers for signal handler */ | |
938 | regs->r12 = (unsigned long) frame; | |
939 | regs->cr_iip = IA32_SA_HANDLER(ka); | |
940 | ||
941 | set_fs(USER_DS); | |
942 | ||
943 | #if 0 | |
944 | regs->eflags &= ~TF_MASK; | |
945 | #endif | |
946 | ||
947 | #if 0 | |
948 | printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%x\n", | |
949 | current->comm, current->pid, (void *) frame, regs->cr_iip, frame->pretcode); | |
950 | #endif | |
951 | ||
952 | return 1; | |
953 | ||
954 | give_sigsegv: | |
955 | force_sigsegv(sig, current); | |
956 | return 0; | |
957 | } | |
958 | ||
959 | int | |
960 | ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info, | |
961 | sigset_t *set, struct pt_regs *regs) | |
962 | { | |
963 | /* Set up the stack frame */ | |
964 | if (ka->sa.sa_flags & SA_SIGINFO) | |
965 | return setup_rt_frame_ia32(sig, ka, info, set, regs); | |
966 | else | |
967 | return setup_frame_ia32(sig, ka, set, regs); | |
968 | } | |
969 | ||
970 | asmlinkage long | |
971 | sys32_sigreturn (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, | |
972 | int arg6, int arg7, struct pt_regs regs) | |
973 | { | |
974 | unsigned long esp = (unsigned int) regs.r12; | |
975 | struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(esp - 8); | |
976 | sigset_t set; | |
977 | int eax; | |
978 | ||
979 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | |
980 | goto badframe; | |
981 | ||
982 | if (__get_user(set.sig[0], &frame->sc.oldmask) | |
983 | || (_COMPAT_NSIG_WORDS > 1 && __copy_from_user((char *) &set.sig + 4, &frame->extramask, | |
984 | sizeof(frame->extramask)))) | |
985 | goto badframe; | |
986 | ||
987 | sigdelsetmask(&set, ~_BLOCKABLE); | |
988 | spin_lock_irq(¤t->sighand->siglock); | |
989 | current->blocked = set; | |
990 | recalc_sigpending(); | |
991 | spin_unlock_irq(¤t->sighand->siglock); | |
992 | ||
993 | if (restore_sigcontext_ia32(®s, &frame->sc, &eax)) | |
994 | goto badframe; | |
995 | return eax; | |
996 | ||
997 | badframe: | |
998 | force_sig(SIGSEGV, current); | |
999 | return 0; | |
1000 | } | |
1001 | ||
1002 | asmlinkage long | |
1003 | sys32_rt_sigreturn (int arg0, int arg1, int arg2, int arg3, int arg4, | |
1004 | int arg5, int arg6, int arg7, struct pt_regs regs) | |
1005 | { | |
1006 | unsigned long esp = (unsigned int) regs.r12; | |
1007 | struct rt_sigframe_ia32 __user *frame = (struct rt_sigframe_ia32 __user *)(esp - 4); | |
1008 | sigset_t set; | |
1009 | int eax; | |
1010 | ||
1011 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | |
1012 | goto badframe; | |
1013 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | |
1014 | goto badframe; | |
1015 | ||
1016 | sigdelsetmask(&set, ~_BLOCKABLE); | |
1017 | spin_lock_irq(¤t->sighand->siglock); | |
1018 | current->blocked = set; | |
1019 | recalc_sigpending(); | |
1020 | spin_unlock_irq(¤t->sighand->siglock); | |
1021 | ||
1022 | if (restore_sigcontext_ia32(®s, &frame->uc.uc_mcontext, &eax)) | |
1023 | goto badframe; | |
1024 | ||
1025 | /* It is more difficult to avoid calling this function than to | |
1026 | call it and ignore errors. */ | |
1027 | do_sigaltstack((stack_t __user *) &frame->uc.uc_stack, NULL, esp); | |
1028 | ||
1029 | return eax; | |
1030 | ||
1031 | badframe: | |
1032 | force_sig(SIGSEGV, current); | |
1033 | return 0; | |
1034 | } |