diff options
Diffstat (limited to 'arch/x86')
| -rw-r--r-- | arch/x86/Kconfig | 1 | ||||
| -rw-r--r-- | arch/x86/include/asm/rcu.h | 32 | ||||
| -rw-r--r-- | arch/x86/include/asm/thread_info.h | 10 | ||||
| -rw-r--r-- | arch/x86/kernel/cpuid.c | 5 | ||||
| -rw-r--r-- | arch/x86/kernel/entry_64.S | 9 | ||||
| -rw-r--r-- | arch/x86/kernel/msr.c | 5 | ||||
| -rw-r--r-- | arch/x86/kernel/ptrace.c | 5 | ||||
| -rw-r--r-- | arch/x86/kernel/signal.c | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/traps.c | 109 | ||||
| -rw-r--r-- | arch/x86/mm/fault.c | 13 |
10 files changed, 141 insertions, 52 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 50a1d1f9b6d3..20c49b8450b8 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -97,6 +97,7 @@ config X86 | |||
| 97 | select KTIME_SCALAR if X86_32 | 97 | select KTIME_SCALAR if X86_32 |
| 98 | select GENERIC_STRNCPY_FROM_USER | 98 | select GENERIC_STRNCPY_FROM_USER |
| 99 | select GENERIC_STRNLEN_USER | 99 | select GENERIC_STRNLEN_USER |
| 100 | select HAVE_RCU_USER_QS if X86_64 | ||
| 100 | 101 | ||
| 101 | config INSTRUCTION_DECODER | 102 | config INSTRUCTION_DECODER |
| 102 | def_bool (KPROBES || PERF_EVENTS || UPROBES) | 103 | def_bool (KPROBES || PERF_EVENTS || UPROBES) |
diff --git a/arch/x86/include/asm/rcu.h b/arch/x86/include/asm/rcu.h new file mode 100644 index 000000000000..d1ac07a23979 --- /dev/null +++ b/arch/x86/include/asm/rcu.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | #ifndef _ASM_X86_RCU_H | ||
| 2 | #define _ASM_X86_RCU_H | ||
| 3 | |||
| 4 | #ifndef __ASSEMBLY__ | ||
| 5 | |||
| 6 | #include <linux/rcupdate.h> | ||
| 7 | #include <asm/ptrace.h> | ||
| 8 | |||
| 9 | static inline void exception_enter(struct pt_regs *regs) | ||
| 10 | { | ||
| 11 | rcu_user_exit(); | ||
| 12 | } | ||
| 13 | |||
| 14 | static inline void exception_exit(struct pt_regs *regs) | ||
| 15 | { | ||
| 16 | #ifdef CONFIG_RCU_USER_QS | ||
| 17 | if (user_mode(regs)) | ||
| 18 | rcu_user_enter(); | ||
| 19 | #endif | ||
| 20 | } | ||
| 21 | |||
| 22 | #else /* __ASSEMBLY__ */ | ||
| 23 | |||
| 24 | #ifdef CONFIG_RCU_USER_QS | ||
| 25 | # define SCHEDULE_USER call schedule_user | ||
| 26 | #else | ||
| 27 | # define SCHEDULE_USER call schedule | ||
| 28 | #endif | ||
| 29 | |||
| 30 | #endif /* !__ASSEMBLY__ */ | ||
| 31 | |||
| 32 | #endif | ||
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 89f794f007ec..c535d847e3b5 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h | |||
| @@ -89,6 +89,7 @@ struct thread_info { | |||
| 89 | #define TIF_NOTSC 16 /* TSC is not accessible in userland */ | 89 | #define TIF_NOTSC 16 /* TSC is not accessible in userland */ |
| 90 | #define TIF_IA32 17 /* IA32 compatibility process */ | 90 | #define TIF_IA32 17 /* IA32 compatibility process */ |
| 91 | #define TIF_FORK 18 /* ret_from_fork */ | 91 | #define TIF_FORK 18 /* ret_from_fork */ |
| 92 | #define TIF_NOHZ 19 /* in adaptive nohz mode */ | ||
| 92 | #define TIF_MEMDIE 20 /* is terminating due to OOM killer */ | 93 | #define TIF_MEMDIE 20 /* is terminating due to OOM killer */ |
| 93 | #define TIF_DEBUG 21 /* uses debug registers */ | 94 | #define TIF_DEBUG 21 /* uses debug registers */ |
| 94 | #define TIF_IO_BITMAP 22 /* uses I/O bitmap */ | 95 | #define TIF_IO_BITMAP 22 /* uses I/O bitmap */ |
| @@ -114,6 +115,7 @@ struct thread_info { | |||
| 114 | #define _TIF_NOTSC (1 << TIF_NOTSC) | 115 | #define _TIF_NOTSC (1 << TIF_NOTSC) |
| 115 | #define _TIF_IA32 (1 << TIF_IA32) | 116 | #define _TIF_IA32 (1 << TIF_IA32) |
| 116 | #define _TIF_FORK (1 << TIF_FORK) | 117 | #define _TIF_FORK (1 << TIF_FORK) |
| 118 | #define _TIF_NOHZ (1 << TIF_NOHZ) | ||
| 117 | #define _TIF_DEBUG (1 << TIF_DEBUG) | 119 | #define _TIF_DEBUG (1 << TIF_DEBUG) |
| 118 | #define _TIF_IO_BITMAP (1 << TIF_IO_BITMAP) | 120 | #define _TIF_IO_BITMAP (1 << TIF_IO_BITMAP) |
| 119 | #define _TIF_FORCED_TF (1 << TIF_FORCED_TF) | 121 | #define _TIF_FORCED_TF (1 << TIF_FORCED_TF) |
| @@ -126,12 +128,13 @@ struct thread_info { | |||
| 126 | /* work to do in syscall_trace_enter() */ | 128 | /* work to do in syscall_trace_enter() */ |
| 127 | #define _TIF_WORK_SYSCALL_ENTRY \ | 129 | #define _TIF_WORK_SYSCALL_ENTRY \ |
| 128 | (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | _TIF_SYSCALL_AUDIT | \ | 130 | (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | _TIF_SYSCALL_AUDIT | \ |
| 129 | _TIF_SECCOMP | _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT) | 131 | _TIF_SECCOMP | _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT | \ |
| 132 | _TIF_NOHZ) | ||
| 130 | 133 | ||
| 131 | /* work to do in syscall_trace_leave() */ | 134 | /* work to do in syscall_trace_leave() */ |
| 132 | #define _TIF_WORK_SYSCALL_EXIT \ | 135 | #define _TIF_WORK_SYSCALL_EXIT \ |
| 133 | (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP | \ | 136 | (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP | \ |
| 134 | _TIF_SYSCALL_TRACEPOINT) | 137 | _TIF_SYSCALL_TRACEPOINT | _TIF_NOHZ) |
| 135 | 138 | ||
| 136 | /* work to do on interrupt/exception return */ | 139 | /* work to do on interrupt/exception return */ |
| 137 | #define _TIF_WORK_MASK \ | 140 | #define _TIF_WORK_MASK \ |
| @@ -141,7 +144,8 @@ struct thread_info { | |||
| 141 | 144 | ||
| 142 | /* work to do on any return to user space */ | 145 | /* work to do on any return to user space */ |
| 143 | #define _TIF_ALLWORK_MASK \ | 146 | #define _TIF_ALLWORK_MASK \ |
| 144 | ((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT) | 147 | ((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT | \ |
| 148 | _TIF_NOHZ) | ||
| 145 | 149 | ||
| 146 | /* Only used for 64 bit */ | 150 | /* Only used for 64 bit */ |
| 147 | #define _TIF_DO_NOTIFY_MASK \ | 151 | #define _TIF_DO_NOTIFY_MASK \ |
diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c index 39472dd2323f..60c78917190c 100644 --- a/arch/x86/kernel/cpuid.c +++ b/arch/x86/kernel/cpuid.c | |||
| @@ -199,12 +199,14 @@ static int __init cpuid_init(void) | |||
| 199 | goto out_chrdev; | 199 | goto out_chrdev; |
| 200 | } | 200 | } |
| 201 | cpuid_class->devnode = cpuid_devnode; | 201 | cpuid_class->devnode = cpuid_devnode; |
| 202 | get_online_cpus(); | ||
| 202 | for_each_online_cpu(i) { | 203 | for_each_online_cpu(i) { |
| 203 | err = cpuid_device_create(i); | 204 | err = cpuid_device_create(i); |
| 204 | if (err != 0) | 205 | if (err != 0) |
| 205 | goto out_class; | 206 | goto out_class; |
| 206 | } | 207 | } |
| 207 | register_hotcpu_notifier(&cpuid_class_cpu_notifier); | 208 | register_hotcpu_notifier(&cpuid_class_cpu_notifier); |
| 209 | put_online_cpus(); | ||
| 208 | 210 | ||
| 209 | err = 0; | 211 | err = 0; |
| 210 | goto out; | 212 | goto out; |
| @@ -214,6 +216,7 @@ out_class: | |||
| 214 | for_each_online_cpu(i) { | 216 | for_each_online_cpu(i) { |
| 215 | cpuid_device_destroy(i); | 217 | cpuid_device_destroy(i); |
| 216 | } | 218 | } |
| 219 | put_online_cpus(); | ||
| 217 | class_destroy(cpuid_class); | 220 | class_destroy(cpuid_class); |
| 218 | out_chrdev: | 221 | out_chrdev: |
| 219 | __unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid"); | 222 | __unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid"); |
| @@ -225,11 +228,13 @@ static void __exit cpuid_exit(void) | |||
| 225 | { | 228 | { |
| 226 | int cpu = 0; | 229 | int cpu = 0; |
| 227 | 230 | ||
| 231 | get_online_cpus(); | ||
| 228 | for_each_online_cpu(cpu) | 232 | for_each_online_cpu(cpu) |
| 229 | cpuid_device_destroy(cpu); | 233 | cpuid_device_destroy(cpu); |
| 230 | class_destroy(cpuid_class); | 234 | class_destroy(cpuid_class); |
| 231 | __unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid"); | 235 | __unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid"); |
| 232 | unregister_hotcpu_notifier(&cpuid_class_cpu_notifier); | 236 | unregister_hotcpu_notifier(&cpuid_class_cpu_notifier); |
| 237 | put_online_cpus(); | ||
| 233 | } | 238 | } |
| 234 | 239 | ||
| 235 | module_init(cpuid_init); | 240 | module_init(cpuid_init); |
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 69babd8c834f..1a8f3cbb6ee3 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
| @@ -56,6 +56,7 @@ | |||
| 56 | #include <asm/ftrace.h> | 56 | #include <asm/ftrace.h> |
| 57 | #include <asm/percpu.h> | 57 | #include <asm/percpu.h> |
| 58 | #include <asm/asm.h> | 58 | #include <asm/asm.h> |
| 59 | #include <asm/rcu.h> | ||
| 59 | #include <linux/err.h> | 60 | #include <linux/err.h> |
| 60 | 61 | ||
| 61 | /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */ | 62 | /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */ |
| @@ -565,7 +566,7 @@ sysret_careful: | |||
| 565 | TRACE_IRQS_ON | 566 | TRACE_IRQS_ON |
| 566 | ENABLE_INTERRUPTS(CLBR_NONE) | 567 | ENABLE_INTERRUPTS(CLBR_NONE) |
| 567 | pushq_cfi %rdi | 568 | pushq_cfi %rdi |
| 568 | call schedule | 569 | SCHEDULE_USER |
| 569 | popq_cfi %rdi | 570 | popq_cfi %rdi |
| 570 | jmp sysret_check | 571 | jmp sysret_check |
| 571 | 572 | ||
| @@ -678,7 +679,7 @@ int_careful: | |||
| 678 | TRACE_IRQS_ON | 679 | TRACE_IRQS_ON |
| 679 | ENABLE_INTERRUPTS(CLBR_NONE) | 680 | ENABLE_INTERRUPTS(CLBR_NONE) |
| 680 | pushq_cfi %rdi | 681 | pushq_cfi %rdi |
| 681 | call schedule | 682 | SCHEDULE_USER |
| 682 | popq_cfi %rdi | 683 | popq_cfi %rdi |
| 683 | DISABLE_INTERRUPTS(CLBR_NONE) | 684 | DISABLE_INTERRUPTS(CLBR_NONE) |
| 684 | TRACE_IRQS_OFF | 685 | TRACE_IRQS_OFF |
| @@ -974,7 +975,7 @@ retint_careful: | |||
| 974 | TRACE_IRQS_ON | 975 | TRACE_IRQS_ON |
| 975 | ENABLE_INTERRUPTS(CLBR_NONE) | 976 | ENABLE_INTERRUPTS(CLBR_NONE) |
| 976 | pushq_cfi %rdi | 977 | pushq_cfi %rdi |
| 977 | call schedule | 978 | SCHEDULE_USER |
| 978 | popq_cfi %rdi | 979 | popq_cfi %rdi |
| 979 | GET_THREAD_INFO(%rcx) | 980 | GET_THREAD_INFO(%rcx) |
| 980 | DISABLE_INTERRUPTS(CLBR_NONE) | 981 | DISABLE_INTERRUPTS(CLBR_NONE) |
| @@ -1449,7 +1450,7 @@ paranoid_userspace: | |||
| 1449 | paranoid_schedule: | 1450 | paranoid_schedule: |
| 1450 | TRACE_IRQS_ON | 1451 | TRACE_IRQS_ON |
| 1451 | ENABLE_INTERRUPTS(CLBR_ANY) | 1452 | ENABLE_INTERRUPTS(CLBR_ANY) |
| 1452 | call schedule | 1453 | SCHEDULE_USER |
| 1453 | DISABLE_INTERRUPTS(CLBR_ANY) | 1454 | DISABLE_INTERRUPTS(CLBR_ANY) |
| 1454 | TRACE_IRQS_OFF | 1455 | TRACE_IRQS_OFF |
| 1455 | jmp paranoid_userspace | 1456 | jmp paranoid_userspace |
diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c index eb113693f043..a7c5661f8496 100644 --- a/arch/x86/kernel/msr.c +++ b/arch/x86/kernel/msr.c | |||
| @@ -257,12 +257,14 @@ static int __init msr_init(void) | |||
| 257 | goto out_chrdev; | 257 | goto out_chrdev; |
| 258 | } | 258 | } |
| 259 | msr_class->devnode = msr_devnode; | 259 | msr_class->devnode = msr_devnode; |
| 260 | get_online_cpus(); | ||
| 260 | for_each_online_cpu(i) { | 261 | for_each_online_cpu(i) { |
| 261 | err = msr_device_create(i); | 262 | err = msr_device_create(i); |
| 262 | if (err != 0) | 263 | if (err != 0) |
| 263 | goto out_class; | 264 | goto out_class; |
| 264 | } | 265 | } |
| 265 | register_hotcpu_notifier(&msr_class_cpu_notifier); | 266 | register_hotcpu_notifier(&msr_class_cpu_notifier); |
| 267 | put_online_cpus(); | ||
| 266 | 268 | ||
| 267 | err = 0; | 269 | err = 0; |
| 268 | goto out; | 270 | goto out; |
| @@ -271,6 +273,7 @@ out_class: | |||
| 271 | i = 0; | 273 | i = 0; |
| 272 | for_each_online_cpu(i) | 274 | for_each_online_cpu(i) |
| 273 | msr_device_destroy(i); | 275 | msr_device_destroy(i); |
| 276 | put_online_cpus(); | ||
| 274 | class_destroy(msr_class); | 277 | class_destroy(msr_class); |
| 275 | out_chrdev: | 278 | out_chrdev: |
| 276 | __unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr"); | 279 | __unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr"); |
| @@ -281,11 +284,13 @@ out: | |||
| 281 | static void __exit msr_exit(void) | 284 | static void __exit msr_exit(void) |
| 282 | { | 285 | { |
| 283 | int cpu = 0; | 286 | int cpu = 0; |
| 287 | get_online_cpus(); | ||
| 284 | for_each_online_cpu(cpu) | 288 | for_each_online_cpu(cpu) |
| 285 | msr_device_destroy(cpu); | 289 | msr_device_destroy(cpu); |
| 286 | class_destroy(msr_class); | 290 | class_destroy(msr_class); |
| 287 | __unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr"); | 291 | __unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr"); |
| 288 | unregister_hotcpu_notifier(&msr_class_cpu_notifier); | 292 | unregister_hotcpu_notifier(&msr_class_cpu_notifier); |
| 293 | put_online_cpus(); | ||
| 289 | } | 294 | } |
| 290 | 295 | ||
| 291 | module_init(msr_init); | 296 | module_init(msr_init); |
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index c4c6a5c2bf0f..9f94f8ec26e4 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/signal.h> | 21 | #include <linux/signal.h> |
| 22 | #include <linux/perf_event.h> | 22 | #include <linux/perf_event.h> |
| 23 | #include <linux/hw_breakpoint.h> | 23 | #include <linux/hw_breakpoint.h> |
| 24 | #include <linux/rcupdate.h> | ||
| 24 | 25 | ||
| 25 | #include <asm/uaccess.h> | 26 | #include <asm/uaccess.h> |
| 26 | #include <asm/pgtable.h> | 27 | #include <asm/pgtable.h> |
| @@ -1463,6 +1464,8 @@ long syscall_trace_enter(struct pt_regs *regs) | |||
| 1463 | { | 1464 | { |
| 1464 | long ret = 0; | 1465 | long ret = 0; |
| 1465 | 1466 | ||
| 1467 | rcu_user_exit(); | ||
| 1468 | |||
| 1466 | /* | 1469 | /* |
| 1467 | * If we stepped into a sysenter/syscall insn, it trapped in | 1470 | * If we stepped into a sysenter/syscall insn, it trapped in |
| 1468 | * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP. | 1471 | * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP. |
| @@ -1526,4 +1529,6 @@ void syscall_trace_leave(struct pt_regs *regs) | |||
| 1526 | !test_thread_flag(TIF_SYSCALL_EMU); | 1529 | !test_thread_flag(TIF_SYSCALL_EMU); |
| 1527 | if (step || test_thread_flag(TIF_SYSCALL_TRACE)) | 1530 | if (step || test_thread_flag(TIF_SYSCALL_TRACE)) |
| 1528 | tracehook_report_syscall_exit(regs, step); | 1531 | tracehook_report_syscall_exit(regs, step); |
| 1532 | |||
| 1533 | rcu_user_enter(); | ||
| 1529 | } | 1534 | } |
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index b280908a376e..bca0ab903e57 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c | |||
| @@ -779,6 +779,8 @@ static void do_signal(struct pt_regs *regs) | |||
| 779 | void | 779 | void |
| 780 | do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) | 780 | do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) |
| 781 | { | 781 | { |
| 782 | rcu_user_exit(); | ||
| 783 | |||
| 782 | #ifdef CONFIG_X86_MCE | 784 | #ifdef CONFIG_X86_MCE |
| 783 | /* notify userspace of pending MCEs */ | 785 | /* notify userspace of pending MCEs */ |
| 784 | if (thread_info_flags & _TIF_MCE_NOTIFY) | 786 | if (thread_info_flags & _TIF_MCE_NOTIFY) |
| @@ -804,6 +806,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) | |||
| 804 | #ifdef CONFIG_X86_32 | 806 | #ifdef CONFIG_X86_32 |
| 805 | clear_thread_flag(TIF_IRET); | 807 | clear_thread_flag(TIF_IRET); |
| 806 | #endif /* CONFIG_X86_32 */ | 808 | #endif /* CONFIG_X86_32 */ |
| 809 | |||
| 810 | rcu_user_enter(); | ||
| 807 | } | 811 | } |
| 808 | 812 | ||
| 809 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where) | 813 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where) |
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index b481341c9369..378967578f22 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c | |||
| @@ -55,6 +55,7 @@ | |||
| 55 | #include <asm/i387.h> | 55 | #include <asm/i387.h> |
| 56 | #include <asm/fpu-internal.h> | 56 | #include <asm/fpu-internal.h> |
| 57 | #include <asm/mce.h> | 57 | #include <asm/mce.h> |
| 58 | #include <asm/rcu.h> | ||
| 58 | 59 | ||
| 59 | #include <asm/mach_traps.h> | 60 | #include <asm/mach_traps.h> |
| 60 | 61 | ||
| @@ -180,11 +181,15 @@ vm86_trap: | |||
| 180 | #define DO_ERROR(trapnr, signr, str, name) \ | 181 | #define DO_ERROR(trapnr, signr, str, name) \ |
| 181 | dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ | 182 | dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ |
| 182 | { \ | 183 | { \ |
| 183 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | 184 | exception_enter(regs); \ |
| 184 | == NOTIFY_STOP) \ | 185 | if (notify_die(DIE_TRAP, str, regs, error_code, \ |
| 186 | trapnr, signr) == NOTIFY_STOP) { \ | ||
| 187 | exception_exit(regs); \ | ||
| 185 | return; \ | 188 | return; \ |
| 189 | } \ | ||
| 186 | conditional_sti(regs); \ | 190 | conditional_sti(regs); \ |
| 187 | do_trap(trapnr, signr, str, regs, error_code, NULL); \ | 191 | do_trap(trapnr, signr, str, regs, error_code, NULL); \ |
| 192 | exception_exit(regs); \ | ||
| 188 | } | 193 | } |
| 189 | 194 | ||
| 190 | #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ | 195 | #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ |
| @@ -195,11 +200,15 @@ dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ | |||
| 195 | info.si_errno = 0; \ | 200 | info.si_errno = 0; \ |
| 196 | info.si_code = sicode; \ | 201 | info.si_code = sicode; \ |
| 197 | info.si_addr = (void __user *)siaddr; \ | 202 | info.si_addr = (void __user *)siaddr; \ |
| 198 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | 203 | exception_enter(regs); \ |
| 199 | == NOTIFY_STOP) \ | 204 | if (notify_die(DIE_TRAP, str, regs, error_code, \ |
| 205 | trapnr, signr) == NOTIFY_STOP) { \ | ||
| 206 | exception_exit(regs); \ | ||
| 200 | return; \ | 207 | return; \ |
| 208 | } \ | ||
| 201 | conditional_sti(regs); \ | 209 | conditional_sti(regs); \ |
| 202 | do_trap(trapnr, signr, str, regs, error_code, &info); \ | 210 | do_trap(trapnr, signr, str, regs, error_code, &info); \ |
| 211 | exception_exit(regs); \ | ||
| 203 | } | 212 | } |
| 204 | 213 | ||
| 205 | DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV, | 214 | DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV, |
| @@ -222,12 +231,14 @@ DO_ERROR_INFO(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check, | |||
| 222 | /* Runs on IST stack */ | 231 | /* Runs on IST stack */ |
| 223 | dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code) | 232 | dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code) |
| 224 | { | 233 | { |
| 234 | exception_enter(regs); | ||
| 225 | if (notify_die(DIE_TRAP, "stack segment", regs, error_code, | 235 | if (notify_die(DIE_TRAP, "stack segment", regs, error_code, |
| 226 | X86_TRAP_SS, SIGBUS) == NOTIFY_STOP) | 236 | X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) { |
| 227 | return; | 237 | preempt_conditional_sti(regs); |
| 228 | preempt_conditional_sti(regs); | 238 | do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL); |
| 229 | do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL); | 239 | preempt_conditional_cli(regs); |
| 230 | preempt_conditional_cli(regs); | 240 | } |
| 241 | exception_exit(regs); | ||
| 231 | } | 242 | } |
| 232 | 243 | ||
| 233 | dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) | 244 | dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) |
| @@ -235,6 +246,7 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) | |||
| 235 | static const char str[] = "double fault"; | 246 | static const char str[] = "double fault"; |
| 236 | struct task_struct *tsk = current; | 247 | struct task_struct *tsk = current; |
| 237 | 248 | ||
| 249 | exception_enter(regs); | ||
| 238 | /* Return not checked because double check cannot be ignored */ | 250 | /* Return not checked because double check cannot be ignored */ |
| 239 | notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV); | 251 | notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV); |
| 240 | 252 | ||
| @@ -255,16 +267,29 @@ do_general_protection(struct pt_regs *regs, long error_code) | |||
| 255 | { | 267 | { |
| 256 | struct task_struct *tsk; | 268 | struct task_struct *tsk; |
| 257 | 269 | ||
| 270 | exception_enter(regs); | ||
| 258 | conditional_sti(regs); | 271 | conditional_sti(regs); |
| 259 | 272 | ||
| 260 | #ifdef CONFIG_X86_32 | 273 | #ifdef CONFIG_X86_32 |
| 261 | if (regs->flags & X86_VM_MASK) | 274 | if (regs->flags & X86_VM_MASK) { |
| 262 | goto gp_in_vm86; | 275 | local_irq_enable(); |
| 276 | handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); | ||
| 277 | goto exit; | ||
| 278 | } | ||
| 263 | #endif | 279 | #endif |
| 264 | 280 | ||
| 265 | tsk = current; | 281 | tsk = current; |
| 266 | if (!user_mode(regs)) | 282 | if (!user_mode(regs)) { |
| 267 | goto gp_in_kernel; | 283 | if (fixup_exception(regs)) |
| 284 | goto exit; | ||
| 285 | |||
| 286 | tsk->thread.error_code = error_code; | ||
| 287 | tsk->thread.trap_nr = X86_TRAP_GP; | ||
| 288 | if (notify_die(DIE_GPF, "general protection fault", regs, error_code, | ||
| 289 | X86_TRAP_GP, SIGSEGV) != NOTIFY_STOP) | ||
| 290 | die("general protection fault", regs, error_code); | ||
| 291 | goto exit; | ||
| 292 | } | ||
| 268 | 293 | ||
| 269 | tsk->thread.error_code = error_code; | 294 | tsk->thread.error_code = error_code; |
| 270 | tsk->thread.trap_nr = X86_TRAP_GP; | 295 | tsk->thread.trap_nr = X86_TRAP_GP; |
| @@ -279,25 +304,8 @@ do_general_protection(struct pt_regs *regs, long error_code) | |||
| 279 | } | 304 | } |
| 280 | 305 | ||
| 281 | force_sig(SIGSEGV, tsk); | 306 | force_sig(SIGSEGV, tsk); |
| 282 | return; | 307 | exit: |
| 283 | 308 | exception_exit(regs); | |
| 284 | #ifdef CONFIG_X86_32 | ||
| 285 | gp_in_vm86: | ||
| 286 | local_irq_enable(); | ||
| 287 | handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); | ||
| 288 | return; | ||
| 289 | #endif | ||
| 290 | |||
| 291 | gp_in_kernel: | ||
| 292 | if (fixup_exception(regs)) | ||
| 293 | return; | ||
| 294 | |||
| 295 | tsk->thread.error_code = error_code; | ||
| 296 | tsk->thread.trap_nr = X86_TRAP_GP; | ||
| 297 | if (notify_die(DIE_GPF, "general protection fault", regs, error_code, | ||
| 298 | X86_TRAP_GP, SIGSEGV) == NOTIFY_STOP) | ||
| 299 | return; | ||
| 300 | die("general protection fault", regs, error_code); | ||
| 301 | } | 309 | } |
| 302 | 310 | ||
| 303 | /* May run on IST stack. */ | 311 | /* May run on IST stack. */ |
| @@ -312,15 +320,16 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co | |||
| 312 | ftrace_int3_handler(regs)) | 320 | ftrace_int3_handler(regs)) |
| 313 | return; | 321 | return; |
| 314 | #endif | 322 | #endif |
| 323 | exception_enter(regs); | ||
| 315 | #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP | 324 | #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP |
| 316 | if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, | 325 | if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, |
| 317 | SIGTRAP) == NOTIFY_STOP) | 326 | SIGTRAP) == NOTIFY_STOP) |
| 318 | return; | 327 | goto exit; |
| 319 | #endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */ | 328 | #endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */ |
| 320 | 329 | ||
| 321 | if (notify_die(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, | 330 | if (notify_die(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, |
| 322 | SIGTRAP) == NOTIFY_STOP) | 331 | SIGTRAP) == NOTIFY_STOP) |
| 323 | return; | 332 | goto exit; |
| 324 | 333 | ||
| 325 | /* | 334 | /* |
| 326 | * Let others (NMI) know that the debug stack is in use | 335 | * Let others (NMI) know that the debug stack is in use |
| @@ -331,6 +340,8 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co | |||
| 331 | do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL); | 340 | do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL); |
| 332 | preempt_conditional_cli(regs); | 341 | preempt_conditional_cli(regs); |
| 333 | debug_stack_usage_dec(); | 342 | debug_stack_usage_dec(); |
| 343 | exit: | ||
| 344 | exception_exit(regs); | ||
| 334 | } | 345 | } |
| 335 | 346 | ||
| 336 | #ifdef CONFIG_X86_64 | 347 | #ifdef CONFIG_X86_64 |
| @@ -391,6 +402,8 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) | |||
| 391 | unsigned long dr6; | 402 | unsigned long dr6; |
| 392 | int si_code; | 403 | int si_code; |
| 393 | 404 | ||
| 405 | exception_enter(regs); | ||
| 406 | |||
| 394 | get_debugreg(dr6, 6); | 407 | get_debugreg(dr6, 6); |
| 395 | 408 | ||
| 396 | /* Filter out all the reserved bits which are preset to 1 */ | 409 | /* Filter out all the reserved bits which are preset to 1 */ |
| @@ -406,7 +419,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) | |||
| 406 | 419 | ||
| 407 | /* Catch kmemcheck conditions first of all! */ | 420 | /* Catch kmemcheck conditions first of all! */ |
| 408 | if ((dr6 & DR_STEP) && kmemcheck_trap(regs)) | 421 | if ((dr6 & DR_STEP) && kmemcheck_trap(regs)) |
| 409 | return; | 422 | goto exit; |
| 410 | 423 | ||
| 411 | /* DR6 may or may not be cleared by the CPU */ | 424 | /* DR6 may or may not be cleared by the CPU */ |
| 412 | set_debugreg(0, 6); | 425 | set_debugreg(0, 6); |
| @@ -421,7 +434,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) | |||
| 421 | 434 | ||
| 422 | if (notify_die(DIE_DEBUG, "debug", regs, PTR_ERR(&dr6), error_code, | 435 | if (notify_die(DIE_DEBUG, "debug", regs, PTR_ERR(&dr6), error_code, |
| 423 | SIGTRAP) == NOTIFY_STOP) | 436 | SIGTRAP) == NOTIFY_STOP) |
| 424 | return; | 437 | goto exit; |
| 425 | 438 | ||
| 426 | /* | 439 | /* |
| 427 | * Let others (NMI) know that the debug stack is in use | 440 | * Let others (NMI) know that the debug stack is in use |
| @@ -437,7 +450,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) | |||
| 437 | X86_TRAP_DB); | 450 | X86_TRAP_DB); |
| 438 | preempt_conditional_cli(regs); | 451 | preempt_conditional_cli(regs); |
| 439 | debug_stack_usage_dec(); | 452 | debug_stack_usage_dec(); |
| 440 | return; | 453 | goto exit; |
| 441 | } | 454 | } |
| 442 | 455 | ||
| 443 | /* | 456 | /* |
| @@ -458,7 +471,8 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) | |||
| 458 | preempt_conditional_cli(regs); | 471 | preempt_conditional_cli(regs); |
| 459 | debug_stack_usage_dec(); | 472 | debug_stack_usage_dec(); |
| 460 | 473 | ||
| 461 | return; | 474 | exit: |
| 475 | exception_exit(regs); | ||
| 462 | } | 476 | } |
| 463 | 477 | ||
| 464 | /* | 478 | /* |
| @@ -555,14 +569,17 @@ dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code) | |||
| 555 | #ifdef CONFIG_X86_32 | 569 | #ifdef CONFIG_X86_32 |
| 556 | ignore_fpu_irq = 1; | 570 | ignore_fpu_irq = 1; |
| 557 | #endif | 571 | #endif |
| 558 | 572 | exception_enter(regs); | |
| 559 | math_error(regs, error_code, X86_TRAP_MF); | 573 | math_error(regs, error_code, X86_TRAP_MF); |
| 574 | exception_exit(regs); | ||
| 560 | } | 575 | } |
| 561 | 576 | ||
| 562 | dotraplinkage void | 577 | dotraplinkage void |
| 563 | do_simd_coprocessor_error(struct pt_regs *regs, long error_code) | 578 | do_simd_coprocessor_error(struct pt_regs *regs, long error_code) |
| 564 | { | 579 | { |
| 580 | exception_enter(regs); | ||
| 565 | math_error(regs, error_code, X86_TRAP_XF); | 581 | math_error(regs, error_code, X86_TRAP_XF); |
| 582 | exception_exit(regs); | ||
| 566 | } | 583 | } |
| 567 | 584 | ||
| 568 | dotraplinkage void | 585 | dotraplinkage void |
| @@ -629,6 +646,7 @@ EXPORT_SYMBOL_GPL(math_state_restore); | |||
| 629 | dotraplinkage void __kprobes | 646 | dotraplinkage void __kprobes |
| 630 | do_device_not_available(struct pt_regs *regs, long error_code) | 647 | do_device_not_available(struct pt_regs *regs, long error_code) |
| 631 | { | 648 | { |
| 649 | exception_enter(regs); | ||
| 632 | #ifdef CONFIG_MATH_EMULATION | 650 | #ifdef CONFIG_MATH_EMULATION |
| 633 | if (read_cr0() & X86_CR0_EM) { | 651 | if (read_cr0() & X86_CR0_EM) { |
| 634 | struct math_emu_info info = { }; | 652 | struct math_emu_info info = { }; |
| @@ -637,6 +655,7 @@ do_device_not_available(struct pt_regs *regs, long error_code) | |||
| 637 | 655 | ||
| 638 | info.regs = regs; | 656 | info.regs = regs; |
| 639 | math_emulate(&info); | 657 | math_emulate(&info); |
| 658 | exception_exit(regs); | ||
| 640 | return; | 659 | return; |
| 641 | } | 660 | } |
| 642 | #endif | 661 | #endif |
| @@ -644,12 +663,15 @@ do_device_not_available(struct pt_regs *regs, long error_code) | |||
| 644 | #ifdef CONFIG_X86_32 | 663 | #ifdef CONFIG_X86_32 |
| 645 | conditional_sti(regs); | 664 | conditional_sti(regs); |
| 646 | #endif | 665 | #endif |
| 666 | exception_exit(regs); | ||
| 647 | } | 667 | } |
| 648 | 668 | ||
| 649 | #ifdef CONFIG_X86_32 | 669 | #ifdef CONFIG_X86_32 |
| 650 | dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) | 670 | dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) |
| 651 | { | 671 | { |
| 652 | siginfo_t info; | 672 | siginfo_t info; |
| 673 | |||
| 674 | exception_enter(regs); | ||
| 653 | local_irq_enable(); | 675 | local_irq_enable(); |
| 654 | 676 | ||
| 655 | info.si_signo = SIGILL; | 677 | info.si_signo = SIGILL; |
| @@ -657,10 +679,11 @@ dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) | |||
| 657 | info.si_code = ILL_BADSTK; | 679 | info.si_code = ILL_BADSTK; |
| 658 | info.si_addr = NULL; | 680 | info.si_addr = NULL; |
| 659 | if (notify_die(DIE_TRAP, "iret exception", regs, error_code, | 681 | if (notify_die(DIE_TRAP, "iret exception", regs, error_code, |
| 660 | X86_TRAP_IRET, SIGILL) == NOTIFY_STOP) | 682 | X86_TRAP_IRET, SIGILL) != NOTIFY_STOP) { |
| 661 | return; | 683 | do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code, |
| 662 | do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code, | 684 | &info); |
| 663 | &info); | 685 | } |
| 686 | exception_exit(regs); | ||
| 664 | } | 687 | } |
| 665 | #endif | 688 | #endif |
| 666 | 689 | ||
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 76dcd9d8e0bc..7dde46d68a25 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <asm/pgalloc.h> /* pgd_*(), ... */ | 18 | #include <asm/pgalloc.h> /* pgd_*(), ... */ |
| 19 | #include <asm/kmemcheck.h> /* kmemcheck_*(), ... */ | 19 | #include <asm/kmemcheck.h> /* kmemcheck_*(), ... */ |
| 20 | #include <asm/fixmap.h> /* VSYSCALL_START */ | 20 | #include <asm/fixmap.h> /* VSYSCALL_START */ |
| 21 | #include <asm/rcu.h> /* exception_enter(), ... */ | ||
| 21 | 22 | ||
| 22 | /* | 23 | /* |
| 23 | * Page fault error code bits: | 24 | * Page fault error code bits: |
| @@ -1000,8 +1001,8 @@ static int fault_in_kernel_space(unsigned long address) | |||
| 1000 | * and the problem, and then passes it off to one of the appropriate | 1001 | * and the problem, and then passes it off to one of the appropriate |
| 1001 | * routines. | 1002 | * routines. |
| 1002 | */ | 1003 | */ |
| 1003 | dotraplinkage void __kprobes | 1004 | static void __kprobes |
| 1004 | do_page_fault(struct pt_regs *regs, unsigned long error_code) | 1005 | __do_page_fault(struct pt_regs *regs, unsigned long error_code) |
| 1005 | { | 1006 | { |
| 1006 | struct vm_area_struct *vma; | 1007 | struct vm_area_struct *vma; |
| 1007 | struct task_struct *tsk; | 1008 | struct task_struct *tsk; |
| @@ -1209,3 +1210,11 @@ good_area: | |||
| 1209 | 1210 | ||
| 1210 | up_read(&mm->mmap_sem); | 1211 | up_read(&mm->mmap_sem); |
| 1211 | } | 1212 | } |
| 1213 | |||
| 1214 | dotraplinkage void __kprobes | ||
| 1215 | do_page_fault(struct pt_regs *regs, unsigned long error_code) | ||
| 1216 | { | ||
| 1217 | exception_enter(regs); | ||
| 1218 | __do_page_fault(regs, error_code); | ||
| 1219 | exception_exit(regs); | ||
| 1220 | } | ||
