diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-04-06 03:02:57 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-04-06 03:02:57 -0400 |
commit | f541ae326fa120fa5c57433e4d9a133df212ce41 (patch) | |
tree | bdbd94ec72cfc601118051cb35e8617d55510177 /arch/x86/kernel/signal.c | |
parent | e255357764f92afcafafbd4879b222b8c752065a (diff) | |
parent | 0221c81b1b8eb0cbb6b30a0ced52ead32d2b4e4c (diff) |
Merge branch 'linus' into perfcounters/core-v2
Merge reason: we have gathered quite a few conflicts, need to merge upstream
Conflicts:
arch/powerpc/kernel/Makefile
arch/x86/ia32/ia32entry.S
arch/x86/include/asm/hardirq.h
arch/x86/include/asm/unistd_32.h
arch/x86/include/asm/unistd_64.h
arch/x86/kernel/cpu/common.c
arch/x86/kernel/irq.c
arch/x86/kernel/syscall_table_32.S
arch/x86/mm/iomap_32.c
include/linux/sched.h
kernel/Makefile
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/signal.c')
-rw-r--r-- | arch/x86/kernel/signal.c | 147 |
1 files changed, 72 insertions, 75 deletions
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 4d3441018065..611615a92c90 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c | |||
@@ -187,6 +187,77 @@ setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, | |||
187 | /* | 187 | /* |
188 | * Set up a signal frame. | 188 | * Set up a signal frame. |
189 | */ | 189 | */ |
190 | |||
191 | /* | ||
192 | * Determine which stack to use.. | ||
193 | */ | ||
194 | static unsigned long align_sigframe(unsigned long sp) | ||
195 | { | ||
196 | #ifdef CONFIG_X86_32 | ||
197 | /* | ||
198 | * Align the stack pointer according to the i386 ABI, | ||
199 | * i.e. so that on function entry ((sp + 4) & 15) == 0. | ||
200 | */ | ||
201 | sp = ((sp + 4) & -16ul) - 4; | ||
202 | #else /* !CONFIG_X86_32 */ | ||
203 | sp = round_down(sp, 16) - 8; | ||
204 | #endif | ||
205 | return sp; | ||
206 | } | ||
207 | |||
208 | static inline void __user * | ||
209 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, | ||
210 | void __user **fpstate) | ||
211 | { | ||
212 | /* Default to using normal stack */ | ||
213 | unsigned long sp = regs->sp; | ||
214 | int onsigstack = on_sig_stack(sp); | ||
215 | |||
216 | #ifdef CONFIG_X86_64 | ||
217 | /* redzone */ | ||
218 | sp -= 128; | ||
219 | #endif /* CONFIG_X86_64 */ | ||
220 | |||
221 | if (!onsigstack) { | ||
222 | /* This is the X/Open sanctioned signal stack switching. */ | ||
223 | if (ka->sa.sa_flags & SA_ONSTACK) { | ||
224 | if (current->sas_ss_size) | ||
225 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
226 | } else { | ||
227 | #ifdef CONFIG_X86_32 | ||
228 | /* This is the legacy signal stack switching. */ | ||
229 | if ((regs->ss & 0xffff) != __USER_DS && | ||
230 | !(ka->sa.sa_flags & SA_RESTORER) && | ||
231 | ka->sa.sa_restorer) | ||
232 | sp = (unsigned long) ka->sa.sa_restorer; | ||
233 | #endif /* CONFIG_X86_32 */ | ||
234 | } | ||
235 | } | ||
236 | |||
237 | if (used_math()) { | ||
238 | sp -= sig_xstate_size; | ||
239 | #ifdef CONFIG_X86_64 | ||
240 | sp = round_down(sp, 64); | ||
241 | #endif /* CONFIG_X86_64 */ | ||
242 | *fpstate = (void __user *)sp; | ||
243 | } | ||
244 | |||
245 | sp = align_sigframe(sp - frame_size); | ||
246 | |||
247 | /* | ||
248 | * If we are on the alternate signal stack and would overflow it, don't. | ||
249 | * Return an always-bogus address instead so we will die with SIGSEGV. | ||
250 | */ | ||
251 | if (onsigstack && !likely(on_sig_stack(sp))) | ||
252 | return (void __user *)-1L; | ||
253 | |||
254 | /* save i387 state */ | ||
255 | if (used_math() && save_i387_xstate(*fpstate) < 0) | ||
256 | return (void __user *)-1L; | ||
257 | |||
258 | return (void __user *)sp; | ||
259 | } | ||
260 | |||
190 | #ifdef CONFIG_X86_32 | 261 | #ifdef CONFIG_X86_32 |
191 | static const struct { | 262 | static const struct { |
192 | u16 poplmovl; | 263 | u16 poplmovl; |
@@ -210,54 +281,6 @@ static const struct { | |||
210 | 0 | 281 | 0 |
211 | }; | 282 | }; |
212 | 283 | ||
213 | /* | ||
214 | * Determine which stack to use.. | ||
215 | */ | ||
216 | static inline void __user * | ||
217 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, | ||
218 | void **fpstate) | ||
219 | { | ||
220 | unsigned long sp; | ||
221 | |||
222 | /* Default to using normal stack */ | ||
223 | sp = regs->sp; | ||
224 | |||
225 | /* | ||
226 | * If we are on the alternate signal stack and would overflow it, don't. | ||
227 | * Return an always-bogus address instead so we will die with SIGSEGV. | ||
228 | */ | ||
229 | if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) | ||
230 | return (void __user *) -1L; | ||
231 | |||
232 | /* This is the X/Open sanctioned signal stack switching. */ | ||
233 | if (ka->sa.sa_flags & SA_ONSTACK) { | ||
234 | if (sas_ss_flags(sp) == 0) | ||
235 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
236 | } else { | ||
237 | /* This is the legacy signal stack switching. */ | ||
238 | if ((regs->ss & 0xffff) != __USER_DS && | ||
239 | !(ka->sa.sa_flags & SA_RESTORER) && | ||
240 | ka->sa.sa_restorer) | ||
241 | sp = (unsigned long) ka->sa.sa_restorer; | ||
242 | } | ||
243 | |||
244 | if (used_math()) { | ||
245 | sp = sp - sig_xstate_size; | ||
246 | *fpstate = (struct _fpstate *) sp; | ||
247 | if (save_i387_xstate(*fpstate) < 0) | ||
248 | return (void __user *)-1L; | ||
249 | } | ||
250 | |||
251 | sp -= frame_size; | ||
252 | /* | ||
253 | * Align the stack pointer according to the i386 ABI, | ||
254 | * i.e. so that on function entry ((sp + 4) & 15) == 0. | ||
255 | */ | ||
256 | sp = ((sp + 4) & -16ul) - 4; | ||
257 | |||
258 | return (void __user *) sp; | ||
259 | } | ||
260 | |||
261 | static int | 284 | static int |
262 | __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | 285 | __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, |
263 | struct pt_regs *regs) | 286 | struct pt_regs *regs) |
@@ -388,24 +411,6 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
388 | return 0; | 411 | return 0; |
389 | } | 412 | } |
390 | #else /* !CONFIG_X86_32 */ | 413 | #else /* !CONFIG_X86_32 */ |
391 | /* | ||
392 | * Determine which stack to use.. | ||
393 | */ | ||
394 | static void __user * | ||
395 | get_stack(struct k_sigaction *ka, unsigned long sp, unsigned long size) | ||
396 | { | ||
397 | /* Default to using normal stack - redzone*/ | ||
398 | sp -= 128; | ||
399 | |||
400 | /* This is the X/Open sanctioned signal stack switching. */ | ||
401 | if (ka->sa.sa_flags & SA_ONSTACK) { | ||
402 | if (sas_ss_flags(sp) == 0) | ||
403 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
404 | } | ||
405 | |||
406 | return (void __user *)round_down(sp - size, 64); | ||
407 | } | ||
408 | |||
409 | static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 414 | static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
410 | sigset_t *set, struct pt_regs *regs) | 415 | sigset_t *set, struct pt_regs *regs) |
411 | { | 416 | { |
@@ -414,15 +419,7 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
414 | int err = 0; | 419 | int err = 0; |
415 | struct task_struct *me = current; | 420 | struct task_struct *me = current; |
416 | 421 | ||
417 | if (used_math()) { | 422 | frame = get_sigframe(ka, regs, sizeof(struct rt_sigframe), &fp); |
418 | fp = get_stack(ka, regs->sp, sig_xstate_size); | ||
419 | frame = (void __user *)round_down( | ||
420 | (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; | ||
421 | |||
422 | if (save_i387_xstate(fp) < 0) | ||
423 | return -EFAULT; | ||
424 | } else | ||
425 | frame = get_stack(ka, regs->sp, sizeof(struct rt_sigframe)) - 8; | ||
426 | 423 | ||
427 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 424 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
428 | return -EFAULT; | 425 | return -EFAULT; |