diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-17 16:03:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-17 16:03:05 -0400 |
commit | 6b6e177d632ee251c7c78d8f266a851ab9704879 (patch) | |
tree | 6feec072e7dd7eb32249369a1a80e6a904307e34 /arch/tile | |
parent | bfaf245022b4b8661af2e35f467cf0e91943c24c (diff) | |
parent | 128f3cb9398b5eeb4ee04b60bd5e314f5c122821 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile
Pull arch/tile updates from Chris Metcalf:
"These are mostly nohz_full changes, plus a smattering of minor fixes
(notably a couple for ftrace)"
* git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile:
tile: nohz: warn if nohz_full uses hypervisor shared cores
tile: ftrace: fix function_graph tracer issues
tile: map data region shadow of kernel as R/W
tile: support CONTEXT_TRACKING and thus NOHZ_FULL
tile: support arch_irq_work_raise
arch: tile: fix null pointer dereference on pt_regs pointer
tile/elf: reorganize notify_exec()
tile: use si_int instead of si_ptr for compat_siginfo
Diffstat (limited to 'arch/tile')
-rw-r--r-- | arch/tile/Kconfig | 1 | ||||
-rw-r--r-- | arch/tile/include/asm/Kbuild | 1 | ||||
-rw-r--r-- | arch/tile/include/asm/ftrace.h | 2 | ||||
-rw-r--r-- | arch/tile/include/asm/irq_work.h | 14 | ||||
-rw-r--r-- | arch/tile/include/asm/smp.h | 1 | ||||
-rw-r--r-- | arch/tile/include/asm/thread_info.h | 9 | ||||
-rw-r--r-- | arch/tile/include/hv/hypervisor.h | 6 | ||||
-rw-r--r-- | arch/tile/kernel/compat_signal.c | 11 | ||||
-rw-r--r-- | arch/tile/kernel/ftrace.c | 6 | ||||
-rw-r--r-- | arch/tile/kernel/mcount_64.S | 7 | ||||
-rw-r--r-- | arch/tile/kernel/process.c | 12 | ||||
-rw-r--r-- | arch/tile/kernel/ptrace.c | 22 | ||||
-rw-r--r-- | arch/tile/kernel/setup.c | 23 | ||||
-rw-r--r-- | arch/tile/kernel/single_step.c | 3 | ||||
-rw-r--r-- | arch/tile/kernel/smp.c | 32 | ||||
-rw-r--r-- | arch/tile/kernel/stack.c | 15 | ||||
-rw-r--r-- | arch/tile/kernel/traps.c | 16 | ||||
-rw-r--r-- | arch/tile/kernel/unaligned.c | 22 | ||||
-rw-r--r-- | arch/tile/mm/elf.c | 47 | ||||
-rw-r--r-- | arch/tile/mm/fault.c | 10 | ||||
-rw-r--r-- | arch/tile/mm/init.c | 7 |
21 files changed, 201 insertions, 66 deletions
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index 0142d578b5a8..a07e31b50d3f 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig | |||
@@ -27,6 +27,7 @@ config TILE | |||
27 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE | 27 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE |
28 | select HAVE_DEBUG_STACKOVERFLOW | 28 | select HAVE_DEBUG_STACKOVERFLOW |
29 | select ARCH_WANT_FRAME_POINTERS | 29 | select ARCH_WANT_FRAME_POINTERS |
30 | select HAVE_CONTEXT_TRACKING | ||
30 | 31 | ||
31 | # FIXME: investigate whether we need/want these options. | 32 | # FIXME: investigate whether we need/want these options. |
32 | # select HAVE_IOREMAP_PROT | 33 | # select HAVE_IOREMAP_PROT |
diff --git a/arch/tile/include/asm/Kbuild b/arch/tile/include/asm/Kbuild index b4c488b65745..f5433e0e34e0 100644 --- a/arch/tile/include/asm/Kbuild +++ b/arch/tile/include/asm/Kbuild | |||
@@ -16,7 +16,6 @@ generic-y += ioctl.h | |||
16 | generic-y += ioctls.h | 16 | generic-y += ioctls.h |
17 | generic-y += ipcbuf.h | 17 | generic-y += ipcbuf.h |
18 | generic-y += irq_regs.h | 18 | generic-y += irq_regs.h |
19 | generic-y += irq_work.h | ||
20 | generic-y += local.h | 19 | generic-y += local.h |
21 | generic-y += local64.h | 20 | generic-y += local64.h |
22 | generic-y += mcs_spinlock.h | 21 | generic-y += mcs_spinlock.h |
diff --git a/arch/tile/include/asm/ftrace.h b/arch/tile/include/asm/ftrace.h index 13a9bb81a8ab..738d239b792f 100644 --- a/arch/tile/include/asm/ftrace.h +++ b/arch/tile/include/asm/ftrace.h | |||
@@ -23,6 +23,8 @@ | |||
23 | #ifndef __ASSEMBLY__ | 23 | #ifndef __ASSEMBLY__ |
24 | extern void __mcount(void); | 24 | extern void __mcount(void); |
25 | 25 | ||
26 | #define ARCH_SUPPORTS_FTRACE_OPS 1 | ||
27 | |||
26 | #ifdef CONFIG_DYNAMIC_FTRACE | 28 | #ifdef CONFIG_DYNAMIC_FTRACE |
27 | static inline unsigned long ftrace_call_adjust(unsigned long addr) | 29 | static inline unsigned long ftrace_call_adjust(unsigned long addr) |
28 | { | 30 | { |
diff --git a/arch/tile/include/asm/irq_work.h b/arch/tile/include/asm/irq_work.h new file mode 100644 index 000000000000..48af33a61a2c --- /dev/null +++ b/arch/tile/include/asm/irq_work.h | |||
@@ -0,0 +1,14 @@ | |||
1 | #ifndef __ASM_IRQ_WORK_H | ||
2 | #define __ASM_IRQ_WORK_H | ||
3 | |||
4 | static inline bool arch_irq_work_has_interrupt(void) | ||
5 | { | ||
6 | #ifdef CONFIG_SMP | ||
7 | extern bool self_interrupt_ok; | ||
8 | return self_interrupt_ok; | ||
9 | #else | ||
10 | return false; | ||
11 | #endif | ||
12 | } | ||
13 | |||
14 | #endif /* __ASM_IRQ_WORK_H */ | ||
diff --git a/arch/tile/include/asm/smp.h b/arch/tile/include/asm/smp.h index 9a326b64f7ae..735e7f144733 100644 --- a/arch/tile/include/asm/smp.h +++ b/arch/tile/include/asm/smp.h | |||
@@ -69,6 +69,7 @@ static inline int xy_to_cpu(int x, int y) | |||
69 | #define MSG_TAG_STOP_CPU 2 | 69 | #define MSG_TAG_STOP_CPU 2 |
70 | #define MSG_TAG_CALL_FUNCTION_MANY 3 | 70 | #define MSG_TAG_CALL_FUNCTION_MANY 3 |
71 | #define MSG_TAG_CALL_FUNCTION_SINGLE 4 | 71 | #define MSG_TAG_CALL_FUNCTION_SINGLE 4 |
72 | #define MSG_TAG_IRQ_WORK 5 | ||
72 | 73 | ||
73 | /* Hook for the generic smp_call_function_many() routine. */ | 74 | /* Hook for the generic smp_call_function_many() routine. */ |
74 | static inline void arch_send_call_function_ipi_mask(struct cpumask *mask) | 75 | static inline void arch_send_call_function_ipi_mask(struct cpumask *mask) |
diff --git a/arch/tile/include/asm/thread_info.h b/arch/tile/include/asm/thread_info.h index 98ee10a0ae89..f804c39a5e4d 100644 --- a/arch/tile/include/asm/thread_info.h +++ b/arch/tile/include/asm/thread_info.h | |||
@@ -124,6 +124,7 @@ extern void _cpu_idle(void); | |||
124 | #define TIF_NOTIFY_RESUME 8 /* callback before returning to user */ | 124 | #define TIF_NOTIFY_RESUME 8 /* callback before returning to user */ |
125 | #define TIF_SYSCALL_TRACEPOINT 9 /* syscall tracepoint instrumentation */ | 125 | #define TIF_SYSCALL_TRACEPOINT 9 /* syscall tracepoint instrumentation */ |
126 | #define TIF_POLLING_NRFLAG 10 /* idle is polling for TIF_NEED_RESCHED */ | 126 | #define TIF_POLLING_NRFLAG 10 /* idle is polling for TIF_NEED_RESCHED */ |
127 | #define TIF_NOHZ 11 /* in adaptive nohz mode */ | ||
127 | 128 | ||
128 | #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) | 129 | #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) |
129 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) | 130 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) |
@@ -136,14 +137,16 @@ extern void _cpu_idle(void); | |||
136 | #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) | 137 | #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) |
137 | #define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT) | 138 | #define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT) |
138 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) | 139 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) |
140 | #define _TIF_NOHZ (1<<TIF_NOHZ) | ||
139 | 141 | ||
140 | /* Work to do on any return to user space. */ | 142 | /* Work to do on any return to user space. */ |
141 | #define _TIF_ALLWORK_MASK \ | 143 | #define _TIF_ALLWORK_MASK \ |
142 | (_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SINGLESTEP|\ | 144 | (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_SINGLESTEP | \ |
143 | _TIF_ASYNC_TLB|_TIF_NOTIFY_RESUME) | 145 | _TIF_ASYNC_TLB | _TIF_NOTIFY_RESUME | _TIF_NOHZ) |
144 | 146 | ||
145 | /* Work to do at syscall entry. */ | 147 | /* Work to do at syscall entry. */ |
146 | #define _TIF_SYSCALL_ENTRY_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT) | 148 | #define _TIF_SYSCALL_ENTRY_WORK \ |
149 | (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_NOHZ) | ||
147 | 150 | ||
148 | /* Work to do at syscall exit. */ | 151 | /* Work to do at syscall exit. */ |
149 | #define _TIF_SYSCALL_EXIT_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT) | 152 | #define _TIF_SYSCALL_EXIT_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT) |
diff --git a/arch/tile/include/hv/hypervisor.h b/arch/tile/include/hv/hypervisor.h index dfcdeb61ba34..e0e6af4e783b 100644 --- a/arch/tile/include/hv/hypervisor.h +++ b/arch/tile/include/hv/hypervisor.h | |||
@@ -961,7 +961,11 @@ typedef enum { | |||
961 | HV_INQ_TILES_HFH_CACHE = 2, | 961 | HV_INQ_TILES_HFH_CACHE = 2, |
962 | 962 | ||
963 | /** The set of tiles that can be legally used as a LOTAR for a PTE. */ | 963 | /** The set of tiles that can be legally used as a LOTAR for a PTE. */ |
964 | HV_INQ_TILES_LOTAR = 3 | 964 | HV_INQ_TILES_LOTAR = 3, |
965 | |||
966 | /** The set of "shared" driver tiles that the hypervisor may | ||
967 | * periodically interrupt. */ | ||
968 | HV_INQ_TILES_SHARED = 4 | ||
965 | } HV_InqTileSet; | 969 | } HV_InqTileSet; |
966 | 970 | ||
967 | /** Returns specific information about various sets of tiles within the | 971 | /** Returns specific information about various sets of tiles within the |
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c index 5cbc864398d3..e8c2c04143cd 100644 --- a/arch/tile/kernel/compat_signal.c +++ b/arch/tile/kernel/compat_signal.c | |||
@@ -68,7 +68,7 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr | |||
68 | if (from->si_code < 0) { | 68 | if (from->si_code < 0) { |
69 | err |= __put_user(from->si_pid, &to->si_pid); | 69 | err |= __put_user(from->si_pid, &to->si_pid); |
70 | err |= __put_user(from->si_uid, &to->si_uid); | 70 | err |= __put_user(from->si_uid, &to->si_uid); |
71 | err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr); | 71 | err |= __put_user(from->si_int, &to->si_int); |
72 | } else { | 72 | } else { |
73 | /* | 73 | /* |
74 | * First 32bits of unions are always present: | 74 | * First 32bits of unions are always present: |
@@ -93,8 +93,7 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr | |||
93 | break; | 93 | break; |
94 | case __SI_TIMER >> 16: | 94 | case __SI_TIMER >> 16: |
95 | err |= __put_user(from->si_overrun, &to->si_overrun); | 95 | err |= __put_user(from->si_overrun, &to->si_overrun); |
96 | err |= __put_user(ptr_to_compat(from->si_ptr), | 96 | err |= __put_user(from->si_int, &to->si_int); |
97 | &to->si_ptr); | ||
98 | break; | 97 | break; |
99 | /* This is not generated by the kernel as of now. */ | 98 | /* This is not generated by the kernel as of now. */ |
100 | case __SI_RT >> 16: | 99 | case __SI_RT >> 16: |
@@ -110,19 +109,19 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr | |||
110 | int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from) | 109 | int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from) |
111 | { | 110 | { |
112 | int err; | 111 | int err; |
113 | u32 ptr32; | ||
114 | 112 | ||
115 | if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo))) | 113 | if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo))) |
116 | return -EFAULT; | 114 | return -EFAULT; |
117 | 115 | ||
116 | memset(to, 0, sizeof(*to)); | ||
117 | |||
118 | err = __get_user(to->si_signo, &from->si_signo); | 118 | err = __get_user(to->si_signo, &from->si_signo); |
119 | err |= __get_user(to->si_errno, &from->si_errno); | 119 | err |= __get_user(to->si_errno, &from->si_errno); |
120 | err |= __get_user(to->si_code, &from->si_code); | 120 | err |= __get_user(to->si_code, &from->si_code); |
121 | 121 | ||
122 | err |= __get_user(to->si_pid, &from->si_pid); | 122 | err |= __get_user(to->si_pid, &from->si_pid); |
123 | err |= __get_user(to->si_uid, &from->si_uid); | 123 | err |= __get_user(to->si_uid, &from->si_uid); |
124 | err |= __get_user(ptr32, &from->si_ptr); | 124 | err |= __get_user(to->si_int, &from->si_int); |
125 | to->si_ptr = compat_ptr(ptr32); | ||
126 | 125 | ||
127 | return err; | 126 | return err; |
128 | } | 127 | } |
diff --git a/arch/tile/kernel/ftrace.c b/arch/tile/kernel/ftrace.c index 8d52d83cc516..0c0996175b1e 100644 --- a/arch/tile/kernel/ftrace.c +++ b/arch/tile/kernel/ftrace.c | |||
@@ -74,7 +74,11 @@ static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr, | |||
74 | create_JumpOff_X1(pcrel_by_instr); | 74 | create_JumpOff_X1(pcrel_by_instr); |
75 | } | 75 | } |
76 | 76 | ||
77 | if (addr == FTRACE_ADDR) { | 77 | /* |
78 | * Also put { move r10, lr; jal ftrace_stub } in a bundle, which | ||
79 | * is used to replace the instruction in address ftrace_call. | ||
80 | */ | ||
81 | if (addr == FTRACE_ADDR || addr == (unsigned long)ftrace_stub) { | ||
78 | /* opcode: or r10, lr, zero */ | 82 | /* opcode: or r10, lr, zero */ |
79 | opcode_x0 = | 83 | opcode_x0 = |
80 | create_Dest_X0(10) | | 84 | create_Dest_X0(10) | |
diff --git a/arch/tile/kernel/mcount_64.S b/arch/tile/kernel/mcount_64.S index 3c2b8d5e1d1a..6c6702451962 100644 --- a/arch/tile/kernel/mcount_64.S +++ b/arch/tile/kernel/mcount_64.S | |||
@@ -81,7 +81,12 @@ STD_ENTRY(ftrace_caller) | |||
81 | 81 | ||
82 | /* arg1: self return address */ | 82 | /* arg1: self return address */ |
83 | /* arg2: parent's return address */ | 83 | /* arg2: parent's return address */ |
84 | { move r0, lr; move r1, r10 } | 84 | /* arg3: ftrace_ops */ |
85 | /* arg4: regs (but make it NULL) */ | ||
86 | { move r0, lr; moveli r2, hw2_last(function_trace_op) } | ||
87 | { move r1, r10; shl16insli r2, r2, hw1(function_trace_op) } | ||
88 | { movei r3, 0; shl16insli r2, r2, hw0(function_trace_op) } | ||
89 | ld r2,r2 | ||
85 | 90 | ||
86 | .global ftrace_call | 91 | .global ftrace_call |
87 | ftrace_call: | 92 | ftrace_call: |
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index 48e5773dd0b7..b403c2e3e263 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
28 | #include <linux/tracehook.h> | 28 | #include <linux/tracehook.h> |
29 | #include <linux/signal.h> | 29 | #include <linux/signal.h> |
30 | #include <linux/context_tracking.h> | ||
30 | #include <asm/stack.h> | 31 | #include <asm/stack.h> |
31 | #include <asm/switch_to.h> | 32 | #include <asm/switch_to.h> |
32 | #include <asm/homecache.h> | 33 | #include <asm/homecache.h> |
@@ -474,6 +475,8 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags) | |||
474 | if (!user_mode(regs)) | 475 | if (!user_mode(regs)) |
475 | return 0; | 476 | return 0; |
476 | 477 | ||
478 | user_exit(); | ||
479 | |||
477 | /* Enable interrupts; they are disabled again on return to caller. */ | 480 | /* Enable interrupts; they are disabled again on return to caller. */ |
478 | local_irq_enable(); | 481 | local_irq_enable(); |
479 | 482 | ||
@@ -496,11 +499,12 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags) | |||
496 | tracehook_notify_resume(regs); | 499 | tracehook_notify_resume(regs); |
497 | return 1; | 500 | return 1; |
498 | } | 501 | } |
499 | if (thread_info_flags & _TIF_SINGLESTEP) { | 502 | if (thread_info_flags & _TIF_SINGLESTEP) |
500 | single_step_once(regs); | 503 | single_step_once(regs); |
501 | return 0; | 504 | |
502 | } | 505 | user_enter(); |
503 | panic("work_pending: bad flags %#x\n", thread_info_flags); | 506 | |
507 | return 0; | ||
504 | } | 508 | } |
505 | 509 | ||
506 | unsigned long get_wchan(struct task_struct *p) | 510 | unsigned long get_wchan(struct task_struct *p) |
diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c index de98c6ddf136..f84eed8243da 100644 --- a/arch/tile/kernel/ptrace.c +++ b/arch/tile/kernel/ptrace.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/regset.h> | 22 | #include <linux/regset.h> |
23 | #include <linux/elf.h> | 23 | #include <linux/elf.h> |
24 | #include <linux/tracehook.h> | 24 | #include <linux/tracehook.h> |
25 | #include <linux/context_tracking.h> | ||
25 | #include <asm/traps.h> | 26 | #include <asm/traps.h> |
26 | #include <arch/chip.h> | 27 | #include <arch/chip.h> |
27 | 28 | ||
@@ -252,12 +253,21 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
252 | 253 | ||
253 | int do_syscall_trace_enter(struct pt_regs *regs) | 254 | int do_syscall_trace_enter(struct pt_regs *regs) |
254 | { | 255 | { |
255 | if (test_thread_flag(TIF_SYSCALL_TRACE)) { | 256 | u32 work = ACCESS_ONCE(current_thread_info()->flags); |
257 | |||
258 | /* | ||
259 | * If TIF_NOHZ is set, we are required to call user_exit() before | ||
260 | * doing anything that could touch RCU. | ||
261 | */ | ||
262 | if (work & _TIF_NOHZ) | ||
263 | user_exit(); | ||
264 | |||
265 | if (work & _TIF_SYSCALL_TRACE) { | ||
256 | if (tracehook_report_syscall_entry(regs)) | 266 | if (tracehook_report_syscall_entry(regs)) |
257 | regs->regs[TREG_SYSCALL_NR] = -1; | 267 | regs->regs[TREG_SYSCALL_NR] = -1; |
258 | } | 268 | } |
259 | 269 | ||
260 | if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) | 270 | if (work & _TIF_SYSCALL_TRACEPOINT) |
261 | trace_sys_enter(regs, regs->regs[TREG_SYSCALL_NR]); | 271 | trace_sys_enter(regs, regs->regs[TREG_SYSCALL_NR]); |
262 | 272 | ||
263 | return regs->regs[TREG_SYSCALL_NR]; | 273 | return regs->regs[TREG_SYSCALL_NR]; |
@@ -268,6 +278,12 @@ void do_syscall_trace_exit(struct pt_regs *regs) | |||
268 | long errno; | 278 | long errno; |
269 | 279 | ||
270 | /* | 280 | /* |
281 | * We may come here right after calling schedule_user() | ||
282 | * in which case we can be in RCU user mode. | ||
283 | */ | ||
284 | user_exit(); | ||
285 | |||
286 | /* | ||
271 | * The standard tile calling convention returns the value (or negative | 287 | * The standard tile calling convention returns the value (or negative |
272 | * errno) in r0, and zero (or positive errno) in r1. | 288 | * errno) in r0, and zero (or positive errno) in r1. |
273 | * It saves a couple of cycles on the hot path to do this work in | 289 | * It saves a couple of cycles on the hot path to do this work in |
@@ -303,5 +319,7 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs) | |||
303 | /* Handle synthetic interrupt delivered only by the simulator. */ | 319 | /* Handle synthetic interrupt delivered only by the simulator. */ |
304 | void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num) | 320 | void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num) |
305 | { | 321 | { |
322 | enum ctx_state prev_state = exception_enter(); | ||
306 | send_sigtrap(current, regs); | 323 | send_sigtrap(current, regs); |
324 | exception_exit(prev_state); | ||
307 | } | 325 | } |
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c index f1f579914952..7833b2ccdfbc 100644 --- a/arch/tile/kernel/setup.c +++ b/arch/tile/kernel/setup.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/hugetlb.h> | 32 | #include <linux/hugetlb.h> |
33 | #include <linux/start_kernel.h> | 33 | #include <linux/start_kernel.h> |
34 | #include <linux/screen_info.h> | 34 | #include <linux/screen_info.h> |
35 | #include <linux/tick.h> | ||
35 | #include <asm/setup.h> | 36 | #include <asm/setup.h> |
36 | #include <asm/sections.h> | 37 | #include <asm/sections.h> |
37 | #include <asm/cacheflush.h> | 38 | #include <asm/cacheflush.h> |
@@ -1390,6 +1391,28 @@ static int __init dataplane(char *str) | |||
1390 | 1391 | ||
1391 | early_param("dataplane", dataplane); | 1392 | early_param("dataplane", dataplane); |
1392 | 1393 | ||
1394 | #ifdef CONFIG_NO_HZ_FULL | ||
1395 | /* Warn if hypervisor shared cpus are marked as nohz_full. */ | ||
1396 | static int __init check_nohz_full_cpus(void) | ||
1397 | { | ||
1398 | struct cpumask shared; | ||
1399 | int cpu; | ||
1400 | |||
1401 | if (hv_inquire_tiles(HV_INQ_TILES_SHARED, | ||
1402 | (HV_VirtAddr) shared.bits, sizeof(shared)) < 0) { | ||
1403 | pr_warn("WARNING: No support for inquiring hv shared tiles\n"); | ||
1404 | return 0; | ||
1405 | } | ||
1406 | for_each_cpu(cpu, &shared) { | ||
1407 | if (tick_nohz_full_cpu(cpu)) | ||
1408 | pr_warn("WARNING: nohz_full cpu %d receives hypervisor interrupts!\n", | ||
1409 | cpu); | ||
1410 | } | ||
1411 | return 0; | ||
1412 | } | ||
1413 | arch_initcall(check_nohz_full_cpus); | ||
1414 | #endif | ||
1415 | |||
1393 | #ifdef CONFIG_CMDLINE_BOOL | 1416 | #ifdef CONFIG_CMDLINE_BOOL |
1394 | static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; | 1417 | static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; |
1395 | #endif | 1418 | #endif |
diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c index 862973074bf9..53f7b9def07b 100644 --- a/arch/tile/kernel/single_step.c +++ b/arch/tile/kernel/single_step.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/types.h> | 23 | #include <linux/types.h> |
24 | #include <linux/err.h> | 24 | #include <linux/err.h> |
25 | #include <linux/prctl.h> | 25 | #include <linux/prctl.h> |
26 | #include <linux/context_tracking.h> | ||
26 | #include <asm/cacheflush.h> | 27 | #include <asm/cacheflush.h> |
27 | #include <asm/traps.h> | 28 | #include <asm/traps.h> |
28 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
@@ -738,6 +739,7 @@ static DEFINE_PER_CPU(unsigned long, ss_saved_pc); | |||
738 | 739 | ||
739 | void gx_singlestep_handle(struct pt_regs *regs, int fault_num) | 740 | void gx_singlestep_handle(struct pt_regs *regs, int fault_num) |
740 | { | 741 | { |
742 | enum ctx_state prev_state = exception_enter(); | ||
741 | unsigned long *ss_pc = this_cpu_ptr(&ss_saved_pc); | 743 | unsigned long *ss_pc = this_cpu_ptr(&ss_saved_pc); |
742 | struct thread_info *info = (void *)current_thread_info(); | 744 | struct thread_info *info = (void *)current_thread_info(); |
743 | int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP); | 745 | int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP); |
@@ -754,6 +756,7 @@ void gx_singlestep_handle(struct pt_regs *regs, int fault_num) | |||
754 | __insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control); | 756 | __insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control); |
755 | send_sigtrap(current, regs); | 757 | send_sigtrap(current, regs); |
756 | } | 758 | } |
759 | exception_exit(prev_state); | ||
757 | } | 760 | } |
758 | 761 | ||
759 | 762 | ||
diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c index d3c4ed780ce2..07e3ff5cc740 100644 --- a/arch/tile/kernel/smp.c +++ b/arch/tile/kernel/smp.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
20 | #include <linux/irq.h> | 20 | #include <linux/irq.h> |
21 | #include <linux/irq_work.h> | ||
21 | #include <linux/module.h> | 22 | #include <linux/module.h> |
22 | #include <asm/cacheflush.h> | 23 | #include <asm/cacheflush.h> |
23 | #include <asm/homecache.h> | 24 | #include <asm/homecache.h> |
@@ -33,6 +34,8 @@ EXPORT_SYMBOL(smp_topology); | |||
33 | static unsigned long __iomem *ipi_mappings[NR_CPUS]; | 34 | static unsigned long __iomem *ipi_mappings[NR_CPUS]; |
34 | #endif | 35 | #endif |
35 | 36 | ||
37 | /* Does messaging work correctly to the local cpu? */ | ||
38 | bool self_interrupt_ok; | ||
36 | 39 | ||
37 | /* | 40 | /* |
38 | * Top-level send_IPI*() functions to send messages to other cpus. | 41 | * Top-level send_IPI*() functions to send messages to other cpus. |
@@ -147,6 +150,10 @@ void evaluate_message(int tag) | |||
147 | generic_smp_call_function_single_interrupt(); | 150 | generic_smp_call_function_single_interrupt(); |
148 | break; | 151 | break; |
149 | 152 | ||
153 | case MSG_TAG_IRQ_WORK: /* Invoke IRQ work */ | ||
154 | irq_work_run(); | ||
155 | break; | ||
156 | |||
150 | default: | 157 | default: |
151 | panic("Unknown IPI message tag %d", tag); | 158 | panic("Unknown IPI message tag %d", tag); |
152 | break; | 159 | break; |
@@ -186,6 +193,15 @@ void flush_icache_range(unsigned long start, unsigned long end) | |||
186 | EXPORT_SYMBOL(flush_icache_range); | 193 | EXPORT_SYMBOL(flush_icache_range); |
187 | 194 | ||
188 | 195 | ||
196 | #ifdef CONFIG_IRQ_WORK | ||
197 | void arch_irq_work_raise(void) | ||
198 | { | ||
199 | if (arch_irq_work_has_interrupt()) | ||
200 | send_IPI_single(smp_processor_id(), MSG_TAG_IRQ_WORK); | ||
201 | } | ||
202 | #endif | ||
203 | |||
204 | |||
189 | /* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */ | 205 | /* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */ |
190 | static irqreturn_t handle_reschedule_ipi(int irq, void *token) | 206 | static irqreturn_t handle_reschedule_ipi(int irq, void *token) |
191 | { | 207 | { |
@@ -203,8 +219,22 @@ static struct irqaction resched_action = { | |||
203 | 219 | ||
204 | void __init ipi_init(void) | 220 | void __init ipi_init(void) |
205 | { | 221 | { |
222 | int cpu = smp_processor_id(); | ||
223 | HV_Recipient recip = { .y = cpu_y(cpu), .x = cpu_x(cpu), | ||
224 | .state = HV_TO_BE_SENT }; | ||
225 | int tag = MSG_TAG_CALL_FUNCTION_SINGLE; | ||
226 | |||
227 | /* | ||
228 | * Test if we can message ourselves for arch_irq_work_raise. | ||
229 | * This functionality is only available in the Tilera hypervisor | ||
230 | * in versions 4.3.4 and following. | ||
231 | */ | ||
232 | if (hv_send_message(&recip, 1, (HV_VirtAddr)&tag, sizeof(tag)) == 1) | ||
233 | self_interrupt_ok = true; | ||
234 | else | ||
235 | pr_warn("Older hypervisor: disabling fast irq_work_raise\n"); | ||
236 | |||
206 | #if CHIP_HAS_IPI() | 237 | #if CHIP_HAS_IPI() |
207 | int cpu; | ||
208 | /* Map IPI trigger MMIO addresses. */ | 238 | /* Map IPI trigger MMIO addresses. */ |
209 | for_each_possible_cpu(cpu) { | 239 | for_each_possible_cpu(cpu) { |
210 | HV_Coord tile; | 240 | HV_Coord tile; |
diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c index 7ff5afdbd3aa..c42dce50acd8 100644 --- a/arch/tile/kernel/stack.c +++ b/arch/tile/kernel/stack.c | |||
@@ -108,14 +108,15 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt) | |||
108 | p->sp < PAGE_OFFSET && p->sp != 0) { | 108 | p->sp < PAGE_OFFSET && p->sp != 0) { |
109 | if (kbt->verbose) | 109 | if (kbt->verbose) |
110 | pr_err(" <%s while in user mode>\n", fault); | 110 | pr_err(" <%s while in user mode>\n", fault); |
111 | } else if (kbt->verbose) { | 111 | } else { |
112 | pr_err(" (odd fault: pc %#lx, sp %#lx, ex1 %#lx?)\n", | 112 | if (kbt->verbose) |
113 | p->pc, p->sp, p->ex1); | 113 | pr_err(" (odd fault: pc %#lx, sp %#lx, ex1 %#lx?)\n", |
114 | p = NULL; | 114 | p->pc, p->sp, p->ex1); |
115 | return NULL; | ||
115 | } | 116 | } |
116 | if (!kbt->profile || ((1ULL << p->faultnum) & QUEUED_INTERRUPTS) == 0) | 117 | if (kbt->profile && ((1ULL << p->faultnum) & QUEUED_INTERRUPTS) != 0) |
117 | return p; | 118 | return NULL; |
118 | return NULL; | 119 | return p; |
119 | } | 120 | } |
120 | 121 | ||
121 | /* Is the pc pointing to a sigreturn trampoline? */ | 122 | /* Is the pc pointing to a sigreturn trampoline? */ |
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c index bf841ca517bb..312fc134c1cb 100644 --- a/arch/tile/kernel/traps.c +++ b/arch/tile/kernel/traps.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/reboot.h> | 20 | #include <linux/reboot.h> |
21 | #include <linux/uaccess.h> | 21 | #include <linux/uaccess.h> |
22 | #include <linux/ptrace.h> | 22 | #include <linux/ptrace.h> |
23 | #include <linux/context_tracking.h> | ||
23 | #include <asm/stack.h> | 24 | #include <asm/stack.h> |
24 | #include <asm/traps.h> | 25 | #include <asm/traps.h> |
25 | #include <asm/setup.h> | 26 | #include <asm/setup.h> |
@@ -253,6 +254,7 @@ static int do_bpt(struct pt_regs *regs) | |||
253 | void __kprobes do_trap(struct pt_regs *regs, int fault_num, | 254 | void __kprobes do_trap(struct pt_regs *regs, int fault_num, |
254 | unsigned long reason) | 255 | unsigned long reason) |
255 | { | 256 | { |
257 | enum ctx_state prev_state = exception_enter(); | ||
256 | siginfo_t info = { 0 }; | 258 | siginfo_t info = { 0 }; |
257 | int signo, code; | 259 | int signo, code; |
258 | unsigned long address = 0; | 260 | unsigned long address = 0; |
@@ -261,7 +263,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, | |||
261 | 263 | ||
262 | /* Handle breakpoints, etc. */ | 264 | /* Handle breakpoints, etc. */ |
263 | if (is_kernel && fault_num == INT_ILL && do_bpt(regs)) | 265 | if (is_kernel && fault_num == INT_ILL && do_bpt(regs)) |
264 | return; | 266 | goto done; |
265 | 267 | ||
266 | /* Re-enable interrupts, if they were previously enabled. */ | 268 | /* Re-enable interrupts, if they were previously enabled. */ |
267 | if (!(regs->flags & PT_FLAGS_DISABLE_IRQ)) | 269 | if (!(regs->flags & PT_FLAGS_DISABLE_IRQ)) |
@@ -275,7 +277,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, | |||
275 | const char *name; | 277 | const char *name; |
276 | char buf[100]; | 278 | char buf[100]; |
277 | if (fixup_exception(regs)) /* ILL_TRANS or UNALIGN_DATA */ | 279 | if (fixup_exception(regs)) /* ILL_TRANS or UNALIGN_DATA */ |
278 | return; | 280 | goto done; |
279 | if (fault_num >= 0 && | 281 | if (fault_num >= 0 && |
280 | fault_num < ARRAY_SIZE(int_name) && | 282 | fault_num < ARRAY_SIZE(int_name) && |
281 | int_name[fault_num] != NULL) | 283 | int_name[fault_num] != NULL) |
@@ -294,7 +296,6 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, | |||
294 | fault_num, name, regs->pc, buf); | 296 | fault_num, name, regs->pc, buf); |
295 | show_regs(regs); | 297 | show_regs(regs); |
296 | do_exit(SIGKILL); /* FIXME: implement i386 die() */ | 298 | do_exit(SIGKILL); /* FIXME: implement i386 die() */ |
297 | return; | ||
298 | } | 299 | } |
299 | 300 | ||
300 | switch (fault_num) { | 301 | switch (fault_num) { |
@@ -308,7 +309,6 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, | |||
308 | pr_err("Unreadable instruction for INT_ILL: %#lx\n", | 309 | pr_err("Unreadable instruction for INT_ILL: %#lx\n", |
309 | regs->pc); | 310 | regs->pc); |
310 | do_exit(SIGKILL); | 311 | do_exit(SIGKILL); |
311 | return; | ||
312 | } | 312 | } |
313 | if (!special_ill(instr, &signo, &code)) { | 313 | if (!special_ill(instr, &signo, &code)) { |
314 | signo = SIGILL; | 314 | signo = SIGILL; |
@@ -319,7 +319,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, | |||
319 | case INT_GPV: | 319 | case INT_GPV: |
320 | #if CHIP_HAS_TILE_DMA() | 320 | #if CHIP_HAS_TILE_DMA() |
321 | if (retry_gpv(reason)) | 321 | if (retry_gpv(reason)) |
322 | return; | 322 | goto done; |
323 | #endif | 323 | #endif |
324 | /*FALLTHROUGH*/ | 324 | /*FALLTHROUGH*/ |
325 | case INT_UDN_ACCESS: | 325 | case INT_UDN_ACCESS: |
@@ -346,7 +346,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, | |||
346 | if (!state || | 346 | if (!state || |
347 | (void __user *)(regs->pc) != state->buffer) { | 347 | (void __user *)(regs->pc) != state->buffer) { |
348 | single_step_once(regs); | 348 | single_step_once(regs); |
349 | return; | 349 | goto done; |
350 | } | 350 | } |
351 | } | 351 | } |
352 | #endif | 352 | #endif |
@@ -380,7 +380,6 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, | |||
380 | #endif | 380 | #endif |
381 | default: | 381 | default: |
382 | panic("Unexpected do_trap interrupt number %d", fault_num); | 382 | panic("Unexpected do_trap interrupt number %d", fault_num); |
383 | return; | ||
384 | } | 383 | } |
385 | 384 | ||
386 | info.si_signo = signo; | 385 | info.si_signo = signo; |
@@ -391,6 +390,9 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, | |||
391 | if (signo != SIGTRAP) | 390 | if (signo != SIGTRAP) |
392 | trace_unhandled_signal("trap", regs, address, signo); | 391 | trace_unhandled_signal("trap", regs, address, signo); |
393 | force_sig_info(signo, &info, current); | 392 | force_sig_info(signo, &info, current); |
393 | |||
394 | done: | ||
395 | exception_exit(prev_state); | ||
394 | } | 396 | } |
395 | 397 | ||
396 | void kernel_double_fault(int dummy, ulong pc, ulong lr, ulong sp, ulong r52) | 398 | void kernel_double_fault(int dummy, ulong pc, ulong lr, ulong sp, ulong r52) |
diff --git a/arch/tile/kernel/unaligned.c b/arch/tile/kernel/unaligned.c index 7d9a83be0aca..d075f92ccee0 100644 --- a/arch/tile/kernel/unaligned.c +++ b/arch/tile/kernel/unaligned.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/compat.h> | 26 | #include <linux/compat.h> |
27 | #include <linux/prctl.h> | 27 | #include <linux/prctl.h> |
28 | #include <linux/context_tracking.h> | ||
28 | #include <asm/cacheflush.h> | 29 | #include <asm/cacheflush.h> |
29 | #include <asm/traps.h> | 30 | #include <asm/traps.h> |
30 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
@@ -1448,6 +1449,7 @@ void jit_bundle_gen(struct pt_regs *regs, tilegx_bundle_bits bundle, | |||
1448 | 1449 | ||
1449 | void do_unaligned(struct pt_regs *regs, int vecnum) | 1450 | void do_unaligned(struct pt_regs *regs, int vecnum) |
1450 | { | 1451 | { |
1452 | enum ctx_state prev_state = exception_enter(); | ||
1451 | tilegx_bundle_bits __user *pc; | 1453 | tilegx_bundle_bits __user *pc; |
1452 | tilegx_bundle_bits bundle; | 1454 | tilegx_bundle_bits bundle; |
1453 | struct thread_info *info = current_thread_info(); | 1455 | struct thread_info *info = current_thread_info(); |
@@ -1487,12 +1489,11 @@ void do_unaligned(struct pt_regs *regs, int vecnum) | |||
1487 | (int)unaligned_fixup, | 1489 | (int)unaligned_fixup, |
1488 | (unsigned long long)regs->ex1, | 1490 | (unsigned long long)regs->ex1, |
1489 | (unsigned long long)regs->pc); | 1491 | (unsigned long long)regs->pc); |
1490 | return; | 1492 | } else { |
1493 | /* Not fixable. Go panic. */ | ||
1494 | panic("Unalign exception in Kernel. pc=%lx", | ||
1495 | regs->pc); | ||
1491 | } | 1496 | } |
1492 | /* Not fixable. Go panic. */ | ||
1493 | panic("Unalign exception in Kernel. pc=%lx", | ||
1494 | regs->pc); | ||
1495 | return; | ||
1496 | } else { | 1497 | } else { |
1497 | /* | 1498 | /* |
1498 | * Try to fix the exception. If we can't, panic the | 1499 | * Try to fix the exception. If we can't, panic the |
@@ -1501,8 +1502,8 @@ void do_unaligned(struct pt_regs *regs, int vecnum) | |||
1501 | bundle = GX_INSN_BSWAP( | 1502 | bundle = GX_INSN_BSWAP( |
1502 | *((tilegx_bundle_bits *)(regs->pc))); | 1503 | *((tilegx_bundle_bits *)(regs->pc))); |
1503 | jit_bundle_gen(regs, bundle, align_ctl); | 1504 | jit_bundle_gen(regs, bundle, align_ctl); |
1504 | return; | ||
1505 | } | 1505 | } |
1506 | goto done; | ||
1506 | } | 1507 | } |
1507 | 1508 | ||
1508 | /* | 1509 | /* |
@@ -1526,7 +1527,7 @@ void do_unaligned(struct pt_regs *regs, int vecnum) | |||
1526 | 1527 | ||
1527 | trace_unhandled_signal("unaligned fixup trap", regs, 0, SIGBUS); | 1528 | trace_unhandled_signal("unaligned fixup trap", regs, 0, SIGBUS); |
1528 | force_sig_info(info.si_signo, &info, current); | 1529 | force_sig_info(info.si_signo, &info, current); |
1529 | return; | 1530 | goto done; |
1530 | } | 1531 | } |
1531 | 1532 | ||
1532 | 1533 | ||
@@ -1543,7 +1544,7 @@ void do_unaligned(struct pt_regs *regs, int vecnum) | |||
1543 | trace_unhandled_signal("segfault in unalign fixup", regs, | 1544 | trace_unhandled_signal("segfault in unalign fixup", regs, |
1544 | (unsigned long)info.si_addr, SIGSEGV); | 1545 | (unsigned long)info.si_addr, SIGSEGV); |
1545 | force_sig_info(info.si_signo, &info, current); | 1546 | force_sig_info(info.si_signo, &info, current); |
1546 | return; | 1547 | goto done; |
1547 | } | 1548 | } |
1548 | 1549 | ||
1549 | if (!info->unalign_jit_base) { | 1550 | if (!info->unalign_jit_base) { |
@@ -1578,7 +1579,7 @@ void do_unaligned(struct pt_regs *regs, int vecnum) | |||
1578 | 1579 | ||
1579 | if (IS_ERR((void __force *)user_page)) { | 1580 | if (IS_ERR((void __force *)user_page)) { |
1580 | pr_err("Out of kernel pages trying do_mmap\n"); | 1581 | pr_err("Out of kernel pages trying do_mmap\n"); |
1581 | return; | 1582 | goto done; |
1582 | } | 1583 | } |
1583 | 1584 | ||
1584 | /* Save the address in the thread_info struct */ | 1585 | /* Save the address in the thread_info struct */ |
@@ -1591,6 +1592,9 @@ void do_unaligned(struct pt_regs *regs, int vecnum) | |||
1591 | 1592 | ||
1592 | /* Generate unalign JIT */ | 1593 | /* Generate unalign JIT */ |
1593 | jit_bundle_gen(regs, GX_INSN_BSWAP(bundle), align_ctl); | 1594 | jit_bundle_gen(regs, GX_INSN_BSWAP(bundle), align_ctl); |
1595 | |||
1596 | done: | ||
1597 | exception_exit(prev_state); | ||
1594 | } | 1598 | } |
1595 | 1599 | ||
1596 | #endif /* __tilegx__ */ | 1600 | #endif /* __tilegx__ */ |
diff --git a/arch/tile/mm/elf.c b/arch/tile/mm/elf.c index 23f044e8a7ab..f7ddae3725a4 100644 --- a/arch/tile/mm/elf.c +++ b/arch/tile/mm/elf.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/binfmts.h> | 17 | #include <linux/binfmts.h> |
18 | #include <linux/compat.h> | 18 | #include <linux/compat.h> |
19 | #include <linux/mman.h> | 19 | #include <linux/mman.h> |
20 | #include <linux/file.h> | ||
20 | #include <linux/elf.h> | 21 | #include <linux/elf.h> |
21 | #include <asm/pgtable.h> | 22 | #include <asm/pgtable.h> |
22 | #include <asm/pgalloc.h> | 23 | #include <asm/pgalloc.h> |
@@ -39,30 +40,34 @@ static void sim_notify_exec(const char *binary_name) | |||
39 | 40 | ||
40 | static int notify_exec(struct mm_struct *mm) | 41 | static int notify_exec(struct mm_struct *mm) |
41 | { | 42 | { |
43 | int ret = 0; | ||
42 | char *buf, *path; | 44 | char *buf, *path; |
43 | struct vm_area_struct *vma; | 45 | struct vm_area_struct *vma; |
46 | struct file *exe_file; | ||
44 | 47 | ||
45 | if (!sim_is_simulator()) | 48 | if (!sim_is_simulator()) |
46 | return 1; | 49 | return 1; |
47 | 50 | ||
48 | if (mm->exe_file == NULL) | ||
49 | return 0; | ||
50 | |||
51 | for (vma = current->mm->mmap; ; vma = vma->vm_next) { | ||
52 | if (vma == NULL) | ||
53 | return 0; | ||
54 | if (vma->vm_file == mm->exe_file) | ||
55 | break; | ||
56 | } | ||
57 | |||
58 | buf = (char *) __get_free_page(GFP_KERNEL); | 51 | buf = (char *) __get_free_page(GFP_KERNEL); |
59 | if (buf == NULL) | 52 | if (buf == NULL) |
60 | return 0; | 53 | return 0; |
61 | 54 | ||
62 | path = d_path(&mm->exe_file->f_path, buf, PAGE_SIZE); | 55 | exe_file = get_mm_exe_file(mm); |
63 | if (IS_ERR(path)) { | 56 | if (exe_file == NULL) |
64 | free_page((unsigned long)buf); | 57 | goto done_free; |
65 | return 0; | 58 | |
59 | path = d_path(&exe_file->f_path, buf, PAGE_SIZE); | ||
60 | if (IS_ERR(path)) | ||
61 | goto done_put; | ||
62 | |||
63 | down_read(&mm->mmap_sem); | ||
64 | for (vma = current->mm->mmap; ; vma = vma->vm_next) { | ||
65 | if (vma == NULL) { | ||
66 | up_read(&mm->mmap_sem); | ||
67 | goto done_put; | ||
68 | } | ||
69 | if (vma->vm_file == exe_file) | ||
70 | break; | ||
66 | } | 71 | } |
67 | 72 | ||
68 | /* | 73 | /* |
@@ -80,14 +85,20 @@ static int notify_exec(struct mm_struct *mm) | |||
80 | __insn_mtspr(SPR_SIM_CONTROL, | 85 | __insn_mtspr(SPR_SIM_CONTROL, |
81 | (SIM_CONTROL_DLOPEN | 86 | (SIM_CONTROL_DLOPEN |
82 | | (c << _SIM_CONTROL_OPERATOR_BITS))); | 87 | | (c << _SIM_CONTROL_OPERATOR_BITS))); |
83 | if (c == '\0') | 88 | if (c == '\0') { |
89 | ret = 1; /* success */ | ||
84 | break; | 90 | break; |
91 | } | ||
85 | } | 92 | } |
86 | } | 93 | } |
94 | up_read(&mm->mmap_sem); | ||
87 | 95 | ||
88 | sim_notify_exec(path); | 96 | sim_notify_exec(path); |
97 | done_put: | ||
98 | fput(exe_file); | ||
99 | done_free: | ||
89 | free_page((unsigned long)buf); | 100 | free_page((unsigned long)buf); |
90 | return 1; | 101 | return ret; |
91 | } | 102 | } |
92 | 103 | ||
93 | /* Notify a running simulator, if any, that we loaded an interpreter. */ | 104 | /* Notify a running simulator, if any, that we loaded an interpreter. */ |
@@ -109,8 +120,6 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, | |||
109 | struct mm_struct *mm = current->mm; | 120 | struct mm_struct *mm = current->mm; |
110 | int retval = 0; | 121 | int retval = 0; |
111 | 122 | ||
112 | down_write(&mm->mmap_sem); | ||
113 | |||
114 | /* | 123 | /* |
115 | * Notify the simulator that an exec just occurred. | 124 | * Notify the simulator that an exec just occurred. |
116 | * If we can't find the filename of the mapping, just use | 125 | * If we can't find the filename of the mapping, just use |
@@ -119,6 +128,8 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, | |||
119 | if (!notify_exec(mm)) | 128 | if (!notify_exec(mm)) |
120 | sim_notify_exec(bprm->filename); | 129 | sim_notify_exec(bprm->filename); |
121 | 130 | ||
131 | down_write(&mm->mmap_sem); | ||
132 | |||
122 | retval = setup_vdso_pages(); | 133 | retval = setup_vdso_pages(); |
123 | 134 | ||
124 | #ifndef __tilegx__ | 135 | #ifndef __tilegx__ |
diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c index 0f61a73534e6..e83cc999da02 100644 --- a/arch/tile/mm/fault.c +++ b/arch/tile/mm/fault.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/syscalls.h> | 35 | #include <linux/syscalls.h> |
36 | #include <linux/uaccess.h> | 36 | #include <linux/uaccess.h> |
37 | #include <linux/kdebug.h> | 37 | #include <linux/kdebug.h> |
38 | #include <linux/context_tracking.h> | ||
38 | 39 | ||
39 | #include <asm/pgalloc.h> | 40 | #include <asm/pgalloc.h> |
40 | #include <asm/sections.h> | 41 | #include <asm/sections.h> |
@@ -702,6 +703,7 @@ void do_page_fault(struct pt_regs *regs, int fault_num, | |||
702 | unsigned long address, unsigned long write) | 703 | unsigned long address, unsigned long write) |
703 | { | 704 | { |
704 | int is_page_fault; | 705 | int is_page_fault; |
706 | enum ctx_state prev_state = exception_enter(); | ||
705 | 707 | ||
706 | #ifdef CONFIG_KPROBES | 708 | #ifdef CONFIG_KPROBES |
707 | /* | 709 | /* |
@@ -711,7 +713,7 @@ void do_page_fault(struct pt_regs *regs, int fault_num, | |||
711 | */ | 713 | */ |
712 | if (notify_die(DIE_PAGE_FAULT, "page fault", regs, -1, | 714 | if (notify_die(DIE_PAGE_FAULT, "page fault", regs, -1, |
713 | regs->faultnum, SIGSEGV) == NOTIFY_STOP) | 715 | regs->faultnum, SIGSEGV) == NOTIFY_STOP) |
714 | return; | 716 | goto done; |
715 | #endif | 717 | #endif |
716 | 718 | ||
717 | #ifdef __tilegx__ | 719 | #ifdef __tilegx__ |
@@ -750,7 +752,6 @@ void do_page_fault(struct pt_regs *regs, int fault_num, | |||
750 | current->comm, current->pid, pc, address); | 752 | current->comm, current->pid, pc, address); |
751 | show_regs(regs); | 753 | show_regs(regs); |
752 | do_group_exit(SIGKILL); | 754 | do_group_exit(SIGKILL); |
753 | return; | ||
754 | } | 755 | } |
755 | } | 756 | } |
756 | #else | 757 | #else |
@@ -834,12 +835,15 @@ void do_page_fault(struct pt_regs *regs, int fault_num, | |||
834 | async->is_fault = is_page_fault; | 835 | async->is_fault = is_page_fault; |
835 | async->is_write = write; | 836 | async->is_write = write; |
836 | async->address = address; | 837 | async->address = address; |
837 | return; | 838 | goto done; |
838 | } | 839 | } |
839 | } | 840 | } |
840 | #endif | 841 | #endif |
841 | 842 | ||
842 | handle_page_fault(regs, fault_num, is_page_fault, address, write); | 843 | handle_page_fault(regs, fault_num, is_page_fault, address, write); |
844 | |||
845 | done: | ||
846 | exception_exit(prev_state); | ||
843 | } | 847 | } |
844 | 848 | ||
845 | 849 | ||
diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c index ace32d7d3864..5bd252e3fdc5 100644 --- a/arch/tile/mm/init.c +++ b/arch/tile/mm/init.c | |||
@@ -233,9 +233,12 @@ static pgprot_t __init init_pgprot(ulong address) | |||
233 | if (kdata_huge) | 233 | if (kdata_huge) |
234 | return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH); | 234 | return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH); |
235 | 235 | ||
236 | /* We map the aliased pages of permanent text inaccessible. */ | 236 | /* |
237 | * We map the aliased pages of permanent text so we can | ||
238 | * update them if necessary, for ftrace, etc. | ||
239 | */ | ||
237 | if (address < (ulong) _sinittext - CODE_DELTA) | 240 | if (address < (ulong) _sinittext - CODE_DELTA) |
238 | return PAGE_NONE; | 241 | return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH); |
239 | 242 | ||
240 | /* We map read-only data non-coherent for performance. */ | 243 | /* We map read-only data non-coherent for performance. */ |
241 | if ((address >= (ulong) __start_rodata && | 244 | if ((address >= (ulong) __start_rodata && |