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
This commit is contained in:
Коммит
6b6e177d63
|
@ -27,6 +27,7 @@ config TILE
|
|||
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
|
||||
select HAVE_DEBUG_STACKOVERFLOW
|
||||
select ARCH_WANT_FRAME_POINTERS
|
||||
select HAVE_CONTEXT_TRACKING
|
||||
|
||||
# FIXME: investigate whether we need/want these options.
|
||||
# select HAVE_IOREMAP_PROT
|
||||
|
|
|
@ -16,7 +16,6 @@ generic-y += ioctl.h
|
|||
generic-y += ioctls.h
|
||||
generic-y += ipcbuf.h
|
||||
generic-y += irq_regs.h
|
||||
generic-y += irq_work.h
|
||||
generic-y += local.h
|
||||
generic-y += local64.h
|
||||
generic-y += mcs_spinlock.h
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#ifndef __ASSEMBLY__
|
||||
extern void __mcount(void);
|
||||
|
||||
#define ARCH_SUPPORTS_FTRACE_OPS 1
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
static inline unsigned long ftrace_call_adjust(unsigned long addr)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
#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)
|
|||
#define MSG_TAG_STOP_CPU 2
|
||||
#define MSG_TAG_CALL_FUNCTION_MANY 3
|
||||
#define MSG_TAG_CALL_FUNCTION_SINGLE 4
|
||||
#define MSG_TAG_IRQ_WORK 5
|
||||
|
||||
/* Hook for the generic smp_call_function_many() routine. */
|
||||
static inline void arch_send_call_function_ipi_mask(struct cpumask *mask)
|
||||
|
|
|
@ -124,6 +124,7 @@ extern void _cpu_idle(void);
|
|||
#define TIF_NOTIFY_RESUME 8 /* callback before returning to user */
|
||||
#define TIF_SYSCALL_TRACEPOINT 9 /* syscall tracepoint instrumentation */
|
||||
#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_NEED_RESCHED (1<<TIF_NEED_RESCHED)
|
||||
|
@ -136,14 +137,16 @@ extern void _cpu_idle(void);
|
|||
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
|
||||
#define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT)
|
||||
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
|
||||
#define _TIF_NOHZ (1<<TIF_NOHZ)
|
||||
|
||||
/* Work to do on any return to user space. */
|
||||
#define _TIF_ALLWORK_MASK \
|
||||
(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SINGLESTEP|\
|
||||
_TIF_ASYNC_TLB|_TIF_NOTIFY_RESUME)
|
||||
(_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_SINGLESTEP | \
|
||||
_TIF_ASYNC_TLB | _TIF_NOTIFY_RESUME | _TIF_NOHZ)
|
||||
|
||||
/* 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. */
|
||||
#define _TIF_SYSCALL_EXIT_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT)
|
||||
|
|
|
@ -961,7 +961,11 @@ typedef enum {
|
|||
HV_INQ_TILES_HFH_CACHE = 2,
|
||||
|
||||
/** 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;
|
||||
|
||||
/** 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
|
|||
if (from->si_code < 0) {
|
||||
err |= __put_user(from->si_pid, &to->si_pid);
|
||||
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 {
|
||||
/*
|
||||
* 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
|
|||
break;
|
||||
case __SI_TIMER >> 16:
|
||||
err |= __put_user(from->si_overrun, &to->si_overrun);
|
||||
err |= __put_user(ptr_to_compat(from->si_ptr),
|
||||
&to->si_ptr);
|
||||
err |= __put_user(from->si_int, &to->si_int);
|
||||
break;
|
||||
/* This is not generated by the kernel as of now. */
|
||||
case __SI_RT >> 16:
|
||||
|
@ -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 err;
|
||||
u32 ptr32;
|
||||
|
||||
if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo)))
|
||||
return -EFAULT;
|
||||
|
||||
memset(to, 0, sizeof(*to));
|
||||
|
||||
err = __get_user(to->si_signo, &from->si_signo);
|
||||
err |= __get_user(to->si_errno, &from->si_errno);
|
||||
err |= __get_user(to->si_code, &from->si_code);
|
||||
|
||||
err |= __get_user(to->si_pid, &from->si_pid);
|
||||
err |= __get_user(to->si_uid, &from->si_uid);
|
||||
err |= __get_user(ptr32, &from->si_ptr);
|
||||
to->si_ptr = compat_ptr(ptr32);
|
||||
err |= __get_user(to->si_int, &from->si_int);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -74,7 +74,11 @@ static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr,
|
|||
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_x0 =
|
||||
create_Dest_X0(10) |
|
||||
|
|
|
@ -81,7 +81,12 @@ STD_ENTRY(ftrace_caller)
|
|||
|
||||
/* arg1: self 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
|
||||
ftrace_call:
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/tracehook.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/context_tracking.h>
|
||||
#include <asm/stack.h>
|
||||
#include <asm/switch_to.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))
|
||||
return 0;
|
||||
|
||||
user_exit();
|
||||
|
||||
/* Enable interrupts; they are disabled again on return to caller. */
|
||||
local_irq_enable();
|
||||
|
||||
|
@ -496,11 +499,12 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
|
|||
tracehook_notify_resume(regs);
|
||||
return 1;
|
||||
}
|
||||
if (thread_info_flags & _TIF_SINGLESTEP) {
|
||||
if (thread_info_flags & _TIF_SINGLESTEP)
|
||||
single_step_once(regs);
|
||||
return 0;
|
||||
}
|
||||
panic("work_pending: bad flags %#x\n", thread_info_flags);
|
||||
|
||||
user_enter();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long get_wchan(struct task_struct *p)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/regset.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/tracehook.h>
|
||||
#include <linux/context_tracking.h>
|
||||
#include <asm/traps.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)
|
||||
{
|
||||
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))
|
||||
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]);
|
||||
|
||||
return regs->regs[TREG_SYSCALL_NR];
|
||||
|
@ -267,6 +277,12 @@ void do_syscall_trace_exit(struct pt_regs *regs)
|
|||
{
|
||||
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
|
||||
* 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. */
|
||||
void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num)
|
||||
{
|
||||
enum ctx_state prev_state = exception_enter();
|
||||
send_sigtrap(current, regs);
|
||||
exception_exit(prev_state);
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/hugetlb.h>
|
||||
#include <linux/start_kernel.h>
|
||||
#include <linux/screen_info.h>
|
||||
#include <linux/tick.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
@ -1390,6 +1391,28 @@ static int __init dataplane(char *str)
|
|||
|
||||
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
|
||||
static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
|
||||
#endif
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/prctl.h>
|
||||
#include <linux/context_tracking.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/traps.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)
|
||||
{
|
||||
enum ctx_state prev_state = exception_enter();
|
||||
unsigned long *ss_pc = this_cpu_ptr(&ss_saved_pc);
|
||||
struct thread_info *info = (void *)current_thread_info();
|
||||
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);
|
||||
send_sigtrap(current, regs);
|
||||
}
|
||||
exception_exit(prev_state);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irq_work.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/homecache.h>
|
||||
|
@ -33,6 +34,8 @@ EXPORT_SYMBOL(smp_topology);
|
|||
static unsigned long __iomem *ipi_mappings[NR_CPUS];
|
||||
#endif
|
||||
|
||||
/* Does messaging work correctly to the local cpu? */
|
||||
bool self_interrupt_ok;
|
||||
|
||||
/*
|
||||
* Top-level send_IPI*() functions to send messages to other cpus.
|
||||
|
@ -147,6 +150,10 @@ void evaluate_message(int tag)
|
|||
generic_smp_call_function_single_interrupt();
|
||||
break;
|
||||
|
||||
case MSG_TAG_IRQ_WORK: /* Invoke IRQ work */
|
||||
irq_work_run();
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("Unknown IPI message tag %d", tag);
|
||||
break;
|
||||
|
@ -186,6 +193,15 @@ void flush_icache_range(unsigned long start, unsigned long end)
|
|||
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. */
|
||||
static irqreturn_t handle_reschedule_ipi(int irq, void *token)
|
||||
{
|
||||
|
@ -203,8 +219,22 @@ static struct irqaction resched_action = {
|
|||
|
||||
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()
|
||||
int cpu;
|
||||
/* Map IPI trigger MMIO addresses. */
|
||||
for_each_possible_cpu(cpu) {
|
||||
HV_Coord tile;
|
||||
|
|
|
@ -108,14 +108,15 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
|
|||
p->sp < PAGE_OFFSET && p->sp != 0) {
|
||||
if (kbt->verbose)
|
||||
pr_err(" <%s while in user mode>\n", fault);
|
||||
} else if (kbt->verbose) {
|
||||
pr_err(" (odd fault: pc %#lx, sp %#lx, ex1 %#lx?)\n",
|
||||
p->pc, p->sp, p->ex1);
|
||||
p = NULL;
|
||||
} else {
|
||||
if (kbt->verbose)
|
||||
pr_err(" (odd fault: pc %#lx, sp %#lx, ex1 %#lx?)\n",
|
||||
p->pc, p->sp, p->ex1);
|
||||
return NULL;
|
||||
}
|
||||
if (!kbt->profile || ((1ULL << p->faultnum) & QUEUED_INTERRUPTS) == 0)
|
||||
return p;
|
||||
return NULL;
|
||||
if (kbt->profile && ((1ULL << p->faultnum) & QUEUED_INTERRUPTS) != 0)
|
||||
return NULL;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Is the pc pointing to a sigreturn trampoline? */
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/reboot.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/context_tracking.h>
|
||||
#include <asm/stack.h>
|
||||
#include <asm/traps.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,
|
||||
unsigned long reason)
|
||||
{
|
||||
enum ctx_state prev_state = exception_enter();
|
||||
siginfo_t info = { 0 };
|
||||
int signo, code;
|
||||
unsigned long address = 0;
|
||||
|
@ -261,7 +263,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
|
|||
|
||||
/* Handle breakpoints, etc. */
|
||||
if (is_kernel && fault_num == INT_ILL && do_bpt(regs))
|
||||
return;
|
||||
goto done;
|
||||
|
||||
/* Re-enable interrupts, if they were previously enabled. */
|
||||
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;
|
||||
char buf[100];
|
||||
if (fixup_exception(regs)) /* ILL_TRANS or UNALIGN_DATA */
|
||||
return;
|
||||
goto done;
|
||||
if (fault_num >= 0 &&
|
||||
fault_num < ARRAY_SIZE(int_name) &&
|
||||
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);
|
||||
show_regs(regs);
|
||||
do_exit(SIGKILL); /* FIXME: implement i386 die() */
|
||||
return;
|
||||
}
|
||||
|
||||
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",
|
||||
regs->pc);
|
||||
do_exit(SIGKILL);
|
||||
return;
|
||||
}
|
||||
if (!special_ill(instr, &signo, &code)) {
|
||||
signo = SIGILL;
|
||||
|
@ -319,7 +319,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
|
|||
case INT_GPV:
|
||||
#if CHIP_HAS_TILE_DMA()
|
||||
if (retry_gpv(reason))
|
||||
return;
|
||||
goto done;
|
||||
#endif
|
||||
/*FALLTHROUGH*/
|
||||
case INT_UDN_ACCESS:
|
||||
|
@ -346,7 +346,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
|
|||
if (!state ||
|
||||
(void __user *)(regs->pc) != state->buffer) {
|
||||
single_step_once(regs);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -380,7 +380,6 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
|
|||
#endif
|
||||
default:
|
||||
panic("Unexpected do_trap interrupt number %d", fault_num);
|
||||
return;
|
||||
}
|
||||
|
||||
info.si_signo = signo;
|
||||
|
@ -391,6 +390,9 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
|
|||
if (signo != SIGTRAP)
|
||||
trace_unhandled_signal("trap", regs, address, signo);
|
||||
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)
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/prctl.h>
|
||||
#include <linux/context_tracking.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/traps.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)
|
||||
{
|
||||
enum ctx_state prev_state = exception_enter();
|
||||
tilegx_bundle_bits __user *pc;
|
||||
tilegx_bundle_bits bundle;
|
||||
struct thread_info *info = current_thread_info();
|
||||
|
@ -1487,12 +1489,11 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
|
|||
(int)unaligned_fixup,
|
||||
(unsigned long long)regs->ex1,
|
||||
(unsigned long long)regs->pc);
|
||||
return;
|
||||
} else {
|
||||
/* Not fixable. Go panic. */
|
||||
panic("Unalign exception in Kernel. pc=%lx",
|
||||
regs->pc);
|
||||
}
|
||||
/* Not fixable. Go panic. */
|
||||
panic("Unalign exception in Kernel. pc=%lx",
|
||||
regs->pc);
|
||||
return;
|
||||
} else {
|
||||
/*
|
||||
* 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(
|
||||
*((tilegx_bundle_bits *)(regs->pc)));
|
||||
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);
|
||||
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,
|
||||
(unsigned long)info.si_addr, SIGSEGV);
|
||||
force_sig_info(info.si_signo, &info, current);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
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)) {
|
||||
pr_err("Out of kernel pages trying do_mmap\n");
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Save the address in the thread_info struct */
|
||||
|
@ -1591,6 +1592,9 @@ void do_unaligned(struct pt_regs *regs, int vecnum)
|
|||
|
||||
/* Generate unalign JIT */
|
||||
jit_bundle_gen(regs, GX_INSN_BSWAP(bundle), align_ctl);
|
||||
|
||||
done:
|
||||
exception_exit(prev_state);
|
||||
}
|
||||
|
||||
#endif /* __tilegx__ */
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/binfmts.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/elf.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/pgalloc.h>
|
||||
|
@ -39,30 +40,34 @@ static void sim_notify_exec(const char *binary_name)
|
|||
|
||||
static int notify_exec(struct mm_struct *mm)
|
||||
{
|
||||
int ret = 0;
|
||||
char *buf, *path;
|
||||
struct vm_area_struct *vma;
|
||||
struct file *exe_file;
|
||||
|
||||
if (!sim_is_simulator())
|
||||
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);
|
||||
if (buf == NULL)
|
||||
return 0;
|
||||
|
||||
path = d_path(&mm->exe_file->f_path, buf, PAGE_SIZE);
|
||||
if (IS_ERR(path)) {
|
||||
free_page((unsigned long)buf);
|
||||
return 0;
|
||||
exe_file = get_mm_exe_file(mm);
|
||||
if (exe_file == NULL)
|
||||
goto done_free;
|
||||
|
||||
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)
|
|||
__insn_mtspr(SPR_SIM_CONTROL,
|
||||
(SIM_CONTROL_DLOPEN
|
||||
| (c << _SIM_CONTROL_OPERATOR_BITS)));
|
||||
if (c == '\0')
|
||||
if (c == '\0') {
|
||||
ret = 1; /* success */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
up_read(&mm->mmap_sem);
|
||||
|
||||
sim_notify_exec(path);
|
||||
done_put:
|
||||
fput(exe_file);
|
||||
done_free:
|
||||
free_page((unsigned long)buf);
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Notify a running simulator, if any, that we loaded an interpreter. */
|
||||
|
@ -109,8 +120,6 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
|
|||
struct mm_struct *mm = current->mm;
|
||||
int retval = 0;
|
||||
|
||||
down_write(&mm->mmap_sem);
|
||||
|
||||
/*
|
||||
* Notify the simulator that an exec just occurred.
|
||||
* 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,
|
|||
if (!notify_exec(mm))
|
||||
sim_notify_exec(bprm->filename);
|
||||
|
||||
down_write(&mm->mmap_sem);
|
||||
|
||||
retval = setup_vdso_pages();
|
||||
|
||||
#ifndef __tilegx__
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <linux/syscalls.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/context_tracking.h>
|
||||
|
||||
#include <asm/pgalloc.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)
|
||||
{
|
||||
int is_page_fault;
|
||||
enum ctx_state prev_state = exception_enter();
|
||||
|
||||
#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,
|
||||
regs->faultnum, SIGSEGV) == NOTIFY_STOP)
|
||||
return;
|
||||
goto done;
|
||||
#endif
|
||||
|
||||
#ifdef __tilegx__
|
||||
|
@ -750,7 +752,6 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
|
|||
current->comm, current->pid, pc, address);
|
||||
show_regs(regs);
|
||||
do_group_exit(SIGKILL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
@ -834,12 +835,15 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
|
|||
async->is_fault = is_page_fault;
|
||||
async->is_write = write;
|
||||
async->address = address;
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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)
|
|||
if (kdata_huge)
|
||||
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)
|
||||
return PAGE_NONE;
|
||||
return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH);
|
||||
|
||||
/* We map read-only data non-coherent for performance. */
|
||||
if ((address >= (ulong) __start_rodata &&
|
||||
|
|
Загрузка…
Ссылка в новой задаче