diff options
-rw-r--r-- | arch/ia64/include/asm/siginfo.h | 5 | ||||
-rw-r--r-- | arch/powerpc/include/asm/siginfo.h | 5 | ||||
-rw-r--r-- | arch/x86/ia32/ia32_signal.c | 68 | ||||
-rw-r--r-- | arch/x86/kernel/process_64.c | 4 | ||||
-rw-r--r-- | arch/x86/kernel/ptrace.c | 7 | ||||
-rw-r--r-- | arch/x86/kernel/signal_32.c | 222 | ||||
-rw-r--r-- | arch/x86/kernel/signal_64.c | 207 | ||||
-rw-r--r-- | arch/x86/kernel/traps_32.c | 4 | ||||
-rw-r--r-- | arch/x86/kernel/traps_64.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/vmlinux_64.lds.S | 2 | ||||
-rw-r--r-- | arch/x86/mm/ioremap.c | 2 | ||||
-rw-r--r-- | include/asm-generic/siginfo.h | 2 | ||||
-rw-r--r-- | include/asm-parisc/siginfo.h | 5 | ||||
-rw-r--r-- | include/asm-x86/ptrace.h | 6 | ||||
-rw-r--r-- | include/asm-x86/spinlock.h | 60 | ||||
-rw-r--r-- | include/asm-x86/traps.h | 12 |
16 files changed, 339 insertions, 274 deletions
diff --git a/arch/ia64/include/asm/siginfo.h b/arch/ia64/include/asm/siginfo.h index 9294e4b0c8bc..118d42979003 100644 --- a/arch/ia64/include/asm/siginfo.h +++ b/arch/ia64/include/asm/siginfo.h | |||
@@ -113,11 +113,6 @@ typedef struct siginfo { | |||
113 | #undef NSIGSEGV | 113 | #undef NSIGSEGV |
114 | #define NSIGSEGV 3 | 114 | #define NSIGSEGV 3 |
115 | 115 | ||
116 | /* | ||
117 | * SIGTRAP si_codes | ||
118 | */ | ||
119 | #define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */ | ||
120 | #define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint or watchpoint */ | ||
121 | #undef NSIGTRAP | 116 | #undef NSIGTRAP |
122 | #define NSIGTRAP 4 | 117 | #define NSIGTRAP 4 |
123 | 118 | ||
diff --git a/arch/powerpc/include/asm/siginfo.h b/arch/powerpc/include/asm/siginfo.h index 12f1bce037be..49495b0534ed 100644 --- a/arch/powerpc/include/asm/siginfo.h +++ b/arch/powerpc/include/asm/siginfo.h | |||
@@ -15,11 +15,6 @@ | |||
15 | 15 | ||
16 | #include <asm-generic/siginfo.h> | 16 | #include <asm-generic/siginfo.h> |
17 | 17 | ||
18 | /* | ||
19 | * SIGTRAP si_codes | ||
20 | */ | ||
21 | #define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */ | ||
22 | #define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint or watchpoint */ | ||
23 | #undef NSIGTRAP | 18 | #undef NSIGTRAP |
24 | #define NSIGTRAP 4 | 19 | #define NSIGTRAP 4 |
25 | 20 | ||
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index 8d64c1bc8474..4bc02b23674b 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c | |||
@@ -351,31 +351,28 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, | |||
351 | savesegment(es, tmp); | 351 | savesegment(es, tmp); |
352 | err |= __put_user(tmp, (unsigned int __user *)&sc->es); | 352 | err |= __put_user(tmp, (unsigned int __user *)&sc->es); |
353 | 353 | ||
354 | err |= __put_user((u32)regs->di, &sc->di); | 354 | err |= __put_user(regs->di, &sc->di); |
355 | err |= __put_user((u32)regs->si, &sc->si); | 355 | err |= __put_user(regs->si, &sc->si); |
356 | err |= __put_user((u32)regs->bp, &sc->bp); | 356 | err |= __put_user(regs->bp, &sc->bp); |
357 | err |= __put_user((u32)regs->sp, &sc->sp); | 357 | err |= __put_user(regs->sp, &sc->sp); |
358 | err |= __put_user((u32)regs->bx, &sc->bx); | 358 | err |= __put_user(regs->bx, &sc->bx); |
359 | err |= __put_user((u32)regs->dx, &sc->dx); | 359 | err |= __put_user(regs->dx, &sc->dx); |
360 | err |= __put_user((u32)regs->cx, &sc->cx); | 360 | err |= __put_user(regs->cx, &sc->cx); |
361 | err |= __put_user((u32)regs->ax, &sc->ax); | 361 | err |= __put_user(regs->ax, &sc->ax); |
362 | err |= __put_user((u32)regs->cs, &sc->cs); | 362 | err |= __put_user(regs->cs, &sc->cs); |
363 | err |= __put_user((u32)regs->ss, &sc->ss); | 363 | err |= __put_user(regs->ss, &sc->ss); |
364 | err |= __put_user(current->thread.trap_no, &sc->trapno); | 364 | err |= __put_user(current->thread.trap_no, &sc->trapno); |
365 | err |= __put_user(current->thread.error_code, &sc->err); | 365 | err |= __put_user(current->thread.error_code, &sc->err); |
366 | err |= __put_user((u32)regs->ip, &sc->ip); | 366 | err |= __put_user(regs->ip, &sc->ip); |
367 | err |= __put_user((u32)regs->flags, &sc->flags); | 367 | err |= __put_user(regs->flags, &sc->flags); |
368 | err |= __put_user((u32)regs->sp, &sc->sp_at_signal); | 368 | err |= __put_user(regs->sp, &sc->sp_at_signal); |
369 | 369 | ||
370 | tmp = save_i387_xstate_ia32(fpstate); | 370 | tmp = save_i387_xstate_ia32(fpstate); |
371 | if (tmp < 0) | 371 | if (tmp < 0) |
372 | err = -EFAULT; | 372 | err = -EFAULT; |
373 | else { | 373 | else |
374 | clear_used_math(); | ||
375 | stts(); | ||
376 | err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL), | 374 | err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL), |
377 | &sc->fpstate); | 375 | &sc->fpstate); |
378 | } | ||
379 | 376 | ||
380 | /* non-iBCS2 extensions.. */ | 377 | /* non-iBCS2 extensions.. */ |
381 | err |= __put_user(mask, &sc->oldmask); | 378 | err |= __put_user(mask, &sc->oldmask); |
@@ -444,21 +441,18 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
444 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); | 441 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
445 | 442 | ||
446 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 443 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
447 | goto give_sigsegv; | 444 | return -EFAULT; |
448 | 445 | ||
449 | err |= __put_user(sig, &frame->sig); | 446 | if (__put_user(sig, &frame->sig)) |
450 | if (err) | 447 | return -EFAULT; |
451 | goto give_sigsegv; | ||
452 | 448 | ||
453 | err |= ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]); | 449 | if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0])) |
454 | if (err) | 450 | return -EFAULT; |
455 | goto give_sigsegv; | ||
456 | 451 | ||
457 | if (_COMPAT_NSIG_WORDS > 1) { | 452 | if (_COMPAT_NSIG_WORDS > 1) { |
458 | err |= __copy_to_user(frame->extramask, &set->sig[1], | 453 | if (__copy_to_user(frame->extramask, &set->sig[1], |
459 | sizeof(frame->extramask)); | 454 | sizeof(frame->extramask))) |
460 | if (err) | 455 | return -EFAULT; |
461 | goto give_sigsegv; | ||
462 | } | 456 | } |
463 | 457 | ||
464 | if (ka->sa.sa_flags & SA_RESTORER) { | 458 | if (ka->sa.sa_flags & SA_RESTORER) { |
@@ -479,7 +473,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
479 | */ | 473 | */ |
480 | err |= __copy_to_user(frame->retcode, &code, 8); | 474 | err |= __copy_to_user(frame->retcode, &code, 8); |
481 | if (err) | 475 | if (err) |
482 | goto give_sigsegv; | 476 | return -EFAULT; |
483 | 477 | ||
484 | /* Set up registers for signal handler */ | 478 | /* Set up registers for signal handler */ |
485 | regs->sp = (unsigned long) frame; | 479 | regs->sp = (unsigned long) frame; |
@@ -502,10 +496,6 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
502 | #endif | 496 | #endif |
503 | 497 | ||
504 | return 0; | 498 | return 0; |
505 | |||
506 | give_sigsegv: | ||
507 | force_sigsegv(sig, current); | ||
508 | return -EFAULT; | ||
509 | } | 499 | } |
510 | 500 | ||
511 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 501 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
@@ -533,14 +523,14 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
533 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); | 523 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
534 | 524 | ||
535 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 525 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
536 | goto give_sigsegv; | 526 | return -EFAULT; |
537 | 527 | ||
538 | err |= __put_user(sig, &frame->sig); | 528 | err |= __put_user(sig, &frame->sig); |
539 | err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo); | 529 | err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo); |
540 | err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc); | 530 | err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc); |
541 | err |= copy_siginfo_to_user32(&frame->info, info); | 531 | err |= copy_siginfo_to_user32(&frame->info, info); |
542 | if (err) | 532 | if (err) |
543 | goto give_sigsegv; | 533 | return -EFAULT; |
544 | 534 | ||
545 | /* Create the ucontext. */ | 535 | /* Create the ucontext. */ |
546 | if (cpu_has_xsave) | 536 | if (cpu_has_xsave) |
@@ -556,7 +546,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
556 | regs, set->sig[0]); | 546 | regs, set->sig[0]); |
557 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 547 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
558 | if (err) | 548 | if (err) |
559 | goto give_sigsegv; | 549 | return -EFAULT; |
560 | 550 | ||
561 | if (ka->sa.sa_flags & SA_RESTORER) | 551 | if (ka->sa.sa_flags & SA_RESTORER) |
562 | restorer = ka->sa.sa_restorer; | 552 | restorer = ka->sa.sa_restorer; |
@@ -571,7 +561,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
571 | */ | 561 | */ |
572 | err |= __copy_to_user(frame->retcode, &code, 8); | 562 | err |= __copy_to_user(frame->retcode, &code, 8); |
573 | if (err) | 563 | if (err) |
574 | goto give_sigsegv; | 564 | return -EFAULT; |
575 | 565 | ||
576 | /* Set up registers for signal handler */ | 566 | /* Set up registers for signal handler */ |
577 | regs->sp = (unsigned long) frame; | 567 | regs->sp = (unsigned long) frame; |
@@ -599,8 +589,4 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
599 | #endif | 589 | #endif |
600 | 590 | ||
601 | return 0; | 591 | return 0; |
602 | |||
603 | give_sigsegv: | ||
604 | force_sigsegv(sig, current); | ||
605 | return -EFAULT; | ||
606 | } | 592 | } |
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 18e63350d7d2..ca80394ef5b8 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
@@ -736,12 +736,12 @@ unsigned long get_wchan(struct task_struct *p) | |||
736 | if (!p || p == current || p->state == TASK_RUNNING) | 736 | if (!p || p == current || p->state == TASK_RUNNING) |
737 | return 0; | 737 | return 0; |
738 | stack = (unsigned long)task_stack_page(p); | 738 | stack = (unsigned long)task_stack_page(p); |
739 | if (p->thread.sp < stack || p->thread.sp > stack+THREAD_SIZE) | 739 | if (p->thread.sp < stack || p->thread.sp >= stack+THREAD_SIZE) |
740 | return 0; | 740 | return 0; |
741 | fp = *(u64 *)(p->thread.sp); | 741 | fp = *(u64 *)(p->thread.sp); |
742 | do { | 742 | do { |
743 | if (fp < (unsigned long)stack || | 743 | if (fp < (unsigned long)stack || |
744 | fp > (unsigned long)stack+THREAD_SIZE) | 744 | fp >= (unsigned long)stack+THREAD_SIZE) |
745 | return 0; | 745 | return 0; |
746 | ip = *(u64 *)(fp+8); | 746 | ip = *(u64 *)(fp+8); |
747 | if (!in_sched_functions(ip)) | 747 | if (!in_sched_functions(ip)) |
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index e375b658efc3..42ec4421e10b 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -1452,7 +1452,8 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) | |||
1452 | #endif | 1452 | #endif |
1453 | } | 1453 | } |
1454 | 1454 | ||
1455 | void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) | 1455 | void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, |
1456 | int error_code, int si_code) | ||
1456 | { | 1457 | { |
1457 | struct siginfo info; | 1458 | struct siginfo info; |
1458 | 1459 | ||
@@ -1461,7 +1462,7 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) | |||
1461 | 1462 | ||
1462 | memset(&info, 0, sizeof(info)); | 1463 | memset(&info, 0, sizeof(info)); |
1463 | info.si_signo = SIGTRAP; | 1464 | info.si_signo = SIGTRAP; |
1464 | info.si_code = TRAP_BRKPT; | 1465 | info.si_code = si_code; |
1465 | 1466 | ||
1466 | /* User-mode ip? */ | 1467 | /* User-mode ip? */ |
1467 | info.si_addr = user_mode_vm(regs) ? (void __user *) regs->ip : NULL; | 1468 | info.si_addr = user_mode_vm(regs) ? (void __user *) regs->ip : NULL; |
@@ -1548,5 +1549,5 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs) | |||
1548 | */ | 1549 | */ |
1549 | if (test_thread_flag(TIF_SINGLESTEP) && | 1550 | if (test_thread_flag(TIF_SINGLESTEP) && |
1550 | tracehook_consider_fatal_signal(current, SIGTRAP, SIG_DFL)) | 1551 | tracehook_consider_fatal_signal(current, SIGTRAP, SIG_DFL)) |
1551 | send_sigtrap(current, regs, 0); | 1552 | send_sigtrap(current, regs, 0, TRAP_BRKPT); |
1552 | } | 1553 | } |
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c index b21070ea33a4..d6dd057d0f22 100644 --- a/arch/x86/kernel/signal_32.c +++ b/arch/x86/kernel/signal_32.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
28 | #include <asm/i387.h> | 28 | #include <asm/i387.h> |
29 | #include <asm/vdso.h> | 29 | #include <asm/vdso.h> |
30 | #include <asm/syscall.h> | ||
30 | #include <asm/syscalls.h> | 31 | #include <asm/syscalls.h> |
31 | 32 | ||
32 | #include "sigframe.h" | 33 | #include "sigframe.h" |
@@ -112,6 +113,27 @@ asmlinkage int sys_sigaltstack(unsigned long bx) | |||
112 | return do_sigaltstack(uss, uoss, regs->sp); | 113 | return do_sigaltstack(uss, uoss, regs->sp); |
113 | } | 114 | } |
114 | 115 | ||
116 | #define COPY(x) { \ | ||
117 | err |= __get_user(regs->x, &sc->x); \ | ||
118 | } | ||
119 | |||
120 | #define COPY_SEG(seg) { \ | ||
121 | unsigned short tmp; \ | ||
122 | err |= __get_user(tmp, &sc->seg); \ | ||
123 | regs->seg = tmp; \ | ||
124 | } | ||
125 | |||
126 | #define COPY_SEG_STRICT(seg) { \ | ||
127 | unsigned short tmp; \ | ||
128 | err |= __get_user(tmp, &sc->seg); \ | ||
129 | regs->seg = tmp | 3; \ | ||
130 | } | ||
131 | |||
132 | #define GET_SEG(seg) { \ | ||
133 | unsigned short tmp; \ | ||
134 | err |= __get_user(tmp, &sc->seg); \ | ||
135 | loadsegment(seg, tmp); \ | ||
136 | } | ||
115 | 137 | ||
116 | /* | 138 | /* |
117 | * Do a signal return; undo the signal stack. | 139 | * Do a signal return; undo the signal stack. |
@@ -120,28 +142,13 @@ static int | |||
120 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | 142 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, |
121 | unsigned long *pax) | 143 | unsigned long *pax) |
122 | { | 144 | { |
145 | void __user *buf; | ||
146 | unsigned int tmpflags; | ||
123 | unsigned int err = 0; | 147 | unsigned int err = 0; |
124 | 148 | ||
125 | /* Always make any pending restarted system calls return -EINTR */ | 149 | /* Always make any pending restarted system calls return -EINTR */ |
126 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | 150 | current_thread_info()->restart_block.fn = do_no_restart_syscall; |
127 | 151 | ||
128 | #define COPY(x) err |= __get_user(regs->x, &sc->x) | ||
129 | |||
130 | #define COPY_SEG(seg) \ | ||
131 | { unsigned short tmp; \ | ||
132 | err |= __get_user(tmp, &sc->seg); \ | ||
133 | regs->seg = tmp; } | ||
134 | |||
135 | #define COPY_SEG_STRICT(seg) \ | ||
136 | { unsigned short tmp; \ | ||
137 | err |= __get_user(tmp, &sc->seg); \ | ||
138 | regs->seg = tmp|3; } | ||
139 | |||
140 | #define GET_SEG(seg) \ | ||
141 | { unsigned short tmp; \ | ||
142 | err |= __get_user(tmp, &sc->seg); \ | ||
143 | loadsegment(seg, tmp); } | ||
144 | |||
145 | GET_SEG(gs); | 152 | GET_SEG(gs); |
146 | COPY_SEG(fs); | 153 | COPY_SEG(fs); |
147 | COPY_SEG(es); | 154 | COPY_SEG(es); |
@@ -151,21 +158,12 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
151 | COPY_SEG_STRICT(cs); | 158 | COPY_SEG_STRICT(cs); |
152 | COPY_SEG_STRICT(ss); | 159 | COPY_SEG_STRICT(ss); |
153 | 160 | ||
154 | { | 161 | err |= __get_user(tmpflags, &sc->flags); |
155 | unsigned int tmpflags; | 162 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); |
156 | 163 | regs->orig_ax = -1; /* disable syscall checks */ | |
157 | err |= __get_user(tmpflags, &sc->flags); | ||
158 | regs->flags = (regs->flags & ~FIX_EFLAGS) | | ||
159 | (tmpflags & FIX_EFLAGS); | ||
160 | regs->orig_ax = -1; /* disable syscall checks */ | ||
161 | } | ||
162 | |||
163 | { | ||
164 | void __user *buf; | ||
165 | 164 | ||
166 | err |= __get_user(buf, &sc->fpstate); | 165 | err |= __get_user(buf, &sc->fpstate); |
167 | err |= restore_i387_xstate(buf); | 166 | err |= restore_i387_xstate(buf); |
168 | } | ||
169 | 167 | ||
170 | err |= __get_user(*pax, &sc->ax); | 168 | err |= __get_user(*pax, &sc->ax); |
171 | return err; | 169 | return err; |
@@ -214,9 +212,8 @@ badframe: | |||
214 | return 0; | 212 | return 0; |
215 | } | 213 | } |
216 | 214 | ||
217 | asmlinkage int sys_rt_sigreturn(unsigned long __unused) | 215 | static long do_rt_sigreturn(struct pt_regs *regs) |
218 | { | 216 | { |
219 | struct pt_regs *regs = (struct pt_regs *)&__unused; | ||
220 | struct rt_sigframe __user *frame; | 217 | struct rt_sigframe __user *frame; |
221 | unsigned long ax; | 218 | unsigned long ax; |
222 | sigset_t set; | 219 | sigset_t set; |
@@ -242,10 +239,17 @@ asmlinkage int sys_rt_sigreturn(unsigned long __unused) | |||
242 | return ax; | 239 | return ax; |
243 | 240 | ||
244 | badframe: | 241 | badframe: |
245 | force_sig(SIGSEGV, current); | 242 | signal_fault(regs, frame, "rt_sigreturn"); |
246 | return 0; | 243 | return 0; |
247 | } | 244 | } |
248 | 245 | ||
246 | asmlinkage int sys_rt_sigreturn(unsigned long __unused) | ||
247 | { | ||
248 | struct pt_regs *regs = (struct pt_regs *)&__unused; | ||
249 | |||
250 | return do_rt_sigreturn(regs); | ||
251 | } | ||
252 | |||
249 | /* | 253 | /* |
250 | * Set up a signal frame. | 254 | * Set up a signal frame. |
251 | */ | 255 | */ |
@@ -337,39 +341,29 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, | |||
337 | } | 341 | } |
338 | 342 | ||
339 | static int | 343 | static int |
340 | setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | 344 | __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, |
341 | struct pt_regs *regs) | 345 | struct pt_regs *regs) |
342 | { | 346 | { |
343 | struct sigframe __user *frame; | 347 | struct sigframe __user *frame; |
344 | void __user *restorer; | 348 | void __user *restorer; |
345 | int err = 0; | 349 | int err = 0; |
346 | int usig; | ||
347 | void __user *fpstate = NULL; | 350 | void __user *fpstate = NULL; |
348 | 351 | ||
349 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); | 352 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
350 | 353 | ||
351 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 354 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
352 | goto give_sigsegv; | 355 | return -EFAULT; |
353 | 356 | ||
354 | usig = current_thread_info()->exec_domain | 357 | if (__put_user(sig, &frame->sig)) |
355 | && current_thread_info()->exec_domain->signal_invmap | 358 | return -EFAULT; |
356 | && sig < 32 | ||
357 | ? current_thread_info()->exec_domain->signal_invmap[sig] | ||
358 | : sig; | ||
359 | 359 | ||
360 | err = __put_user(usig, &frame->sig); | 360 | if (setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0])) |
361 | if (err) | 361 | return -EFAULT; |
362 | goto give_sigsegv; | ||
363 | |||
364 | err = setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]); | ||
365 | if (err) | ||
366 | goto give_sigsegv; | ||
367 | 362 | ||
368 | if (_NSIG_WORDS > 1) { | 363 | if (_NSIG_WORDS > 1) { |
369 | err = __copy_to_user(&frame->extramask, &set->sig[1], | 364 | if (__copy_to_user(&frame->extramask, &set->sig[1], |
370 | sizeof(frame->extramask)); | 365 | sizeof(frame->extramask))) |
371 | if (err) | 366 | return -EFAULT; |
372 | goto give_sigsegv; | ||
373 | } | 367 | } |
374 | 368 | ||
375 | if (current->mm->context.vdso) | 369 | if (current->mm->context.vdso) |
@@ -394,7 +388,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
394 | err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); | 388 | err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); |
395 | 389 | ||
396 | if (err) | 390 | if (err) |
397 | goto give_sigsegv; | 391 | return -EFAULT; |
398 | 392 | ||
399 | /* Set up registers for signal handler */ | 393 | /* Set up registers for signal handler */ |
400 | regs->sp = (unsigned long)frame; | 394 | regs->sp = (unsigned long)frame; |
@@ -409,38 +403,27 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
409 | regs->cs = __USER_CS; | 403 | regs->cs = __USER_CS; |
410 | 404 | ||
411 | return 0; | 405 | return 0; |
412 | |||
413 | give_sigsegv: | ||
414 | force_sigsegv(sig, current); | ||
415 | return -EFAULT; | ||
416 | } | 406 | } |
417 | 407 | ||
418 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 408 | static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
419 | sigset_t *set, struct pt_regs *regs) | 409 | sigset_t *set, struct pt_regs *regs) |
420 | { | 410 | { |
421 | struct rt_sigframe __user *frame; | 411 | struct rt_sigframe __user *frame; |
422 | void __user *restorer; | 412 | void __user *restorer; |
423 | int err = 0; | 413 | int err = 0; |
424 | int usig; | ||
425 | void __user *fpstate = NULL; | 414 | void __user *fpstate = NULL; |
426 | 415 | ||
427 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); | 416 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
428 | 417 | ||
429 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 418 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
430 | goto give_sigsegv; | 419 | return -EFAULT; |
431 | |||
432 | usig = current_thread_info()->exec_domain | ||
433 | && current_thread_info()->exec_domain->signal_invmap | ||
434 | && sig < 32 | ||
435 | ? current_thread_info()->exec_domain->signal_invmap[sig] | ||
436 | : sig; | ||
437 | 420 | ||
438 | err |= __put_user(usig, &frame->sig); | 421 | err |= __put_user(sig, &frame->sig); |
439 | err |= __put_user(&frame->info, &frame->pinfo); | 422 | err |= __put_user(&frame->info, &frame->pinfo); |
440 | err |= __put_user(&frame->uc, &frame->puc); | 423 | err |= __put_user(&frame->uc, &frame->puc); |
441 | err |= copy_siginfo_to_user(&frame->info, info); | 424 | err |= copy_siginfo_to_user(&frame->info, info); |
442 | if (err) | 425 | if (err) |
443 | goto give_sigsegv; | 426 | return -EFAULT; |
444 | 427 | ||
445 | /* Create the ucontext. */ | 428 | /* Create the ucontext. */ |
446 | if (cpu_has_xsave) | 429 | if (cpu_has_xsave) |
@@ -456,7 +439,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
456 | regs, set->sig[0]); | 439 | regs, set->sig[0]); |
457 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 440 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
458 | if (err) | 441 | if (err) |
459 | goto give_sigsegv; | 442 | return -EFAULT; |
460 | 443 | ||
461 | /* Set up to return from userspace. */ | 444 | /* Set up to return from userspace. */ |
462 | restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn); | 445 | restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn); |
@@ -476,12 +459,12 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
476 | err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); | 459 | err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); |
477 | 460 | ||
478 | if (err) | 461 | if (err) |
479 | goto give_sigsegv; | 462 | return -EFAULT; |
480 | 463 | ||
481 | /* Set up registers for signal handler */ | 464 | /* Set up registers for signal handler */ |
482 | regs->sp = (unsigned long)frame; | 465 | regs->sp = (unsigned long)frame; |
483 | regs->ip = (unsigned long)ka->sa.sa_handler; | 466 | regs->ip = (unsigned long)ka->sa.sa_handler; |
484 | regs->ax = (unsigned long)usig; | 467 | regs->ax = (unsigned long)sig; |
485 | regs->dx = (unsigned long)&frame->info; | 468 | regs->dx = (unsigned long)&frame->info; |
486 | regs->cx = (unsigned long)&frame->uc; | 469 | regs->cx = (unsigned long)&frame->uc; |
487 | 470 | ||
@@ -491,15 +474,48 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
491 | regs->cs = __USER_CS; | 474 | regs->cs = __USER_CS; |
492 | 475 | ||
493 | return 0; | 476 | return 0; |
494 | |||
495 | give_sigsegv: | ||
496 | force_sigsegv(sig, current); | ||
497 | return -EFAULT; | ||
498 | } | 477 | } |
499 | 478 | ||
500 | /* | 479 | /* |
501 | * OK, we're invoking a handler: | 480 | * OK, we're invoking a handler: |
502 | */ | 481 | */ |
482 | static int signr_convert(int sig) | ||
483 | { | ||
484 | struct thread_info *info = current_thread_info(); | ||
485 | |||
486 | if (info->exec_domain && info->exec_domain->signal_invmap && sig < 32) | ||
487 | return info->exec_domain->signal_invmap[sig]; | ||
488 | return sig; | ||
489 | } | ||
490 | |||
491 | #define is_ia32 1 | ||
492 | #define ia32_setup_frame __setup_frame | ||
493 | #define ia32_setup_rt_frame __setup_rt_frame | ||
494 | |||
495 | static int | ||
496 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
497 | sigset_t *set, struct pt_regs *regs) | ||
498 | { | ||
499 | int usig = signr_convert(sig); | ||
500 | int ret; | ||
501 | |||
502 | /* Set up the stack frame */ | ||
503 | if (is_ia32) { | ||
504 | if (ka->sa.sa_flags & SA_SIGINFO) | ||
505 | ret = ia32_setup_rt_frame(usig, ka, info, set, regs); | ||
506 | else | ||
507 | ret = ia32_setup_frame(usig, ka, set, regs); | ||
508 | } else | ||
509 | ret = __setup_rt_frame(sig, ka, info, set, regs); | ||
510 | |||
511 | if (ret) { | ||
512 | force_sigsegv(sig, current); | ||
513 | return -EFAULT; | ||
514 | } | ||
515 | |||
516 | return ret; | ||
517 | } | ||
518 | |||
503 | static int | 519 | static int |
504 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | 520 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, |
505 | sigset_t *oldset, struct pt_regs *regs) | 521 | sigset_t *oldset, struct pt_regs *regs) |
@@ -507,9 +523,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
507 | int ret; | 523 | int ret; |
508 | 524 | ||
509 | /* Are we from a system call? */ | 525 | /* Are we from a system call? */ |
510 | if ((long)regs->orig_ax >= 0) { | 526 | if (syscall_get_nr(current, regs) >= 0) { |
511 | /* If so, check system call restarting.. */ | 527 | /* If so, check system call restarting.. */ |
512 | switch (regs->ax) { | 528 | switch (syscall_get_error(current, regs)) { |
513 | case -ERESTART_RESTARTBLOCK: | 529 | case -ERESTART_RESTARTBLOCK: |
514 | case -ERESTARTNOHAND: | 530 | case -ERESTARTNOHAND: |
515 | regs->ax = -EINTR; | 531 | regs->ax = -EINTR; |
@@ -536,15 +552,20 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
536 | likely(test_and_clear_thread_flag(TIF_FORCED_TF))) | 552 | likely(test_and_clear_thread_flag(TIF_FORCED_TF))) |
537 | regs->flags &= ~X86_EFLAGS_TF; | 553 | regs->flags &= ~X86_EFLAGS_TF; |
538 | 554 | ||
539 | /* Set up the stack frame */ | 555 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |
540 | if (ka->sa.sa_flags & SA_SIGINFO) | ||
541 | ret = setup_rt_frame(sig, ka, info, oldset, regs); | ||
542 | else | ||
543 | ret = setup_frame(sig, ka, oldset, regs); | ||
544 | 556 | ||
545 | if (ret) | 557 | if (ret) |
546 | return ret; | 558 | return ret; |
547 | 559 | ||
560 | #ifdef CONFIG_X86_64 | ||
561 | /* | ||
562 | * This has nothing to do with segment registers, | ||
563 | * despite the name. This magic affects uaccess.h | ||
564 | * macros' behavior. Reset it to the normal setting. | ||
565 | */ | ||
566 | set_fs(USER_DS); | ||
567 | #endif | ||
568 | |||
548 | /* | 569 | /* |
549 | * Clear the direction flag as per the ABI for function entry. | 570 | * Clear the direction flag as per the ABI for function entry. |
550 | */ | 571 | */ |
@@ -571,6 +592,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
571 | return 0; | 592 | return 0; |
572 | } | 593 | } |
573 | 594 | ||
595 | #define NR_restart_syscall __NR_restart_syscall | ||
574 | /* | 596 | /* |
575 | * Note that 'init' is a special process: it doesn't get signals it doesn't | 597 | * Note that 'init' is a special process: it doesn't get signals it doesn't |
576 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 598 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
@@ -623,9 +645,9 @@ static void do_signal(struct pt_regs *regs) | |||
623 | } | 645 | } |
624 | 646 | ||
625 | /* Did we come from a system call? */ | 647 | /* Did we come from a system call? */ |
626 | if ((long)regs->orig_ax >= 0) { | 648 | if (syscall_get_nr(current, regs) >= 0) { |
627 | /* Restart the system call - no handlers present */ | 649 | /* Restart the system call - no handlers present */ |
628 | switch (regs->ax) { | 650 | switch (syscall_get_error(current, regs)) { |
629 | case -ERESTARTNOHAND: | 651 | case -ERESTARTNOHAND: |
630 | case -ERESTARTSYS: | 652 | case -ERESTARTSYS: |
631 | case -ERESTARTNOINTR: | 653 | case -ERESTARTNOINTR: |
@@ -634,7 +656,7 @@ static void do_signal(struct pt_regs *regs) | |||
634 | break; | 656 | break; |
635 | 657 | ||
636 | case -ERESTART_RESTARTBLOCK: | 658 | case -ERESTART_RESTARTBLOCK: |
637 | regs->ax = __NR_restart_syscall; | 659 | regs->ax = NR_restart_syscall; |
638 | regs->ip -= 2; | 660 | regs->ip -= 2; |
639 | break; | 661 | break; |
640 | } | 662 | } |
@@ -657,6 +679,12 @@ static void do_signal(struct pt_regs *regs) | |||
657 | void | 679 | void |
658 | do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) | 680 | do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) |
659 | { | 681 | { |
682 | #if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE) | ||
683 | /* notify userspace of pending MCEs */ | ||
684 | if (thread_info_flags & _TIF_MCE_NOTIFY) | ||
685 | mce_notify_user(); | ||
686 | #endif /* CONFIG_X86_64 && CONFIG_X86_MCE */ | ||
687 | |||
660 | /* deal with pending signal delivery */ | 688 | /* deal with pending signal delivery */ |
661 | if (thread_info_flags & _TIF_SIGPENDING) | 689 | if (thread_info_flags & _TIF_SIGPENDING) |
662 | do_signal(regs); | 690 | do_signal(regs); |
@@ -666,5 +694,23 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) | |||
666 | tracehook_notify_resume(regs); | 694 | tracehook_notify_resume(regs); |
667 | } | 695 | } |
668 | 696 | ||
697 | #ifdef CONFIG_X86_32 | ||
669 | clear_thread_flag(TIF_IRET); | 698 | clear_thread_flag(TIF_IRET); |
699 | #endif /* CONFIG_X86_32 */ | ||
700 | } | ||
701 | |||
702 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where) | ||
703 | { | ||
704 | struct task_struct *me = current; | ||
705 | |||
706 | if (show_unhandled_signals && printk_ratelimit()) { | ||
707 | printk(KERN_INFO | ||
708 | "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx", | ||
709 | me->comm, me->pid, where, frame, | ||
710 | regs->ip, regs->sp, regs->orig_ax); | ||
711 | print_vma_addr(" in ", regs->ip); | ||
712 | printk(KERN_CONT "\n"); | ||
713 | } | ||
714 | |||
715 | force_sig(SIGSEGV, me); | ||
670 | } | 716 | } |
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index 823a55bf8c39..a5c9627f4db9 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c | |||
@@ -52,6 +52,16 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | |||
52 | return do_sigaltstack(uss, uoss, regs->sp); | 52 | return do_sigaltstack(uss, uoss, regs->sp); |
53 | } | 53 | } |
54 | 54 | ||
55 | #define COPY(x) { \ | ||
56 | err |= __get_user(regs->x, &sc->x); \ | ||
57 | } | ||
58 | |||
59 | #define COPY_SEG_STRICT(seg) { \ | ||
60 | unsigned short tmp; \ | ||
61 | err |= __get_user(tmp, &sc->seg); \ | ||
62 | regs->seg = tmp | 3; \ | ||
63 | } | ||
64 | |||
55 | /* | 65 | /* |
56 | * Do a signal return; undo the signal stack. | 66 | * Do a signal return; undo the signal stack. |
57 | */ | 67 | */ |
@@ -59,13 +69,13 @@ static int | |||
59 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | 69 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, |
60 | unsigned long *pax) | 70 | unsigned long *pax) |
61 | { | 71 | { |
72 | void __user *buf; | ||
73 | unsigned int tmpflags; | ||
62 | unsigned int err = 0; | 74 | unsigned int err = 0; |
63 | 75 | ||
64 | /* Always make any pending restarted system calls return -EINTR */ | 76 | /* Always make any pending restarted system calls return -EINTR */ |
65 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | 77 | current_thread_info()->restart_block.fn = do_no_restart_syscall; |
66 | 78 | ||
67 | #define COPY(x) (err |= __get_user(regs->x, &sc->x)) | ||
68 | |||
69 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); | 79 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); |
70 | COPY(dx); COPY(cx); COPY(ip); | 80 | COPY(dx); COPY(cx); COPY(ip); |
71 | COPY(r8); | 81 | COPY(r8); |
@@ -80,34 +90,24 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
80 | /* Kernel saves and restores only the CS segment register on signals, | 90 | /* Kernel saves and restores only the CS segment register on signals, |
81 | * which is the bare minimum needed to allow mixed 32/64-bit code. | 91 | * which is the bare minimum needed to allow mixed 32/64-bit code. |
82 | * App's signal handler can save/restore other segments if needed. */ | 92 | * App's signal handler can save/restore other segments if needed. */ |
83 | { | 93 | COPY_SEG_STRICT(cs); |
84 | unsigned cs; | ||
85 | err |= __get_user(cs, &sc->cs); | ||
86 | regs->cs = cs | 3; /* Force into user mode */ | ||
87 | } | ||
88 | 94 | ||
89 | { | 95 | err |= __get_user(tmpflags, &sc->flags); |
90 | unsigned int tmpflags; | 96 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); |
91 | err |= __get_user(tmpflags, &sc->flags); | 97 | regs->orig_ax = -1; /* disable syscall checks */ |
92 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); | ||
93 | regs->orig_ax = -1; /* disable syscall checks */ | ||
94 | } | ||
95 | 98 | ||
96 | { | 99 | err |= __get_user(buf, &sc->fpstate); |
97 | struct _fpstate __user *buf; | 100 | err |= restore_i387_xstate(buf); |
98 | err |= __get_user(buf, &sc->fpstate); | ||
99 | err |= restore_i387_xstate(buf); | ||
100 | } | ||
101 | 101 | ||
102 | err |= __get_user(*pax, &sc->ax); | 102 | err |= __get_user(*pax, &sc->ax); |
103 | return err; | 103 | return err; |
104 | } | 104 | } |
105 | 105 | ||
106 | asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | 106 | static long do_rt_sigreturn(struct pt_regs *regs) |
107 | { | 107 | { |
108 | struct rt_sigframe __user *frame; | 108 | struct rt_sigframe __user *frame; |
109 | sigset_t set; | ||
110 | unsigned long ax; | 109 | unsigned long ax; |
110 | sigset_t set; | ||
111 | 111 | ||
112 | frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long)); | 112 | frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long)); |
113 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 113 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
@@ -130,10 +130,15 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | |||
130 | return ax; | 130 | return ax; |
131 | 131 | ||
132 | badframe: | 132 | badframe: |
133 | signal_fault(regs, frame, "sigreturn"); | 133 | signal_fault(regs, frame, "rt_sigreturn"); |
134 | return 0; | 134 | return 0; |
135 | } | 135 | } |
136 | 136 | ||
137 | asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | ||
138 | { | ||
139 | return do_rt_sigreturn(regs); | ||
140 | } | ||
141 | |||
137 | /* | 142 | /* |
138 | * Set up a signal frame. | 143 | * Set up a signal frame. |
139 | */ | 144 | */ |
@@ -195,8 +200,8 @@ get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size) | |||
195 | return (void __user *)round_down(sp - size, 64); | 200 | return (void __user *)round_down(sp - size, 64); |
196 | } | 201 | } |
197 | 202 | ||
198 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 203 | static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
199 | sigset_t *set, struct pt_regs *regs) | 204 | sigset_t *set, struct pt_regs *regs) |
200 | { | 205 | { |
201 | struct rt_sigframe __user *frame; | 206 | struct rt_sigframe __user *frame; |
202 | void __user *fp = NULL; | 207 | void __user *fp = NULL; |
@@ -209,17 +214,16 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
209 | (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; | 214 | (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; |
210 | 215 | ||
211 | if (save_i387_xstate(fp) < 0) | 216 | if (save_i387_xstate(fp) < 0) |
212 | err |= -1; | 217 | return -EFAULT; |
213 | } else | 218 | } else |
214 | frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8; | 219 | frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8; |
215 | 220 | ||
216 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 221 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
217 | goto give_sigsegv; | 222 | return -EFAULT; |
218 | 223 | ||
219 | if (ka->sa.sa_flags & SA_SIGINFO) { | 224 | if (ka->sa.sa_flags & SA_SIGINFO) { |
220 | err |= copy_siginfo_to_user(&frame->info, info); | 225 | if (copy_siginfo_to_user(&frame->info, info)) |
221 | if (err) | 226 | return -EFAULT; |
222 | goto give_sigsegv; | ||
223 | } | 227 | } |
224 | 228 | ||
225 | /* Create the ucontext. */ | 229 | /* Create the ucontext. */ |
@@ -247,11 +251,11 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
247 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); | 251 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); |
248 | } else { | 252 | } else { |
249 | /* could use a vstub here */ | 253 | /* could use a vstub here */ |
250 | goto give_sigsegv; | 254 | return -EFAULT; |
251 | } | 255 | } |
252 | 256 | ||
253 | if (err) | 257 | if (err) |
254 | goto give_sigsegv; | 258 | return -EFAULT; |
255 | 259 | ||
256 | /* Set up registers for signal handler */ | 260 | /* Set up registers for signal handler */ |
257 | regs->di = sig; | 261 | regs->di = sig; |
@@ -271,15 +275,45 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
271 | regs->cs = __USER_CS; | 275 | regs->cs = __USER_CS; |
272 | 276 | ||
273 | return 0; | 277 | return 0; |
274 | |||
275 | give_sigsegv: | ||
276 | force_sigsegv(sig, current); | ||
277 | return -EFAULT; | ||
278 | } | 278 | } |
279 | 279 | ||
280 | /* | 280 | /* |
281 | * OK, we're invoking a handler | 281 | * OK, we're invoking a handler |
282 | */ | 282 | */ |
283 | static int signr_convert(int sig) | ||
284 | { | ||
285 | return sig; | ||
286 | } | ||
287 | |||
288 | #ifdef CONFIG_IA32_EMULATION | ||
289 | #define is_ia32 test_thread_flag(TIF_IA32) | ||
290 | #else | ||
291 | #define is_ia32 0 | ||
292 | #endif | ||
293 | |||
294 | static int | ||
295 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
296 | sigset_t *set, struct pt_regs *regs) | ||
297 | { | ||
298 | int usig = signr_convert(sig); | ||
299 | int ret; | ||
300 | |||
301 | /* Set up the stack frame */ | ||
302 | if (is_ia32) { | ||
303 | if (ka->sa.sa_flags & SA_SIGINFO) | ||
304 | ret = ia32_setup_rt_frame(usig, ka, info, set, regs); | ||
305 | else | ||
306 | ret = ia32_setup_frame(usig, ka, set, regs); | ||
307 | } else | ||
308 | ret = __setup_rt_frame(sig, ka, info, set, regs); | ||
309 | |||
310 | if (ret) { | ||
311 | force_sigsegv(sig, current); | ||
312 | return -EFAULT; | ||
313 | } | ||
314 | |||
315 | return ret; | ||
316 | } | ||
283 | 317 | ||
284 | static int | 318 | static int |
285 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | 319 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, |
@@ -317,51 +351,48 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | |||
317 | likely(test_and_clear_thread_flag(TIF_FORCED_TF))) | 351 | likely(test_and_clear_thread_flag(TIF_FORCED_TF))) |
318 | regs->flags &= ~X86_EFLAGS_TF; | 352 | regs->flags &= ~X86_EFLAGS_TF; |
319 | 353 | ||
320 | #ifdef CONFIG_IA32_EMULATION | ||
321 | if (test_thread_flag(TIF_IA32)) { | ||
322 | if (ka->sa.sa_flags & SA_SIGINFO) | ||
323 | ret = ia32_setup_rt_frame(sig, ka, info, oldset, regs); | ||
324 | else | ||
325 | ret = ia32_setup_frame(sig, ka, oldset, regs); | ||
326 | } else | ||
327 | #endif | ||
328 | ret = setup_rt_frame(sig, ka, info, oldset, regs); | 354 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |
329 | 355 | ||
330 | if (ret == 0) { | 356 | if (ret) |
331 | /* | 357 | return ret; |
332 | * This has nothing to do with segment registers, | ||
333 | * despite the name. This magic affects uaccess.h | ||
334 | * macros' behavior. Reset it to the normal setting. | ||
335 | */ | ||
336 | set_fs(USER_DS); | ||
337 | 358 | ||
338 | /* | 359 | #ifdef CONFIG_X86_64 |
339 | * Clear the direction flag as per the ABI for function entry. | 360 | /* |
340 | */ | 361 | * This has nothing to do with segment registers, |
341 | regs->flags &= ~X86_EFLAGS_DF; | 362 | * despite the name. This magic affects uaccess.h |
363 | * macros' behavior. Reset it to the normal setting. | ||
364 | */ | ||
365 | set_fs(USER_DS); | ||
366 | #endif | ||
342 | 367 | ||
343 | /* | 368 | /* |
344 | * Clear TF when entering the signal handler, but | 369 | * Clear the direction flag as per the ABI for function entry. |
345 | * notify any tracer that was single-stepping it. | 370 | */ |
346 | * The tracer may want to single-step inside the | 371 | regs->flags &= ~X86_EFLAGS_DF; |
347 | * handler too. | ||
348 | */ | ||
349 | regs->flags &= ~X86_EFLAGS_TF; | ||
350 | 372 | ||
351 | spin_lock_irq(¤t->sighand->siglock); | 373 | /* |
352 | sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); | 374 | * Clear TF when entering the signal handler, but |
353 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 375 | * notify any tracer that was single-stepping it. |
354 | sigaddset(¤t->blocked, sig); | 376 | * The tracer may want to single-step inside the |
355 | recalc_sigpending(); | 377 | * handler too. |
356 | spin_unlock_irq(¤t->sighand->siglock); | 378 | */ |
379 | regs->flags &= ~X86_EFLAGS_TF; | ||
357 | 380 | ||
358 | tracehook_signal_handler(sig, info, ka, regs, | 381 | spin_lock_irq(¤t->sighand->siglock); |
359 | test_thread_flag(TIF_SINGLESTEP)); | 382 | sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); |
360 | } | 383 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
384 | sigaddset(¤t->blocked, sig); | ||
385 | recalc_sigpending(); | ||
386 | spin_unlock_irq(¤t->sighand->siglock); | ||
361 | 387 | ||
362 | return ret; | 388 | tracehook_signal_handler(sig, info, ka, regs, |
389 | test_thread_flag(TIF_SINGLESTEP)); | ||
390 | |||
391 | return 0; | ||
363 | } | 392 | } |
364 | 393 | ||
394 | #define NR_restart_syscall \ | ||
395 | test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : __NR_restart_syscall | ||
365 | /* | 396 | /* |
366 | * Note that 'init' is a special process: it doesn't get signals it doesn't | 397 | * Note that 'init' is a special process: it doesn't get signals it doesn't |
367 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 398 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
@@ -391,7 +422,8 @@ static void do_signal(struct pt_regs *regs) | |||
391 | 422 | ||
392 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 423 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
393 | if (signr > 0) { | 424 | if (signr > 0) { |
394 | /* Re-enable any watchpoints before delivering the | 425 | /* |
426 | * Re-enable any watchpoints before delivering the | ||
395 | * signal to user space. The processor register will | 427 | * signal to user space. The processor register will |
396 | * have been cleared if the watchpoint triggered | 428 | * have been cleared if the watchpoint triggered |
397 | * inside the kernel. | 429 | * inside the kernel. |
@@ -399,7 +431,7 @@ static void do_signal(struct pt_regs *regs) | |||
399 | if (current->thread.debugreg7) | 431 | if (current->thread.debugreg7) |
400 | set_debugreg(current->thread.debugreg7, 7); | 432 | set_debugreg(current->thread.debugreg7, 7); |
401 | 433 | ||
402 | /* Whee! Actually deliver the signal. */ | 434 | /* Whee! Actually deliver the signal. */ |
403 | if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { | 435 | if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { |
404 | /* | 436 | /* |
405 | * A signal was successfully delivered; the saved | 437 | * A signal was successfully delivered; the saved |
@@ -422,10 +454,9 @@ static void do_signal(struct pt_regs *regs) | |||
422 | regs->ax = regs->orig_ax; | 454 | regs->ax = regs->orig_ax; |
423 | regs->ip -= 2; | 455 | regs->ip -= 2; |
424 | break; | 456 | break; |
457 | |||
425 | case -ERESTART_RESTARTBLOCK: | 458 | case -ERESTART_RESTARTBLOCK: |
426 | regs->ax = test_thread_flag(TIF_IA32) ? | 459 | regs->ax = NR_restart_syscall; |
427 | __NR_ia32_restart_syscall : | ||
428 | __NR_restart_syscall; | ||
429 | regs->ip -= 2; | 460 | regs->ip -= 2; |
430 | break; | 461 | break; |
431 | } | 462 | } |
@@ -441,14 +472,18 @@ static void do_signal(struct pt_regs *regs) | |||
441 | } | 472 | } |
442 | } | 473 | } |
443 | 474 | ||
444 | void do_notify_resume(struct pt_regs *regs, void *unused, | 475 | /* |
445 | __u32 thread_info_flags) | 476 | * notification of userspace execution resumption |
477 | * - triggered by the TIF_WORK_MASK flags | ||
478 | */ | ||
479 | void | ||
480 | do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) | ||
446 | { | 481 | { |
447 | #ifdef CONFIG_X86_MCE | 482 | #if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE) |
448 | /* notify userspace of pending MCEs */ | 483 | /* notify userspace of pending MCEs */ |
449 | if (thread_info_flags & _TIF_MCE_NOTIFY) | 484 | if (thread_info_flags & _TIF_MCE_NOTIFY) |
450 | mce_notify_user(); | 485 | mce_notify_user(); |
451 | #endif /* CONFIG_X86_MCE */ | 486 | #endif /* CONFIG_X86_64 && CONFIG_X86_MCE */ |
452 | 487 | ||
453 | /* deal with pending signal delivery */ | 488 | /* deal with pending signal delivery */ |
454 | if (thread_info_flags & _TIF_SIGPENDING) | 489 | if (thread_info_flags & _TIF_SIGPENDING) |
@@ -458,17 +493,23 @@ void do_notify_resume(struct pt_regs *regs, void *unused, | |||
458 | clear_thread_flag(TIF_NOTIFY_RESUME); | 493 | clear_thread_flag(TIF_NOTIFY_RESUME); |
459 | tracehook_notify_resume(regs); | 494 | tracehook_notify_resume(regs); |
460 | } | 495 | } |
496 | |||
497 | #ifdef CONFIG_X86_32 | ||
498 | clear_thread_flag(TIF_IRET); | ||
499 | #endif /* CONFIG_X86_32 */ | ||
461 | } | 500 | } |
462 | 501 | ||
463 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where) | 502 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where) |
464 | { | 503 | { |
465 | struct task_struct *me = current; | 504 | struct task_struct *me = current; |
505 | |||
466 | if (show_unhandled_signals && printk_ratelimit()) { | 506 | if (show_unhandled_signals && printk_ratelimit()) { |
467 | printk("%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx", | 507 | printk(KERN_INFO |
468 | me->comm, me->pid, where, frame, regs->ip, | 508 | "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx", |
469 | regs->sp, regs->orig_ax); | 509 | me->comm, me->pid, where, frame, |
510 | regs->ip, regs->sp, regs->orig_ax); | ||
470 | print_vma_addr(" in ", regs->ip); | 511 | print_vma_addr(" in ", regs->ip); |
471 | printk("\n"); | 512 | printk(KERN_CONT "\n"); |
472 | } | 513 | } |
473 | 514 | ||
474 | force_sig(SIGSEGV, me); | 515 | force_sig(SIGSEGV, me); |
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index da5a5964fccb..0429c5de5ea9 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c | |||
@@ -891,6 +891,7 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code) | |||
891 | { | 891 | { |
892 | struct task_struct *tsk = current; | 892 | struct task_struct *tsk = current; |
893 | unsigned int condition; | 893 | unsigned int condition; |
894 | int si_code; | ||
894 | 895 | ||
895 | trace_hardirqs_fixup(); | 896 | trace_hardirqs_fixup(); |
896 | 897 | ||
@@ -935,8 +936,9 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code) | |||
935 | goto clear_TF_reenable; | 936 | goto clear_TF_reenable; |
936 | } | 937 | } |
937 | 938 | ||
939 | si_code = get_si_code((unsigned long)condition); | ||
938 | /* Ok, finally something we can handle */ | 940 | /* Ok, finally something we can handle */ |
939 | send_sigtrap(tsk, regs, error_code); | 941 | send_sigtrap(tsk, regs, error_code, si_code); |
940 | 942 | ||
941 | /* | 943 | /* |
942 | * Disable additional traps. They'll be re-enabled when | 944 | * Disable additional traps. They'll be re-enabled when |
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c index 2887a789e38f..9c0ac0cab013 100644 --- a/arch/x86/kernel/traps_64.c +++ b/arch/x86/kernel/traps_64.c | |||
@@ -940,7 +940,7 @@ asmlinkage void __kprobes do_debug(struct pt_regs *regs, | |||
940 | tsk->thread.error_code = error_code; | 940 | tsk->thread.error_code = error_code; |
941 | info.si_signo = SIGTRAP; | 941 | info.si_signo = SIGTRAP; |
942 | info.si_errno = 0; | 942 | info.si_errno = 0; |
943 | info.si_code = TRAP_BRKPT; | 943 | info.si_code = get_si_code(condition); |
944 | info.si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL; | 944 | info.si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL; |
945 | force_sig_info(SIGTRAP, &info, tsk); | 945 | force_sig_info(SIGTRAP, &info, tsk); |
946 | 946 | ||
diff --git a/arch/x86/kernel/vmlinux_64.lds.S b/arch/x86/kernel/vmlinux_64.lds.S index 201e81a91a95..46e05447405b 100644 --- a/arch/x86/kernel/vmlinux_64.lds.S +++ b/arch/x86/kernel/vmlinux_64.lds.S | |||
@@ -172,8 +172,8 @@ SECTIONS | |||
172 | .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) { | 172 | .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) { |
173 | *(.x86_cpu_dev.init) | 173 | *(.x86_cpu_dev.init) |
174 | } | 174 | } |
175 | SECURITY_INIT | ||
176 | __x86_cpu_dev_end = .; | 175 | __x86_cpu_dev_end = .; |
176 | SECURITY_INIT | ||
177 | 177 | ||
178 | . = ALIGN(8); | 178 | . = ALIGN(8); |
179 | .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) { | 179 | .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) { |
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 6ab3196d12b4..10b52309aefd 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c | |||
@@ -614,7 +614,7 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size) | |||
614 | */ | 614 | */ |
615 | offset = phys_addr & ~PAGE_MASK; | 615 | offset = phys_addr & ~PAGE_MASK; |
616 | phys_addr &= PAGE_MASK; | 616 | phys_addr &= PAGE_MASK; |
617 | size = PAGE_ALIGN(last_addr) - phys_addr; | 617 | size = PAGE_ALIGN(last_addr + 1) - phys_addr; |
618 | 618 | ||
619 | /* | 619 | /* |
620 | * Mappings have to fit in the FIX_BTMAP area. | 620 | * Mappings have to fit in the FIX_BTMAP area. |
diff --git a/include/asm-generic/siginfo.h b/include/asm-generic/siginfo.h index 8786e01e0db8..969570167e9e 100644 --- a/include/asm-generic/siginfo.h +++ b/include/asm-generic/siginfo.h | |||
@@ -199,6 +199,8 @@ typedef struct siginfo { | |||
199 | */ | 199 | */ |
200 | #define TRAP_BRKPT (__SI_FAULT|1) /* process breakpoint */ | 200 | #define TRAP_BRKPT (__SI_FAULT|1) /* process breakpoint */ |
201 | #define TRAP_TRACE (__SI_FAULT|2) /* process trace trap */ | 201 | #define TRAP_TRACE (__SI_FAULT|2) /* process trace trap */ |
202 | #define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */ | ||
203 | #define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint/watchpoint */ | ||
202 | #define NSIGTRAP 2 | 204 | #define NSIGTRAP 2 |
203 | 205 | ||
204 | /* | 206 | /* |
diff --git a/include/asm-parisc/siginfo.h b/include/asm-parisc/siginfo.h index d4909f55fe35..d7034728f377 100644 --- a/include/asm-parisc/siginfo.h +++ b/include/asm-parisc/siginfo.h | |||
@@ -3,11 +3,6 @@ | |||
3 | 3 | ||
4 | #include <asm-generic/siginfo.h> | 4 | #include <asm-generic/siginfo.h> |
5 | 5 | ||
6 | /* | ||
7 | * SIGTRAP si_codes | ||
8 | */ | ||
9 | #define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */ | ||
10 | #define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint or watchpoint */ | ||
11 | #undef NSIGTRAP | 6 | #undef NSIGTRAP |
12 | #define NSIGTRAP 4 | 7 | #define NSIGTRAP 4 |
13 | 8 | ||
diff --git a/include/asm-x86/ptrace.h b/include/asm-x86/ptrace.h index d64a61097165..ac578f11c1c5 100644 --- a/include/asm-x86/ptrace.h +++ b/include/asm-x86/ptrace.h | |||
@@ -177,11 +177,11 @@ convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs); | |||
177 | 177 | ||
178 | #ifdef CONFIG_X86_32 | 178 | #ifdef CONFIG_X86_32 |
179 | extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, | 179 | extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, |
180 | int error_code); | 180 | int error_code, int si_code); |
181 | #else | ||
182 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where); | ||
183 | #endif | 181 | #endif |
184 | 182 | ||
183 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where); | ||
184 | |||
185 | extern long syscall_trace_enter(struct pt_regs *); | 185 | extern long syscall_trace_enter(struct pt_regs *); |
186 | extern void syscall_trace_leave(struct pt_regs *); | 186 | extern void syscall_trace_leave(struct pt_regs *); |
187 | 187 | ||
diff --git a/include/asm-x86/spinlock.h b/include/asm-x86/spinlock.h index 8badab09146b..157ff7fab97a 100644 --- a/include/asm-x86/spinlock.h +++ b/include/asm-x86/spinlock.h | |||
@@ -21,8 +21,10 @@ | |||
21 | 21 | ||
22 | #ifdef CONFIG_X86_32 | 22 | #ifdef CONFIG_X86_32 |
23 | # define LOCK_PTR_REG "a" | 23 | # define LOCK_PTR_REG "a" |
24 | # define REG_PTR_MODE "k" | ||
24 | #else | 25 | #else |
25 | # define LOCK_PTR_REG "D" | 26 | # define LOCK_PTR_REG "D" |
27 | # define REG_PTR_MODE "q" | ||
26 | #endif | 28 | #endif |
27 | 29 | ||
28 | #if defined(CONFIG_X86_32) && \ | 30 | #if defined(CONFIG_X86_32) && \ |
@@ -54,19 +56,7 @@ | |||
54 | * much between them in performance though, especially as locks are out of line. | 56 | * much between them in performance though, especially as locks are out of line. |
55 | */ | 57 | */ |
56 | #if (NR_CPUS < 256) | 58 | #if (NR_CPUS < 256) |
57 | static inline int __ticket_spin_is_locked(raw_spinlock_t *lock) | 59 | #define TICKET_SHIFT 8 |
58 | { | ||
59 | int tmp = ACCESS_ONCE(lock->slock); | ||
60 | |||
61 | return (((tmp >> 8) & 0xff) != (tmp & 0xff)); | ||
62 | } | ||
63 | |||
64 | static inline int __ticket_spin_is_contended(raw_spinlock_t *lock) | ||
65 | { | ||
66 | int tmp = ACCESS_ONCE(lock->slock); | ||
67 | |||
68 | return (((tmp >> 8) - tmp) & 0xff) > 1; | ||
69 | } | ||
70 | 60 | ||
71 | static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock) | 61 | static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock) |
72 | { | 62 | { |
@@ -89,19 +79,17 @@ static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock) | |||
89 | 79 | ||
90 | static __always_inline int __ticket_spin_trylock(raw_spinlock_t *lock) | 80 | static __always_inline int __ticket_spin_trylock(raw_spinlock_t *lock) |
91 | { | 81 | { |
92 | int tmp; | 82 | int tmp, new; |
93 | short new; | ||
94 | 83 | ||
95 | asm volatile("movw %2,%w0\n\t" | 84 | asm volatile("movzwl %2, %0\n\t" |
96 | "cmpb %h0,%b0\n\t" | 85 | "cmpb %h0,%b0\n\t" |
86 | "leal 0x100(%" REG_PTR_MODE "0), %1\n\t" | ||
97 | "jne 1f\n\t" | 87 | "jne 1f\n\t" |
98 | "movw %w0,%w1\n\t" | ||
99 | "incb %h1\n\t" | ||
100 | LOCK_PREFIX "cmpxchgw %w1,%2\n\t" | 88 | LOCK_PREFIX "cmpxchgw %w1,%2\n\t" |
101 | "1:" | 89 | "1:" |
102 | "sete %b1\n\t" | 90 | "sete %b1\n\t" |
103 | "movzbl %b1,%0\n\t" | 91 | "movzbl %b1,%0\n\t" |
104 | : "=&a" (tmp), "=Q" (new), "+m" (lock->slock) | 92 | : "=&a" (tmp), "=&q" (new), "+m" (lock->slock) |
105 | : | 93 | : |
106 | : "memory", "cc"); | 94 | : "memory", "cc"); |
107 | 95 | ||
@@ -116,19 +104,7 @@ static __always_inline void __ticket_spin_unlock(raw_spinlock_t *lock) | |||
116 | : "memory", "cc"); | 104 | : "memory", "cc"); |
117 | } | 105 | } |
118 | #else | 106 | #else |
119 | static inline int __ticket_spin_is_locked(raw_spinlock_t *lock) | 107 | #define TICKET_SHIFT 16 |
120 | { | ||
121 | int tmp = ACCESS_ONCE(lock->slock); | ||
122 | |||
123 | return (((tmp >> 16) & 0xffff) != (tmp & 0xffff)); | ||
124 | } | ||
125 | |||
126 | static inline int __ticket_spin_is_contended(raw_spinlock_t *lock) | ||
127 | { | ||
128 | int tmp = ACCESS_ONCE(lock->slock); | ||
129 | |||
130 | return (((tmp >> 16) - tmp) & 0xffff) > 1; | ||
131 | } | ||
132 | 108 | ||
133 | static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock) | 109 | static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock) |
134 | { | 110 | { |
@@ -146,7 +122,7 @@ static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock) | |||
146 | /* don't need lfence here, because loads are in-order */ | 122 | /* don't need lfence here, because loads are in-order */ |
147 | "jmp 1b\n" | 123 | "jmp 1b\n" |
148 | "2:" | 124 | "2:" |
149 | : "+Q" (inc), "+m" (lock->slock), "=r" (tmp) | 125 | : "+r" (inc), "+m" (lock->slock), "=&r" (tmp) |
150 | : | 126 | : |
151 | : "memory", "cc"); | 127 | : "memory", "cc"); |
152 | } | 128 | } |
@@ -160,13 +136,13 @@ static __always_inline int __ticket_spin_trylock(raw_spinlock_t *lock) | |||
160 | "movl %0,%1\n\t" | 136 | "movl %0,%1\n\t" |
161 | "roll $16, %0\n\t" | 137 | "roll $16, %0\n\t" |
162 | "cmpl %0,%1\n\t" | 138 | "cmpl %0,%1\n\t" |
139 | "leal 0x00010000(%" REG_PTR_MODE "0), %1\n\t" | ||
163 | "jne 1f\n\t" | 140 | "jne 1f\n\t" |
164 | "addl $0x00010000, %1\n\t" | ||
165 | LOCK_PREFIX "cmpxchgl %1,%2\n\t" | 141 | LOCK_PREFIX "cmpxchgl %1,%2\n\t" |
166 | "1:" | 142 | "1:" |
167 | "sete %b1\n\t" | 143 | "sete %b1\n\t" |
168 | "movzbl %b1,%0\n\t" | 144 | "movzbl %b1,%0\n\t" |
169 | : "=&a" (tmp), "=r" (new), "+m" (lock->slock) | 145 | : "=&a" (tmp), "=&q" (new), "+m" (lock->slock) |
170 | : | 146 | : |
171 | : "memory", "cc"); | 147 | : "memory", "cc"); |
172 | 148 | ||
@@ -182,6 +158,20 @@ static __always_inline void __ticket_spin_unlock(raw_spinlock_t *lock) | |||
182 | } | 158 | } |
183 | #endif | 159 | #endif |
184 | 160 | ||
161 | static inline int __ticket_spin_is_locked(raw_spinlock_t *lock) | ||
162 | { | ||
163 | int tmp = ACCESS_ONCE(lock->slock); | ||
164 | |||
165 | return !!(((tmp >> TICKET_SHIFT) ^ tmp) & ((1 << TICKET_SHIFT) - 1)); | ||
166 | } | ||
167 | |||
168 | static inline int __ticket_spin_is_contended(raw_spinlock_t *lock) | ||
169 | { | ||
170 | int tmp = ACCESS_ONCE(lock->slock); | ||
171 | |||
172 | return (((tmp >> TICKET_SHIFT) - tmp) & ((1 << TICKET_SHIFT) - 1)) > 1; | ||
173 | } | ||
174 | |||
185 | #ifdef CONFIG_PARAVIRT | 175 | #ifdef CONFIG_PARAVIRT |
186 | /* | 176 | /* |
187 | * Define virtualization-friendly old-style lock byte lock, for use in | 177 | * Define virtualization-friendly old-style lock byte lock, for use in |
diff --git a/include/asm-x86/traps.h b/include/asm-x86/traps.h index 2ccebc6fb0b0..7a692baa51ae 100644 --- a/include/asm-x86/traps.h +++ b/include/asm-x86/traps.h | |||
@@ -1,6 +1,8 @@ | |||
1 | #ifndef ASM_X86__TRAPS_H | 1 | #ifndef ASM_X86__TRAPS_H |
2 | #define ASM_X86__TRAPS_H | 2 | #define ASM_X86__TRAPS_H |
3 | 3 | ||
4 | #include <asm/debugreg.h> | ||
5 | |||
4 | /* Common in X86_32 and X86_64 */ | 6 | /* Common in X86_32 and X86_64 */ |
5 | asmlinkage void divide_error(void); | 7 | asmlinkage void divide_error(void); |
6 | asmlinkage void debug(void); | 8 | asmlinkage void debug(void); |
@@ -36,6 +38,16 @@ void do_invalid_op(struct pt_regs *, long); | |||
36 | void do_general_protection(struct pt_regs *, long); | 38 | void do_general_protection(struct pt_regs *, long); |
37 | void do_nmi(struct pt_regs *, long); | 39 | void do_nmi(struct pt_regs *, long); |
38 | 40 | ||
41 | static inline int get_si_code(unsigned long condition) | ||
42 | { | ||
43 | if (condition & DR_STEP) | ||
44 | return TRAP_TRACE; | ||
45 | else if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) | ||
46 | return TRAP_HWBKPT; | ||
47 | else | ||
48 | return TRAP_BRKPT; | ||
49 | } | ||
50 | |||
39 | extern int panic_on_unrecovered_nmi; | 51 | extern int panic_on_unrecovered_nmi; |
40 | extern int kstack_depth_to_print; | 52 | extern int kstack_depth_to_print; |
41 | 53 | ||