tile: support CONTEXT_TRACKING and thus NOHZ_FULL
Add the TIF_NOHZ flag appropriately. Add call to user_exit() on entry to do_work_pending() and on entry to syscalls via do_syscall_trace_enter(), and also the top of do_syscall_trace_exit() just because it's done in x86. Add call to user_enter() at the bottom of do_work_pending() once we have no more work to do before returning to userspace. Wrap all the trap code in exception_enter() / exception_exit(). Signed-off-by: Chris Metcalf <cmetcalf@ezchip.com> Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
This commit is contained in:
		
					parent
					
						
							
								b340c656af
							
						
					
				
			
			
				commit
				
					
						49e4e15619
					
				
			
		
					 8 changed files with 67 additions and 28 deletions
				
			
		| 
						 | 
					@ -27,6 +27,7 @@ config TILE
 | 
				
			||||||
	select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
 | 
						select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
 | 
				
			||||||
	select HAVE_DEBUG_STACKOVERFLOW
 | 
						select HAVE_DEBUG_STACKOVERFLOW
 | 
				
			||||||
	select ARCH_WANT_FRAME_POINTERS
 | 
						select ARCH_WANT_FRAME_POINTERS
 | 
				
			||||||
 | 
						select HAVE_CONTEXT_TRACKING
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# FIXME: investigate whether we need/want these options.
 | 
					# FIXME: investigate whether we need/want these options.
 | 
				
			||||||
#	select HAVE_IOREMAP_PROT
 | 
					#	select HAVE_IOREMAP_PROT
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -126,6 +126,7 @@ extern void _cpu_idle(void);
 | 
				
			||||||
#define TIF_NOTIFY_RESUME	8	/* callback before returning to user */
 | 
					#define TIF_NOTIFY_RESUME	8	/* callback before returning to user */
 | 
				
			||||||
#define TIF_SYSCALL_TRACEPOINT	9	/* syscall tracepoint instrumentation */
 | 
					#define TIF_SYSCALL_TRACEPOINT	9	/* syscall tracepoint instrumentation */
 | 
				
			||||||
#define TIF_POLLING_NRFLAG	10	/* idle is polling for TIF_NEED_RESCHED */
 | 
					#define TIF_POLLING_NRFLAG	10	/* idle is polling for TIF_NEED_RESCHED */
 | 
				
			||||||
 | 
					#define TIF_NOHZ		11	/* in adaptive nohz mode */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 | 
					#define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 | 
				
			||||||
#define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 | 
					#define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 | 
				
			||||||
| 
						 | 
					@ -138,14 +139,16 @@ extern void _cpu_idle(void);
 | 
				
			||||||
#define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 | 
					#define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 | 
				
			||||||
#define _TIF_SYSCALL_TRACEPOINT	(1<<TIF_SYSCALL_TRACEPOINT)
 | 
					#define _TIF_SYSCALL_TRACEPOINT	(1<<TIF_SYSCALL_TRACEPOINT)
 | 
				
			||||||
#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 | 
					#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 | 
				
			||||||
 | 
					#define _TIF_NOHZ		(1<<TIF_NOHZ)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Work to do on any return to user space. */
 | 
					/* Work to do on any return to user space. */
 | 
				
			||||||
#define _TIF_ALLWORK_MASK \
 | 
					#define _TIF_ALLWORK_MASK \
 | 
				
			||||||
	(_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_SINGLESTEP | \
 | 
						(_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_SINGLESTEP | \
 | 
				
			||||||
   _TIF_ASYNC_TLB|_TIF_NOTIFY_RESUME)
 | 
						 _TIF_ASYNC_TLB | _TIF_NOTIFY_RESUME | _TIF_NOHZ)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Work to do at syscall entry. */
 | 
					/* Work to do at syscall entry. */
 | 
				
			||||||
#define _TIF_SYSCALL_ENTRY_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT)
 | 
					#define _TIF_SYSCALL_ENTRY_WORK \
 | 
				
			||||||
 | 
						(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_NOHZ)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Work to do at syscall exit. */
 | 
					/* Work to do at syscall exit. */
 | 
				
			||||||
#define _TIF_SYSCALL_EXIT_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT)
 | 
					#define _TIF_SYSCALL_EXIT_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,7 @@
 | 
				
			||||||
#include <linux/kernel.h>
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
#include <linux/tracehook.h>
 | 
					#include <linux/tracehook.h>
 | 
				
			||||||
#include <linux/signal.h>
 | 
					#include <linux/signal.h>
 | 
				
			||||||
 | 
					#include <linux/context_tracking.h>
 | 
				
			||||||
#include <asm/stack.h>
 | 
					#include <asm/stack.h>
 | 
				
			||||||
#include <asm/switch_to.h>
 | 
					#include <asm/switch_to.h>
 | 
				
			||||||
#include <asm/homecache.h>
 | 
					#include <asm/homecache.h>
 | 
				
			||||||
| 
						 | 
					@ -474,6 +475,8 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
 | 
				
			||||||
	if (!user_mode(regs))
 | 
						if (!user_mode(regs))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						user_exit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Enable interrupts; they are disabled again on return to caller. */
 | 
						/* Enable interrupts; they are disabled again on return to caller. */
 | 
				
			||||||
	local_irq_enable();
 | 
						local_irq_enable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -496,12 +499,13 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
 | 
				
			||||||
		tracehook_notify_resume(regs);
 | 
							tracehook_notify_resume(regs);
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (thread_info_flags & _TIF_SINGLESTEP) {
 | 
						if (thread_info_flags & _TIF_SINGLESTEP)
 | 
				
			||||||
		single_step_once(regs);
 | 
							single_step_once(regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						user_enter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
	panic("work_pending: bad flags %#x\n", thread_info_flags);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
unsigned long get_wchan(struct task_struct *p)
 | 
					unsigned long get_wchan(struct task_struct *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,7 @@
 | 
				
			||||||
#include <linux/regset.h>
 | 
					#include <linux/regset.h>
 | 
				
			||||||
#include <linux/elf.h>
 | 
					#include <linux/elf.h>
 | 
				
			||||||
#include <linux/tracehook.h>
 | 
					#include <linux/tracehook.h>
 | 
				
			||||||
 | 
					#include <linux/context_tracking.h>
 | 
				
			||||||
#include <asm/traps.h>
 | 
					#include <asm/traps.h>
 | 
				
			||||||
#include <arch/chip.h>
 | 
					#include <arch/chip.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -252,12 +253,21 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int do_syscall_trace_enter(struct pt_regs *regs)
 | 
					int do_syscall_trace_enter(struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (test_thread_flag(TIF_SYSCALL_TRACE)) {
 | 
						u32 work = ACCESS_ONCE(current_thread_info()->flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * If TIF_NOHZ is set, we are required to call user_exit() before
 | 
				
			||||||
 | 
						 * doing anything that could touch RCU.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (work & _TIF_NOHZ)
 | 
				
			||||||
 | 
							user_exit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (work & _TIF_SYSCALL_TRACE) {
 | 
				
			||||||
		if (tracehook_report_syscall_entry(regs))
 | 
							if (tracehook_report_syscall_entry(regs))
 | 
				
			||||||
			regs->regs[TREG_SYSCALL_NR] = -1;
 | 
								regs->regs[TREG_SYSCALL_NR] = -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 | 
						if (work & _TIF_SYSCALL_TRACEPOINT)
 | 
				
			||||||
		trace_sys_enter(regs, regs->regs[TREG_SYSCALL_NR]);
 | 
							trace_sys_enter(regs, regs->regs[TREG_SYSCALL_NR]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return regs->regs[TREG_SYSCALL_NR];
 | 
						return regs->regs[TREG_SYSCALL_NR];
 | 
				
			||||||
| 
						 | 
					@ -267,6 +277,12 @@ void do_syscall_trace_exit(struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	long errno;
 | 
						long errno;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * We may come here right after calling schedule_user()
 | 
				
			||||||
 | 
						 * in which case we can be in RCU user mode.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						user_exit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The standard tile calling convention returns the value (or negative
 | 
						 * The standard tile calling convention returns the value (or negative
 | 
				
			||||||
	 * errno) in r0, and zero (or positive errno) in r1.
 | 
						 * errno) in r0, and zero (or positive errno) in r1.
 | 
				
			||||||
| 
						 | 
					@ -303,5 +319,7 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs)
 | 
				
			||||||
/* Handle synthetic interrupt delivered only by the simulator. */
 | 
					/* Handle synthetic interrupt delivered only by the simulator. */
 | 
				
			||||||
void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num)
 | 
					void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						enum ctx_state prev_state = exception_enter();
 | 
				
			||||||
	send_sigtrap(current, regs);
 | 
						send_sigtrap(current, regs);
 | 
				
			||||||
 | 
						exception_exit(prev_state);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,7 @@
 | 
				
			||||||
#include <linux/types.h>
 | 
					#include <linux/types.h>
 | 
				
			||||||
#include <linux/err.h>
 | 
					#include <linux/err.h>
 | 
				
			||||||
#include <linux/prctl.h>
 | 
					#include <linux/prctl.h>
 | 
				
			||||||
 | 
					#include <linux/context_tracking.h>
 | 
				
			||||||
#include <asm/cacheflush.h>
 | 
					#include <asm/cacheflush.h>
 | 
				
			||||||
#include <asm/traps.h>
 | 
					#include <asm/traps.h>
 | 
				
			||||||
#include <asm/uaccess.h>
 | 
					#include <asm/uaccess.h>
 | 
				
			||||||
| 
						 | 
					@ -738,6 +739,7 @@ static DEFINE_PER_CPU(unsigned long, ss_saved_pc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void gx_singlestep_handle(struct pt_regs *regs, int fault_num)
 | 
					void gx_singlestep_handle(struct pt_regs *regs, int fault_num)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						enum ctx_state prev_state = exception_enter();
 | 
				
			||||||
	unsigned long *ss_pc = this_cpu_ptr(&ss_saved_pc);
 | 
						unsigned long *ss_pc = this_cpu_ptr(&ss_saved_pc);
 | 
				
			||||||
	struct thread_info *info = (void *)current_thread_info();
 | 
						struct thread_info *info = (void *)current_thread_info();
 | 
				
			||||||
	int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP);
 | 
						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)
 | 
				
			||||||
		__insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control);
 | 
							__insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control);
 | 
				
			||||||
		send_sigtrap(current, regs);
 | 
							send_sigtrap(current, regs);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						exception_exit(prev_state);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,6 +20,7 @@
 | 
				
			||||||
#include <linux/reboot.h>
 | 
					#include <linux/reboot.h>
 | 
				
			||||||
#include <linux/uaccess.h>
 | 
					#include <linux/uaccess.h>
 | 
				
			||||||
#include <linux/ptrace.h>
 | 
					#include <linux/ptrace.h>
 | 
				
			||||||
 | 
					#include <linux/context_tracking.h>
 | 
				
			||||||
#include <asm/stack.h>
 | 
					#include <asm/stack.h>
 | 
				
			||||||
#include <asm/traps.h>
 | 
					#include <asm/traps.h>
 | 
				
			||||||
#include <asm/setup.h>
 | 
					#include <asm/setup.h>
 | 
				
			||||||
| 
						 | 
					@ -253,6 +254,7 @@ static int do_bpt(struct pt_regs *regs)
 | 
				
			||||||
void __kprobes do_trap(struct pt_regs *regs, int fault_num,
 | 
					void __kprobes do_trap(struct pt_regs *regs, int fault_num,
 | 
				
			||||||
		       unsigned long reason)
 | 
							       unsigned long reason)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						enum ctx_state prev_state = exception_enter();
 | 
				
			||||||
	siginfo_t info = { 0 };
 | 
						siginfo_t info = { 0 };
 | 
				
			||||||
	int signo, code;
 | 
						int signo, code;
 | 
				
			||||||
	unsigned long address = 0;
 | 
						unsigned long address = 0;
 | 
				
			||||||
| 
						 | 
					@ -261,7 +263,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Handle breakpoints, etc. */
 | 
						/* Handle breakpoints, etc. */
 | 
				
			||||||
	if (is_kernel && fault_num == INT_ILL && do_bpt(regs))
 | 
						if (is_kernel && fault_num == INT_ILL && do_bpt(regs))
 | 
				
			||||||
		return;
 | 
							goto done;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Re-enable interrupts, if they were previously enabled. */
 | 
						/* Re-enable interrupts, if they were previously enabled. */
 | 
				
			||||||
	if (!(regs->flags & PT_FLAGS_DISABLE_IRQ))
 | 
						if (!(regs->flags & PT_FLAGS_DISABLE_IRQ))
 | 
				
			||||||
| 
						 | 
					@ -275,7 +277,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
 | 
				
			||||||
		const char *name;
 | 
							const char *name;
 | 
				
			||||||
		char buf[100];
 | 
							char buf[100];
 | 
				
			||||||
		if (fixup_exception(regs))  /* ILL_TRANS or UNALIGN_DATA */
 | 
							if (fixup_exception(regs))  /* ILL_TRANS or UNALIGN_DATA */
 | 
				
			||||||
			return;
 | 
								goto done;
 | 
				
			||||||
		if (fault_num >= 0 &&
 | 
							if (fault_num >= 0 &&
 | 
				
			||||||
		    fault_num < ARRAY_SIZE(int_name) &&
 | 
							    fault_num < ARRAY_SIZE(int_name) &&
 | 
				
			||||||
		    int_name[fault_num] != NULL)
 | 
							    int_name[fault_num] != NULL)
 | 
				
			||||||
| 
						 | 
					@ -294,7 +296,6 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
 | 
				
			||||||
			 fault_num, name, regs->pc, buf);
 | 
								 fault_num, name, regs->pc, buf);
 | 
				
			||||||
		show_regs(regs);
 | 
							show_regs(regs);
 | 
				
			||||||
		do_exit(SIGKILL);  /* FIXME: implement i386 die() */
 | 
							do_exit(SIGKILL);  /* FIXME: implement i386 die() */
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (fault_num) {
 | 
						switch (fault_num) {
 | 
				
			||||||
| 
						 | 
					@ -308,7 +309,6 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
 | 
				
			||||||
			pr_err("Unreadable instruction for INT_ILL: %#lx\n",
 | 
								pr_err("Unreadable instruction for INT_ILL: %#lx\n",
 | 
				
			||||||
			       regs->pc);
 | 
								       regs->pc);
 | 
				
			||||||
			do_exit(SIGKILL);
 | 
								do_exit(SIGKILL);
 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (!special_ill(instr, &signo, &code)) {
 | 
							if (!special_ill(instr, &signo, &code)) {
 | 
				
			||||||
			signo = SIGILL;
 | 
								signo = SIGILL;
 | 
				
			||||||
| 
						 | 
					@ -319,7 +319,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
 | 
				
			||||||
	case INT_GPV:
 | 
						case INT_GPV:
 | 
				
			||||||
#if CHIP_HAS_TILE_DMA()
 | 
					#if CHIP_HAS_TILE_DMA()
 | 
				
			||||||
		if (retry_gpv(reason))
 | 
							if (retry_gpv(reason))
 | 
				
			||||||
			return;
 | 
								goto done;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
		/*FALLTHROUGH*/
 | 
							/*FALLTHROUGH*/
 | 
				
			||||||
	case INT_UDN_ACCESS:
 | 
						case INT_UDN_ACCESS:
 | 
				
			||||||
| 
						 | 
					@ -346,7 +346,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
 | 
				
			||||||
			if (!state ||
 | 
								if (!state ||
 | 
				
			||||||
			    (void __user *)(regs->pc) != state->buffer) {
 | 
								    (void __user *)(regs->pc) != state->buffer) {
 | 
				
			||||||
				single_step_once(regs);
 | 
									single_step_once(regs);
 | 
				
			||||||
				return;
 | 
									goto done;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -380,7 +380,6 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		panic("Unexpected do_trap interrupt number %d", fault_num);
 | 
							panic("Unexpected do_trap interrupt number %d", fault_num);
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	info.si_signo = signo;
 | 
						info.si_signo = signo;
 | 
				
			||||||
| 
						 | 
					@ -391,6 +390,9 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
 | 
				
			||||||
	if (signo != SIGTRAP)
 | 
						if (signo != SIGTRAP)
 | 
				
			||||||
		trace_unhandled_signal("trap", regs, address, signo);
 | 
							trace_unhandled_signal("trap", regs, address, signo);
 | 
				
			||||||
	force_sig_info(signo, &info, current);
 | 
						force_sig_info(signo, &info, current);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					done:
 | 
				
			||||||
 | 
						exception_exit(prev_state);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void kernel_double_fault(int dummy, ulong pc, ulong lr, ulong sp, ulong r52)
 | 
					void kernel_double_fault(int dummy, ulong pc, ulong lr, ulong sp, ulong r52)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,7 @@
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
#include <linux/compat.h>
 | 
					#include <linux/compat.h>
 | 
				
			||||||
#include <linux/prctl.h>
 | 
					#include <linux/prctl.h>
 | 
				
			||||||
 | 
					#include <linux/context_tracking.h>
 | 
				
			||||||
#include <asm/cacheflush.h>
 | 
					#include <asm/cacheflush.h>
 | 
				
			||||||
#include <asm/traps.h>
 | 
					#include <asm/traps.h>
 | 
				
			||||||
#include <asm/uaccess.h>
 | 
					#include <asm/uaccess.h>
 | 
				
			||||||
| 
						 | 
					@ -1448,6 +1449,7 @@ void jit_bundle_gen(struct pt_regs *regs, tilegx_bundle_bits bundle,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void do_unaligned(struct pt_regs *regs, int vecnum)
 | 
					void do_unaligned(struct pt_regs *regs, int vecnum)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						enum ctx_state prev_state = exception_enter();
 | 
				
			||||||
	tilegx_bundle_bits __user  *pc;
 | 
						tilegx_bundle_bits __user  *pc;
 | 
				
			||||||
	tilegx_bundle_bits bundle;
 | 
						tilegx_bundle_bits bundle;
 | 
				
			||||||
	struct thread_info *info = current_thread_info();
 | 
						struct thread_info *info = current_thread_info();
 | 
				
			||||||
| 
						 | 
					@ -1487,12 +1489,11 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
 | 
				
			||||||
						(int)unaligned_fixup,
 | 
											(int)unaligned_fixup,
 | 
				
			||||||
						(unsigned long long)regs->ex1,
 | 
											(unsigned long long)regs->ex1,
 | 
				
			||||||
						(unsigned long long)regs->pc);
 | 
											(unsigned long long)regs->pc);
 | 
				
			||||||
				return;
 | 
								} else {
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
				/* Not fixable. Go panic. */
 | 
									/* Not fixable. Go panic. */
 | 
				
			||||||
				panic("Unalign exception in Kernel. pc=%lx",
 | 
									panic("Unalign exception in Kernel. pc=%lx",
 | 
				
			||||||
				      regs->pc);
 | 
									      regs->pc);
 | 
				
			||||||
			return;
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * Try to fix the exception. If we can't, panic the
 | 
								 * Try to fix the exception. If we can't, panic the
 | 
				
			||||||
| 
						 | 
					@ -1501,8 +1502,8 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
 | 
				
			||||||
			bundle = GX_INSN_BSWAP(
 | 
								bundle = GX_INSN_BSWAP(
 | 
				
			||||||
				*((tilegx_bundle_bits *)(regs->pc)));
 | 
									*((tilegx_bundle_bits *)(regs->pc)));
 | 
				
			||||||
			jit_bundle_gen(regs, bundle, align_ctl);
 | 
								jit_bundle_gen(regs, bundle, align_ctl);
 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -1526,7 +1527,7 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		trace_unhandled_signal("unaligned fixup trap", regs, 0, SIGBUS);
 | 
							trace_unhandled_signal("unaligned fixup trap", regs, 0, SIGBUS);
 | 
				
			||||||
		force_sig_info(info.si_signo, &info, current);
 | 
							force_sig_info(info.si_signo, &info, current);
 | 
				
			||||||
		return;
 | 
							goto done;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1543,7 +1544,7 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
 | 
				
			||||||
		trace_unhandled_signal("segfault in unalign fixup", regs,
 | 
							trace_unhandled_signal("segfault in unalign fixup", regs,
 | 
				
			||||||
				       (unsigned long)info.si_addr, SIGSEGV);
 | 
									       (unsigned long)info.si_addr, SIGSEGV);
 | 
				
			||||||
		force_sig_info(info.si_signo, &info, current);
 | 
							force_sig_info(info.si_signo, &info, current);
 | 
				
			||||||
		return;
 | 
							goto done;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!info->unalign_jit_base) {
 | 
						if (!info->unalign_jit_base) {
 | 
				
			||||||
| 
						 | 
					@ -1578,7 +1579,7 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (IS_ERR((void __force *)user_page)) {
 | 
							if (IS_ERR((void __force *)user_page)) {
 | 
				
			||||||
			pr_err("Out of kernel pages trying do_mmap\n");
 | 
								pr_err("Out of kernel pages trying do_mmap\n");
 | 
				
			||||||
			return;
 | 
								goto done;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Save the address in the thread_info struct */
 | 
							/* Save the address in the thread_info struct */
 | 
				
			||||||
| 
						 | 
					@ -1591,6 +1592,9 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Generate unalign JIT */
 | 
						/* Generate unalign JIT */
 | 
				
			||||||
	jit_bundle_gen(regs, GX_INSN_BSWAP(bundle), align_ctl);
 | 
						jit_bundle_gen(regs, GX_INSN_BSWAP(bundle), align_ctl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					done:
 | 
				
			||||||
 | 
						exception_exit(prev_state);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __tilegx__ */
 | 
					#endif /* __tilegx__ */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,6 +35,7 @@
 | 
				
			||||||
#include <linux/syscalls.h>
 | 
					#include <linux/syscalls.h>
 | 
				
			||||||
#include <linux/uaccess.h>
 | 
					#include <linux/uaccess.h>
 | 
				
			||||||
#include <linux/kdebug.h>
 | 
					#include <linux/kdebug.h>
 | 
				
			||||||
 | 
					#include <linux/context_tracking.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/pgalloc.h>
 | 
					#include <asm/pgalloc.h>
 | 
				
			||||||
#include <asm/sections.h>
 | 
					#include <asm/sections.h>
 | 
				
			||||||
| 
						 | 
					@ -702,6 +703,7 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
 | 
				
			||||||
		   unsigned long address, unsigned long write)
 | 
							   unsigned long address, unsigned long write)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int is_page_fault;
 | 
						int is_page_fault;
 | 
				
			||||||
 | 
						enum ctx_state prev_state = exception_enter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_KPROBES
 | 
					#ifdef CONFIG_KPROBES
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -711,7 +713,7 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (notify_die(DIE_PAGE_FAULT, "page fault", regs, -1,
 | 
						if (notify_die(DIE_PAGE_FAULT, "page fault", regs, -1,
 | 
				
			||||||
		       regs->faultnum, SIGSEGV) == NOTIFY_STOP)
 | 
							       regs->faultnum, SIGSEGV) == NOTIFY_STOP)
 | 
				
			||||||
		return;
 | 
							goto done;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __tilegx__
 | 
					#ifdef __tilegx__
 | 
				
			||||||
| 
						 | 
					@ -750,7 +752,6 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
 | 
				
			||||||
				 current->comm, current->pid, pc, address);
 | 
									 current->comm, current->pid, pc, address);
 | 
				
			||||||
			show_regs(regs);
 | 
								show_regs(regs);
 | 
				
			||||||
			do_group_exit(SIGKILL);
 | 
								do_group_exit(SIGKILL);
 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
| 
						 | 
					@ -834,12 +835,15 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
 | 
				
			||||||
			async->is_fault = is_page_fault;
 | 
								async->is_fault = is_page_fault;
 | 
				
			||||||
			async->is_write = write;
 | 
								async->is_write = write;
 | 
				
			||||||
			async->address = address;
 | 
								async->address = address;
 | 
				
			||||||
			return;
 | 
								goto done;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	handle_page_fault(regs, fault_num, is_page_fault, address, write);
 | 
						handle_page_fault(regs, fault_num, is_page_fault, address, write);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					done:
 | 
				
			||||||
 | 
						exception_exit(prev_state);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue