Commit 6b6e177d authored by Linus Torvalds's avatar Linus Torvalds

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
parents bfaf2450 128f3cb9
...@@ -27,6 +27,7 @@ config TILE ...@@ -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
......
...@@ -16,7 +16,6 @@ generic-y += ioctl.h ...@@ -16,7 +16,6 @@ generic-y += ioctl.h
generic-y += ioctls.h generic-y += ioctls.h
generic-y += ipcbuf.h generic-y += ipcbuf.h
generic-y += irq_regs.h generic-y += irq_regs.h
generic-y += irq_work.h
generic-y += local.h generic-y += local.h
generic-y += local64.h generic-y += local64.h
generic-y += mcs_spinlock.h generic-y += mcs_spinlock.h
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
extern void __mcount(void); extern void __mcount(void);
#define ARCH_SUPPORTS_FTRACE_OPS 1
#ifdef CONFIG_DYNAMIC_FTRACE #ifdef CONFIG_DYNAMIC_FTRACE
static inline unsigned long ftrace_call_adjust(unsigned long addr) static inline unsigned long ftrace_call_adjust(unsigned long addr)
{ {
......
#ifndef __ASM_IRQ_WORK_H
#define __ASM_IRQ_WORK_H
static inline bool arch_irq_work_has_interrupt(void)
{
#ifdef CONFIG_SMP
extern bool self_interrupt_ok;
return self_interrupt_ok;
#else
return false;
#endif
}
#endif /* __ASM_IRQ_WORK_H */
...@@ -69,6 +69,7 @@ static inline int xy_to_cpu(int x, int y) ...@@ -69,6 +69,7 @@ static inline int xy_to_cpu(int x, int y)
#define MSG_TAG_STOP_CPU 2 #define MSG_TAG_STOP_CPU 2
#define MSG_TAG_CALL_FUNCTION_MANY 3 #define MSG_TAG_CALL_FUNCTION_MANY 3
#define MSG_TAG_CALL_FUNCTION_SINGLE 4 #define MSG_TAG_CALL_FUNCTION_SINGLE 4
#define MSG_TAG_IRQ_WORK 5
/* Hook for the generic smp_call_function_many() routine. */ /* Hook for the generic smp_call_function_many() routine. */
static inline void arch_send_call_function_ipi_mask(struct cpumask *mask) static inline void arch_send_call_function_ipi_mask(struct cpumask *mask)
......
...@@ -124,6 +124,7 @@ extern void _cpu_idle(void); ...@@ -124,6 +124,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)
...@@ -136,14 +137,16 @@ extern void _cpu_idle(void); ...@@ -136,14 +137,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)
......
...@@ -961,7 +961,11 @@ typedef enum { ...@@ -961,7 +961,11 @@ typedef enum {
HV_INQ_TILES_HFH_CACHE = 2, HV_INQ_TILES_HFH_CACHE = 2,
/** The set of tiles that can be legally used as a LOTAR for a PTE. */ /** The set of tiles that can be legally used as a LOTAR for a PTE. */
HV_INQ_TILES_LOTAR = 3 HV_INQ_TILES_LOTAR = 3,
/** The set of "shared" driver tiles that the hypervisor may
* periodically interrupt. */
HV_INQ_TILES_SHARED = 4
} HV_InqTileSet; } HV_InqTileSet;
/** Returns specific information about various sets of tiles within the /** Returns specific information about various sets of tiles within the
......
...@@ -68,7 +68,7 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr ...@@ -68,7 +68,7 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr
if (from->si_code < 0) { if (from->si_code < 0) {
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr); err |= __put_user(from->si_int, &to->si_int);
} else { } else {
/* /*
* First 32bits of unions are always present: * 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,8 +93,7 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr
break; break;
case __SI_TIMER >> 16: case __SI_TIMER >> 16:
err |= __put_user(from->si_overrun, &to->si_overrun); err |= __put_user(from->si_overrun, &to->si_overrun);
err |= __put_user(ptr_to_compat(from->si_ptr), err |= __put_user(from->si_int, &to->si_int);
&to->si_ptr);
break; break;
/* This is not generated by the kernel as of now. */ /* This is not generated by the kernel as of now. */
case __SI_RT >> 16: case __SI_RT >> 16:
...@@ -110,19 +109,19 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr ...@@ -110,19 +109,19 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr
int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from) int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
{ {
int err; int err;
u32 ptr32;
if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo))) if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo)))
return -EFAULT; return -EFAULT;
memset(to, 0, sizeof(*to));
err = __get_user(to->si_signo, &from->si_signo); err = __get_user(to->si_signo, &from->si_signo);
err |= __get_user(to->si_errno, &from->si_errno); err |= __get_user(to->si_errno, &from->si_errno);
err |= __get_user(to->si_code, &from->si_code); err |= __get_user(to->si_code, &from->si_code);
err |= __get_user(to->si_pid, &from->si_pid); err |= __get_user(to->si_pid, &from->si_pid);
err |= __get_user(to->si_uid, &from->si_uid); err |= __get_user(to->si_uid, &from->si_uid);
err |= __get_user(ptr32, &from->si_ptr); err |= __get_user(to->si_int, &from->si_int);
to->si_ptr = compat_ptr(ptr32);
return err; return err;
} }
......
...@@ -74,7 +74,11 @@ static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr, ...@@ -74,7 +74,11 @@ static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr,
create_JumpOff_X1(pcrel_by_instr); create_JumpOff_X1(pcrel_by_instr);
} }
if (addr == FTRACE_ADDR) { /*
* Also put { move r10, lr; jal ftrace_stub } in a bundle, which
* is used to replace the instruction in address ftrace_call.
*/
if (addr == FTRACE_ADDR || addr == (unsigned long)ftrace_stub) {
/* opcode: or r10, lr, zero */ /* opcode: or r10, lr, zero */
opcode_x0 = opcode_x0 =
create_Dest_X0(10) | create_Dest_X0(10) |
......
...@@ -81,7 +81,12 @@ STD_ENTRY(ftrace_caller) ...@@ -81,7 +81,12 @@ STD_ENTRY(ftrace_caller)
/* arg1: self return address */ /* arg1: self return address */
/* arg2: parent's return address */ /* arg2: parent's return address */
{ move r0, lr; move r1, r10 } /* arg3: ftrace_ops */
/* arg4: regs (but make it NULL) */
{ move r0, lr; moveli r2, hw2_last(function_trace_op) }
{ move r1, r10; shl16insli r2, r2, hw1(function_trace_op) }
{ movei r3, 0; shl16insli r2, r2, hw0(function_trace_op) }
ld r2,r2
.global ftrace_call .global ftrace_call
ftrace_call: ftrace_call:
......
...@@ -27,6 +27,7 @@ ...@@ -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) ...@@ -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,11 +499,12 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags) ...@@ -496,11 +499,12 @@ 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 @@ ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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);
} }
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/hugetlb.h> #include <linux/hugetlb.h>
#include <linux/start_kernel.h> #include <linux/start_kernel.h>
#include <linux/screen_info.h> #include <linux/screen_info.h>
#include <linux/tick.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
...@@ -1390,6 +1391,28 @@ static int __init dataplane(char *str) ...@@ -1390,6 +1391,28 @@ static int __init dataplane(char *str)
early_param("dataplane", dataplane); early_param("dataplane", dataplane);
#ifdef CONFIG_NO_HZ_FULL
/* Warn if hypervisor shared cpus are marked as nohz_full. */
static int __init check_nohz_full_cpus(void)
{
struct cpumask shared;
int cpu;
if (hv_inquire_tiles(HV_INQ_TILES_SHARED,
(HV_VirtAddr) shared.bits, sizeof(shared)) < 0) {
pr_warn("WARNING: No support for inquiring hv shared tiles\n");
return 0;
}
for_each_cpu(cpu, &shared) {
if (tick_nohz_full_cpu(cpu))
pr_warn("WARNING: nohz_full cpu %d receives hypervisor interrupts!\n",
cpu);
}
return 0;
}
arch_initcall(check_nohz_full_cpus);
#endif
#ifdef CONFIG_CMDLINE_BOOL #ifdef CONFIG_CMDLINE_BOOL
static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
#endif #endif
......
...@@ -23,6 +23,7 @@ ...@@ -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); ...@@ -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) ...@@ -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);
} }
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/irq_work.h>
#include <linux/module.h> #include <linux/module.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/homecache.h> #include <asm/homecache.h>
...@@ -33,6 +34,8 @@ EXPORT_SYMBOL(smp_topology); ...@@ -33,6 +34,8 @@ EXPORT_SYMBOL(smp_topology);
static unsigned long __iomem *ipi_mappings[NR_CPUS]; static unsigned long __iomem *ipi_mappings[NR_CPUS];
#endif #endif
/* Does messaging work correctly to the local cpu? */
bool self_interrupt_ok;
/* /*
* Top-level send_IPI*() functions to send messages to other cpus. * Top-level send_IPI*() functions to send messages to other cpus.
...@@ -147,6 +150,10 @@ void evaluate_message(int tag) ...@@ -147,6 +150,10 @@ void evaluate_message(int tag)
generic_smp_call_function_single_interrupt(); generic_smp_call_function_single_interrupt();
break; break;
case MSG_TAG_IRQ_WORK: /* Invoke IRQ work */
irq_work_run();
break;
default: default:
panic("Unknown IPI message tag %d", tag); panic("Unknown IPI message tag %d", tag);
break; break;
...@@ -186,6 +193,15 @@ void flush_icache_range(unsigned long start, unsigned long end) ...@@ -186,6 +193,15 @@ void flush_icache_range(unsigned long start, unsigned long end)
EXPORT_SYMBOL(flush_icache_range); EXPORT_SYMBOL(flush_icache_range);
#ifdef CONFIG_IRQ_WORK
void arch_irq_work_raise(void)
{
if (arch_irq_work_has_interrupt())
send_IPI_single(smp_processor_id(), MSG_TAG_IRQ_WORK);
}
#endif
/* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */ /* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */
static irqreturn_t handle_reschedule_ipi(int irq, void *token) static irqreturn_t handle_reschedule_ipi(int irq, void *token)
{ {
...@@ -203,8 +219,22 @@ static struct irqaction resched_action = { ...@@ -203,8 +219,22 @@ static struct irqaction resched_action = {
void __init ipi_init(void) void __init ipi_init(void)
{ {
int cpu = smp_processor_id();
HV_Recipient recip = { .y = cpu_y(cpu), .x = cpu_x(cpu),
.state = HV_TO_BE_SENT };
int tag = MSG_TAG_CALL_FUNCTION_SINGLE;
/*
* Test if we can message ourselves for arch_irq_work_raise.
* This functionality is only available in the Tilera hypervisor
* in versions 4.3.4 and following.
*/
if (hv_send_message(&recip, 1, (HV_VirtAddr)&tag, sizeof(tag)) == 1)
self_interrupt_ok = true;
else
pr_warn("Older hypervisor: disabling fast irq_work_raise\n");
#if CHIP_HAS_IPI() #if CHIP_HAS_IPI()
int cpu;
/* Map IPI trigger MMIO addresses. */ /* Map IPI trigger MMIO addresses. */
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
HV_Coord tile; HV_Coord tile;
......
...@@ -108,14 +108,15 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt) ...@@ -108,14 +108,15 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
p->sp < PAGE_OFFSET && p->sp != 0) { p->sp < PAGE_OFFSET && p->sp != 0) {
if (kbt->verbose) if (kbt->verbose)
pr_err(" <%s while in user mode>\n", fault); pr_err(" <%s while in user mode>\n", fault);
} else if (kbt->verbose) { } else {
if (kbt->verbose)
pr_err(" (odd fault: pc %#lx, sp %#lx, ex1 %#lx?)\n", pr_err(" (odd fault: pc %#lx, sp %#lx, ex1 %#lx?)\n",
p->pc, p->sp, p->ex1); p->pc, p->sp, p->ex1);
p = NULL; return NULL;
} }
if (!kbt->profile || ((1ULL << p->faultnum) & QUEUED_INTERRUPTS) == 0) if (kbt->profile && ((1ULL << p->faultnum) & QUEUED_INTERRUPTS) != 0)
return p;
return NULL; return NULL;
return p;
} }
/* Is the pc pointing to a sigreturn trampoline? */ /* Is the pc pointing to a sigreturn trampoline? */
......
...@@ -20,6 +20,7 @@ ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 @@ ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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__ */
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/binfmts.h> #include <linux/binfmts.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/mman.h> #include <linux/mman.h>
#include <linux/file.h>
#include <linux/elf.h> #include <linux/elf.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
...@@ -39,30 +40,34 @@ static void sim_notify_exec(const char *binary_name) ...@@ -39,30 +40,34 @@ static void sim_notify_exec(const char *binary_name)
static int notify_exec(struct mm_struct *mm) static int notify_exec(struct mm_struct *mm)
{ {
int ret = 0;
char *buf, *path; char *buf, *path;
struct vm_area_struct *vma; struct vm_area_struct *vma;
struct file *exe_file;
if (!sim_is_simulator()) if (!sim_is_simulator())
return 1; return 1;
if (mm->exe_file == NULL)
return 0;
for (vma = current->mm->mmap; ; vma = vma->vm_next) {
if (vma == NULL)
return 0;
if (vma->vm_file == mm->exe_file)
break;
}
buf = (char *) __get_free_page(GFP_KERNEL); buf = (char *) __get_free_page(GFP_KERNEL);
if (buf == NULL) if (buf == NULL)
return 0; return 0;
path = d_path(&mm->exe_file->f_path, buf, PAGE_SIZE); exe_file = get_mm_exe_file(mm);
if (IS_ERR(path)) { if (exe_file == NULL)
free_page((unsigned long)buf); goto done_free;
return 0;
path = d_path(&exe_file->f_path, buf, PAGE_SIZE);
if (IS_ERR(path))
goto done_put;
down_read(&mm->mmap_sem);
for (vma = current->mm->mmap; ; vma = vma->vm_next) {
if (vma == NULL) {
up_read(&mm->mmap_sem);
goto done_put;
}
if (vma->vm_file == exe_file)
break;
} }
/* /*
...@@ -80,14 +85,20 @@ static int notify_exec(struct mm_struct *mm) ...@@ -80,14 +85,20 @@ static int notify_exec(struct mm_struct *mm)
__insn_mtspr(SPR_SIM_CONTROL, __insn_mtspr(SPR_SIM_CONTROL,
(SIM_CONTROL_DLOPEN (SIM_CONTROL_DLOPEN
| (c << _SIM_CONTROL_OPERATOR_BITS))); | (c << _SIM_CONTROL_OPERATOR_BITS)));
if (c == '\0') if (c == '\0') {
ret = 1; /* success */
break; break;
} }
} }
}
up_read(&mm->mmap_sem);
sim_notify_exec(path); sim_notify_exec(path);
done_put:
fput(exe_file);
done_free:
free_page((unsigned long)buf); free_page((unsigned long)buf);
return 1; return ret;
} }
/* Notify a running simulator, if any, that we loaded an interpreter. */ /* 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,8 +120,6 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
struct mm_struct *mm = current->mm; struct mm_struct *mm = current->mm;
int retval = 0; int retval = 0;
down_write(&mm->mmap_sem);
/* /*
* Notify the simulator that an exec just occurred. * Notify the simulator that an exec just occurred.
* If we can't find the filename of the mapping, just use * 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,6 +128,8 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
if (!notify_exec(mm)) if (!notify_exec(mm))
sim_notify_exec(bprm->filename); sim_notify_exec(bprm->filename);
down_write(&mm->mmap_sem);
retval = setup_vdso_pages(); retval = setup_vdso_pages();
#ifndef __tilegx__ #ifndef __tilegx__
......
...@@ -35,6 +35,7 @@ ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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);
} }
......
...@@ -233,9 +233,12 @@ static pgprot_t __init init_pgprot(ulong address) ...@@ -233,9 +233,12 @@ static pgprot_t __init init_pgprot(ulong address)
if (kdata_huge) if (kdata_huge)
return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH); return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH);
/* We map the aliased pages of permanent text inaccessible. */ /*
* We map the aliased pages of permanent text so we can
* update them if necessary, for ftrace, etc.
*/
if (address < (ulong) _sinittext - CODE_DELTA) if (address < (ulong) _sinittext - CODE_DELTA)
return PAGE_NONE; return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH);
/* We map read-only data non-coherent for performance. */ /* We map read-only data non-coherent for performance. */
if ((address >= (ulong) __start_rodata && if ((address >= (ulong) __start_rodata &&
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment