Release 4.11 arch/arm/kernel/traps.c
/*
* linux/arch/arm/kernel/traps.c
*
* Copyright (C) 1995-2009 Russell King
* Fragments that appear the same as linux/arch/i386/kernel/traps.c (C) Linus Torvalds
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 'traps.c' handles hardware exceptions after we have saved some state in
* 'linux/arch/arm/lib/traps.S'. Mostly a debugging aid, but will probably
* kill the offending process.
*/
#include <linux/signal.h>
#include <linux/personality.h>
#include <linux/kallsyms.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>
#include <linux/hardirq.h>
#include <linux/kdebug.h>
#include <linux/module.h>
#include <linux/kexec.h>
#include <linux/bug.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/sched/signal.h>
#include <linux/sched/debug.h>
#include <linux/sched/task_stack.h>
#include <linux/irq.h>
#include <linux/atomic.h>
#include <asm/cacheflush.h>
#include <asm/exception.h>
#include <asm/unistd.h>
#include <asm/traps.h>
#include <asm/ptrace.h>
#include <asm/unwind.h>
#include <asm/tls.h>
#include <asm/system_misc.h>
#include <asm/opcodes.h>
static const char *handler[]= {
"prefetch abort",
"data abort",
"address exception",
"interrupt",
"undefined instruction",
};
void *vectors_page;
#ifdef CONFIG_DEBUG_USER
unsigned int user_debug;
static int __init user_debug_setup(char *str)
{
get_option(&str, &user_debug);
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Russell King | 23 | 100.00% | 1 | 100.00% |
Total | 23 | 100.00% | 1 | 100.00% |
__setup("user_debug=", user_debug_setup);
#endif
static void dump_mem(const char *, const char *, unsigned long, unsigned long);
void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame)
{
#ifdef CONFIG_KALLSYMS
printk("[<%08lx>] (%ps) from [<%08lx>] (%pS)\n", where, (void *)where, from, (void *)from);
#else
printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from);
#endif
if (in_exception_text(where))
dump_mem("", "Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Russell King | 72 | 87.80% | 7 | 87.50% |
Joe Perches | 10 | 12.20% | 1 | 12.50% |
Total | 82 | 100.00% | 8 | 100.00% |
void dump_backtrace_stm(u32 *stack, u32 instruction)
{
char str[80], *p;
unsigned int x;
int reg;
for (reg = 10, x = 0, p = str; reg >= 0; reg--) {
if (instruction & BIT(reg)) {
p += sprintf(p, " r%d:%08x", reg, *stack--);
if (++x == 6) {
x = 0;
p = str;
printk("%s\n", str);
}
}
}
if (p != str)
printk("%s\n", str);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Russell King | 114 | 100.00% | 1 | 100.00% |
Total | 114 | 100.00% | 1 | 100.00% |
#ifndef CONFIG_ARM_UNWIND
/*
* Stack pointers should always be within the kernels view of
* physical memory. If it is not there, then we can't dump
* out any information relating to the stack.
*/
static int verify_stack(unsigned long sp)
{
if (sp < PAGE_OFFSET ||
(sp > (unsigned long)high_memory && high_memory != NULL))
return -EFAULT;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 31 | 83.78% | 3 | 60.00% |
Linus Torvalds | 5 | 13.51% | 1 | 20.00% |
Russell King | 1 | 2.70% | 1 | 20.00% |
Total | 37 | 100.00% | 5 | 100.00% |
#endif
/*
* Dump out the contents of some memory nicely...
*/
static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
unsigned long top)
{
unsigned long first;
mm_segment_t fs;
int i;
/*
* We need to switch to kernel mode so that we can use __get_user
* to safely read from kernel space. Note that we now dump the
* code first, just in case the backtrace kills us.
*/
fs = get_fs();
set_fs(KERNEL_DS);
printk("%s%s(0x%08lx to 0x%08lx)\n", lvl, str, bottom, top);
for (first = bottom & ~31; first < top; first += 32) {
unsigned long p;
char str[sizeof(" 12345678") * 8 + 1];
memset(str, ' ', sizeof(str));
str[sizeof(str) - 1] = '\0';
for (p = first, i = 0; i < 8 && p < top; i++, p += 4) {
if (p >= bottom && p < top) {
unsigned long val;
if (__get_user(val, (unsigned long *)p) == 0)
sprintf(str + i * 9, " %08lx", val);
else
sprintf(str + i * 9, " ????????");
}
}
printk("%s%04lx:%s\n", lvl, first & 0xffff, str);
}
set_fs(fs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Russell King | 119 | 54.09% | 3 | 42.86% |
Linus Torvalds (pre-git) | 85 | 38.64% | 3 | 42.86% |
Linus Torvalds | 16 | 7.27% | 1 | 14.29% |
Total | 220 | 100.00% | 7 | 100.00% |
static void dump_instr(const char *lvl, struct pt_regs *regs)
{
unsigned long addr = instruction_pointer(regs);
const int thumb = thumb_mode(regs);
const int width = thumb ? 4 : 8;
mm_segment_t fs;
char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
int i;
/*
* We need to switch to kernel mode so that we can use __get_user
* to safely read from kernel space. Note that we now dump the
* code first, just in case the backtrace kills us.
*/
fs = get_fs();
set_fs(KERNEL_DS);
for (i = -4; i < 1 + !!thumb; i++) {
unsigned int val, bad;
if (thumb)
bad = __get_user(val, &((u16 *)addr)[i]);
else
bad = __get_user(val, &((u32 *)addr)[i]);
if (!bad)
p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ",
width, val);
else {
p += sprintf(p, "bad PC value");
break;
}
}
printk("%sCode: %s\n", lvl, str);
set_fs(fs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 134 | 66.67% | 3 | 33.33% |
Russell King | 66 | 32.84% | 5 | 55.56% |
Linus Torvalds | 1 | 0.50% | 1 | 11.11% |
Total | 201 | 100.00% | 9 | 100.00% |
#ifdef CONFIG_ARM_UNWIND
static inline void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
{
unwind_backtrace(regs, tsk);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Catalin Marinas | 24 | 100.00% | 1 | 100.00% |
Total | 24 | 100.00% | 1 | 100.00% |
#else
static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
{
unsigned int fp, mode;
int ok = 1;
printk("Backtrace: ");
if (!tsk)
tsk = current;
if (regs) {
fp = frame_pointer(regs);
mode = processor_mode(regs);
} else if (tsk != current) {
fp = thread_saved_fp(tsk);
mode = 0x10;
} else {
asm("mov %0, fp" : "=r" (fp) : : "cc");
mode = 0x10;
}
if (!fp) {
pr_cont("no frame pointer");
ok = 0;
} else if (verify_stack(fp)) {
pr_cont("invalid frame pointer 0x%08x", fp);
ok = 0;
} else if (fp < (unsigned long)end_of_stack(tsk))
pr_cont("frame pointer underflow");
pr_cont("\n");
if (ok)
c_backtrace(fp, mode);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 95 | 59.01% | 3 | 33.33% |
Catalin Marinas | 53 | 32.92% | 1 | 11.11% |
Russell King | 6 | 3.73% | 2 | 22.22% |
Al Viro | 3 | 1.86% | 1 | 11.11% |
Nikolay Borisov | 3 | 1.86% | 1 | 11.11% |
Linus Torvalds | 1 | 0.62% | 1 | 11.11% |
Total | 161 | 100.00% | 9 | 100.00% |
#endif
void show_stack(struct task_struct *tsk, unsigned long *sp)
{
dump_backtrace(NULL, tsk);
barrier();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds | 13 | 52.00% | 1 | 25.00% |
Russell King | 6 | 24.00% | 1 | 25.00% |
Marc Singer | 3 | 12.00% | 1 | 25.00% |
Catalin Marinas | 3 | 12.00% | 1 | 25.00% |
Total | 25 | 100.00% | 4 | 100.00% |
#ifdef CONFIG_PREEMPT
#define S_PREEMPT " PREEMPT"
#else
#define S_PREEMPT ""
#endif
#ifdef CONFIG_SMP
#define S_SMP " SMP"
#else
#define S_SMP ""
#endif
#ifdef CONFIG_THUMB2_KERNEL
#define S_ISA " THUMB2"
#else
#define S_ISA " ARM"
#endif
static int __die(const char *str, int err, struct pt_regs *regs)
{
struct task_struct *tsk = current;
static int die_counter;
int ret;
pr_emerg("Internal error: %s: %x [#%d]" S_PREEMPT S_SMP S_ISA "\n",
str, err, ++die_counter);
/* trap and error numbers are mostly meaningless on ARM */
ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV);
if (ret == NOTIFY_STOP)
return 1;
print_modules();
__show_regs(regs);
pr_emerg("Process %.*s (pid: %d, stack limit = 0x%p)\n",
TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), end_of_stack(tsk));
if (!user_mode(regs) || in_interrupt()) {
dump_mem(KERN_EMERG, "Stack: ", regs->ARM_sp,
THREAD_SIZE + (unsigned long)task_stack_page(tsk));
dump_backtrace(regs, tsk);
dump_instr(KERN_EMERG, regs);
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Russell King | 77 | 48.73% | 10 | 50.00% |
Linus Torvalds (pre-git) | 55 | 34.81% | 4 | 20.00% |
Linus Torvalds | 8 | 5.06% | 2 | 10.00% |
Rabin Vincent | 7 | 4.43% | 1 | 5.00% |
Andrew Morton | 5 | 3.16% | 1 | 5.00% |
Alexey Dobriyan | 3 | 1.90% | 1 | 5.00% |
Al Viro | 3 | 1.90% | 1 | 5.00% |
Total | 158 | 100.00% | 20 | 100.00% |
static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED;
static int die_owner = -1;
static unsigned int die_nest_count;
static unsigned long oops_begin(void)
{
int cpu;
unsigned long flags;
oops_enter();
/* racy, but better than risking deadlock. */
raw_local_irq_save(flags);
cpu = smp_processor_id();
if (!arch_spin_trylock(&die_lock)) {
if (cpu == die_owner)
/* nested oops. should stop eventually */;
else
arch_spin_lock(&die_lock);
}
die_nest_count++;
die_owner = cpu;
console_verbose();
bust_spinlocks(1);
return flags;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Rabin Vincent | 46 | 62.16% | 1 | 14.29% |
Russell King | 17 | 22.97% | 4 | 57.14% |
Simon Glass | 6 | 8.11% | 1 | 14.29% |
Stephen Boyd | 5 | 6.76% | 1 | 14.29% |
Total | 74 | 100.00% | 7 | 100.00% |
static void oops_end(unsigned long flags, struct pt_regs *regs, int signr)
{
if (regs && kexec_should_crash(current))
crash_kexec(regs);
bust_spinlocks(0);
die_owner = -1;
add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
die_nest_count--;
if (!die_nest_count)
/* Nest count reaches zero, release the lock. */
arch_spin_unlock(&die_lock);
raw_local_irq_restore(flags);
oops_exit();
if (in_interrupt())
panic("Fatal exception in interrupt");
if (panic_on_oops)
panic("Fatal exception");
if (signr)
do_exit(signr);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Rabin Vincent | 43 | 43.00% | 1 | 8.33% |
Russell King | 42 | 42.00% | 5 | 41.67% |
Linus Torvalds (pre-git) | 7 | 7.00% | 3 | 25.00% |
Pavel Emelyanov | 5 | 5.00% | 1 | 8.33% |
Rusty Russell | 2 | 2.00% | 1 | 8.33% |
Simon Horman | 1 | 1.00% | 1 | 8.33% |
Total | 100 | 100.00% | 12 | 100.00% |
/*
* This function is protected against re-entrancy.
*/
void die(const char *str, struct pt_regs *regs, int err)
{
enum bug_trap_type bug_type = BUG_TRAP_TYPE_NONE;
unsigned long flags = oops_begin();
int sig = SIGSEGV;
if (!user_mode(regs))
bug_type = report_bug(regs->ARM_pc, regs);
if (bug_type != BUG_TRAP_TYPE_NONE)
str = "Oops - BUG";
if (__die(str, err, regs))
sig = 0;
oops_end(flags, regs, sig);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Rabin Vincent | 85 | 95.51% | 1 | 33.33% |
Linus Torvalds (pre-git) | 4 | 4.49% | 2 | 66.67% |
Total | 89 | 100.00% | 3 | 100.00% |
void arm_notify_die(const char *str, struct pt_regs *regs,
struct siginfo *info, unsigned long err, unsigned long trap)
{
if (user_mode(regs)) {
current->thread.error_code = err;
current->thread.trap_no = trap;
force_sig_info(info->si_signo, info, current);
} else {
die(str, regs, err);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Russell King | 75 | 98.68% | 2 | 66.67% |
Christoph Hellwig | 1 | 1.32% | 1 | 33.33% |
Total | 76 | 100.00% | 3 | 100.00% |
#ifdef CONFIG_GENERIC_BUG
int is_valid_bugaddr(unsigned long pc)
{
#ifdef CONFIG_THUMB2_KERNEL
u16 bkpt;
u16 insn = __opcode_to_mem_thumb16(BUG_INSTR_VALUE);
#else
u32 bkpt;
u32 insn = __opcode_to_mem_arm(BUG_INSTR_VALUE);
#endif
if (probe_kernel_address((unsigned *)pc, bkpt))
return 0;
return bkpt == insn;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Simon Glass | 40 | 67.80% | 1 | 50.00% |
Ben Dooks | 19 | 32.20% | 1 | 50.00% |
Total | 59 | 100.00% | 2 | 100.00% |
#endif
static LIST_HEAD(undef_hook);
static DEFINE_RAW_SPINLOCK(undef_lock);
void register_undef_hook(struct undef_hook *hook)
{
unsigned long flags;
raw_spin_lock_irqsave(&undef_lock, flags);
list_add(&hook->node, &undef_hook);
raw_spin_unlock_irqrestore(&undef_lock, flags);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Russell King | 39 | 95.12% | 2 | 66.67% |
Thomas Gleixner | 2 | 4.88% | 1 | 33.33% |
Total | 41 | 100.00% | 3 | 100.00% |
void unregister_undef_hook(struct undef_hook *hook)
{
unsigned long flags;
raw_spin_lock_irqsave(&undef_lock, flags);
list_del(&hook->node);
raw_spin_unlock_irqrestore(&undef_lock, flags);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Russell King | 36 | 94.74% | 2 | 66.67% |
Thomas Gleixner | 2 | 5.26% | 1 | 33.33% |
Total | 38 | 100.00% | 3 | 100.00% |
static int call_undef_hook(struct pt_regs *regs, unsigned int instr)
{
struct undef_hook *hook;
unsigned long flags;
int (*fn)(struct pt_regs *regs, unsigned int instr) = NULL;
raw_spin_lock_irqsave(&undef_lock, flags);
list_for_each_entry(hook, &undef_hook, node)
if ((instr & hook->instr_mask) == hook->instr_val &&
(regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val)
fn = hook->fn;
raw_spin_unlock_irqrestore(&undef_lock, flags);
return fn ? fn(regs, instr) : 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Russell King | 110 | 98.21% | 1 | 50.00% |
Thomas Gleixner | 2 | 1.79% | 1 | 50.00% |
Total | 112 | 100.00% | 2 | 100.00% |
asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
{
unsigned int instr;
siginfo_t info;
void __user *pc;
pc = (void __user *)instruction_pointer(regs);
if (processor_mode(regs) == SVC_MODE) {
#ifdef CONFIG_THUMB2_KERNEL
if (thumb_mode(regs)) {
instr = __mem_to_opcode_thumb16(((u16 *)pc)[0]);
if (is_wide_instruction(instr)) {
u16 inst2;
inst2 = __mem_to_opcode_thumb16(((u16 *)pc)[1]);
instr = __opcode_thumb32_compose(instr, inst2);
}
} else
#endif
instr = __mem_to_opcode_arm(*(u32 *) pc);
} else if (thumb_mode(regs)) {
if (get_user(instr, (u16 __user *)pc))
goto die_sig;
instr = __mem_to_opcode_thumb16(instr);
if (is_wide_instruction(instr)) {
unsigned int instr2;
if (get_user(instr2, (u16 __user *)pc+1))
goto die_sig;
instr2 = __mem_to_opcode_thumb16(instr2);
instr = __opcode_thumb32_compose(instr, instr2);
}
} else {
if (get_user(instr, (u32 __user *)pc))
goto die_sig;
instr = __mem_to_opcode_arm(instr);
}
if (call_undef_hook(regs, instr) == 0)
return;
die_sig:
#ifdef CONFIG_DEBUG_USER
if (user_debug & UDBG_UNDEFINED) {
pr_info("%s (%d): undefined instruction: pc=%p\n",
current->comm, task_pid_nr(current), pc);
__show_regs(regs);
dump_instr(KERN_INFO, regs);
}
#endif
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_ILLOPC;
info.si_addr = pc;
arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jon Medhurst (Tixy) | 78 | 23.71% | 1 | 4.35% |
Russell King | 73 | 22.19% | 9 | 39.13% |
Linus Torvalds (pre-git) | 65 | 19.76% | 4 | 17.39% |
Ben Dooks | 49 | 14.89% | 1 | 4.35% |
Dan J Williams | 21 | 6.38% | 1 | 4.35% |
Will Deacon | 17 | 5.17% | 1 | 4.35% |
Linus Torvalds | 13 | 3.95% | 2 | 8.70% |
Taras Kondratiuk | 5 | 1.52% | 1 | 4.35% |
Al Viro | 4 | 1.22% | 1 | 4.35% |
Alexey Dobriyan | 3 | 0.91% | 1 | 4.35% |
Christoph Hellwig | 1 | 0.30% | 1 | 4.35% |
Total | 329 | 100.00% | 23 | 100.00% |
/*
* Handle FIQ similarly to NMI on x86 systems.
*
* The runtime environment for NMIs is extremely restrictive
* (NMIs can pre-empt critical sections meaning almost all locking is
* forbidden) meaning this default FIQ handling must only be used in
* circumstances where non-maskability improves robustness, such as
* watchdog or debug logic.
*
* This handler is not appropriate for general purpose use in drivers
* platform code and can be overrideen using set_fiq_handler.
*/
asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
nmi_enter();
/* nop. FIQ handlers for special arch/arm features can be added here. */
nmi_exit();
set_irq_regs(old_regs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Daniel R Thompson | 34 | 100.00% | 1 | 100.00% |
Total | 34 | 100.00% | 1 | 100.00% |
/*
* bad_mode handles the impossible case in the vectors. If you see one of
* these, then it's extremely serious, and could mean you have buggy hardware.
* It never returns, and never tries to sync. We hope that we can at least
* dump out some state information...
*/
asmlinkage void bad_mode(struct pt_regs *regs, int reason)
{
console_verbose();
pr_crit("Bad mode in %s handler detected\n", handler[reason]);
die("Oops - bad mode", regs, 0);
local_irq_disable();
panic("bad mode");
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 40 | 90.91% | 3 | 42.86% |
Russell King | 4 | 9.09% | 4 | 57.14% |
Total | 44 | 100.00% | 7 | 100.00% |
static int bad_syscall(int n, struct pt_regs *regs)
{
siginfo_t info;
if ((current->personality & PER_MASK) != PER_LINUX) {
send_sig(SIGSEGV, current, 1);
return regs->ARM_r0;
}
#ifdef CONFIG_DEBUG_USER
if (user_debug & UDBG_SYSCALL) {
pr_err("[%d] %s: obsolete system call %08x.\n",
task_pid_nr(current), current->comm, n);
dump_instr(KERN_ERR, regs);
}
#endif
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_ILLTRP;
info.si_addr = (void __user *)instruction_pointer(regs) -
(thumb_mode(regs) ? 2 : 4);
arm_notify_die("Oops - bad syscall", regs, &info, n, 0);
return regs->ARM_r0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds | 112 | 78.32% | 1 | 9.09% |
Russell King | 17 | 11.89% | 5 | 45.45% |
Richard Weinberger | 5 | 3.50% | 1 | 9.09% |
Nico Pitre | 4 | 2.80% | 1 | 9.09% |
Alexey Dobriyan | 3 | 2.10% | 1 | 9.09% |
Al Viro | 1 | 0.70% | 1 | 9.09% |
Christoph Hellwig | 1 | 0.70% | 1 | 9.09% |
Total | 143 | 100.00% | 11 | 100.00% |
static inline int
__do_cache_op(unsigned long start, unsigned long end)
{
int ret;
do {
unsigned long chunk = min(PAGE_SIZE, end - start);
if (fatal_signal_pending(current))
return 0;
ret = flush_cache_user_range(start, start + chunk);
if (ret)
return ret;
cond_resched();
start += chunk;
} while (start < end);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Will Deacon | 40 | 50.63% | 2 | 33.33% |
Russell King | 28 | 35.44% | 2 | 33.33% |
Jon Medhurst (Tixy) | 9 | 11.39% | 1 | 16.67% |
Vladimir Murzin | 2 | 2.53% | 1 | 16.67% |
Total | 79 | 100.00% | 6 | 100.00% |
static inline int
do_cache_op(unsigned long start, unsigned long end, int flags)
{
if (end < start || flags)
return -EINVAL;
if (!access_ok(VERIFY_READ, start, end - start))
return -EFAULT;
return __do_cache_op(start, end);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Russell King | 34 | 60.71% | 3 | 50.00% |
Will Deacon | 22 | 39.29% | 3 | 50.00% |
Total | 56 | 100.00% | 6 | 100.00% |
/*
* Handle all unrecognised system calls.
* 0x9f0000 - 0x9fffff are some more esoteric system calls
*/
#define NR(x) ((__ARM_NR_##x) - __ARM_NR_BASE)
asmlinkage int arm_syscall(int no, struct pt_regs *regs)
{
siginfo_t info;
if ((no >> 16) != (__ARM_NR_BASE>> 16))
return bad_syscall(no, regs);
switch (no & 0xffff) {
case 0: /* branch through 0 */
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = SEGV_MAPERR;
info.si_addr = NULL;
arm_notify_die("branch through zero", regs, &info, 0, 0);
return 0;
case NR(breakpoint): /* SWI BREAK_POINT */
regs->ARM_pc -= thumb_mode(regs) ? 2 : 4;
ptrace_break(current, regs);
return regs->ARM_r0;
/*
* Flush a region from virtual address 'r0' to virtual address 'r1'
* _exclusive_. There is no alignment requirement on either address;
* user space does not need to know the hardware cache layout.
*
* r2 contains flags. It should ALWAYS be passed as ZERO until it
* is defined to be something else. For now we ignore it, but may
* the fires of hell burn in your belly if you break this rule. ;)
*
* (at a later date, we may want to allow this call to not flush
* various aspects of the cache. Passing '0' will guarantee that
* everything necessary gets flushed to maintain consistency in
* the specified region).
*/
case NR(cacheflush):
return do_cache_op(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2);
case NR(usr26):
if (!(elf_hwcap & HWCAP_26BIT))
break;
regs->ARM_cpsr &= ~MODE32_BIT;
return regs->ARM_r0;
case NR(usr32):
if (!(elf_hwcap & HWCAP_26BIT))
break;
regs->ARM_cpsr |= MODE32_BIT;
return regs->ARM_r0;
case NR(set_tls):
set_tls(regs->ARM_r0);
return 0;
default:
/* Calls 9f00xx..9f07ff are defined to return -ENOSYS
if not implemented, rather than raising SIGILL. This
way the calling program can gracefully determine whether
a feature is supported. */
if ((no & 0xffff) <= 0x7ff)
return -ENOSYS;
break;
}
#ifdef CONFIG_DEBUG_USER
/*
* experience shows that these seem to indicate that
* something catastrophic has happened
*/
if (user_debug & UDBG_SYSCALL) {
pr_err("[%d] %s: arm syscall %d\n",
task_pid_nr(current), current->comm, no);
dump_instr("", regs);
if (user_mode(regs)) {
__show_regs(regs);
c_backtrace(frame_pointer(regs), processor_mode(regs));
}
}
#endif
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_ILLTRP;
info.si_addr = (void __user *)instruction_pointer(regs) -
(thumb_mode(regs) ? 2 : 4);
arm_notify_die("Oops - bad syscall(2)", regs, &info, no, 0);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 159 | 44.29% | 5 | 18.52% |
Linus Torvalds | 121 | 33.70% | 1 | 3.70% |
Russell King | 47 | 13.09% | 11 | 40.74% |
Nico Pitre | 19 | 5.29% | 4 | 14.81% |
Alexey Dobriyan | 3 | 0.84% | 1 | 3.70% |
Nikolay Borisov | 3 | 0.84% | 1 | 3.70% |
Nathan Lynch | 3 | 0.84% | 1 | 3.70% |
Christoph Hellwig | 2 | 0.56% | 1 | 3.70% |
Will Deacon | 1 | 0.28% | 1 | 3.70% |
Al Viro | 1 | 0.28% | 1 | 3.70% |
Total | 359 | 100.00% | 27 | 100.00% |
#ifdef CONFIG_TLS_REG_EMUL
/*
* We might be running on an ARMv6+ processor which should have the TLS
* register but for some reason we can't use it, or maybe an SMP system
* using a pre-ARMv6 processor (there are apparently a few prototypes like
* that in existence) and therefore access to that register must be
* emulated.
*/
static int get_tp_trap(struct pt_regs *regs, unsigned int instr)
{
int reg = (instr >> 12) & 15;
if (reg == 15)
return 1;
regs->uregs[reg] = current_thread_info()->tp_value[0];
regs->ARM_pc += 4;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nico Pitre | 56 | 94.92% | 1 | 50.00% |
André Hentschel | 3 | 5.08% | 1 | 50.00% |
Total | 59 | 100.00% | 2 | 100.00% |
static struct undef_hook arm_mrc_hook = {
.instr_mask = 0x0fff0fff,
.instr_val = 0x0e1d0f70,
.cpsr_mask = PSR_T_BIT,
.cpsr_val = 0,
.fn = get_tp_trap,
};
static int __init arm_mrc_hook_init(void)
{
register_undef_hook(&arm_mrc_hook);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nico Pitre | 18 | 100.00% | 1 | 100.00% |
Total | 18 | 100.00% | 1 | 100.00% |
late_initcall(arm_mrc_hook_init);
#endif
/*
* A data abort trap was taken, but we did not handle the instruction.
* Try to abort the user program, or panic if it was the kernel.
*/
asmlinkage void
baddataabort(int code, unsigned long instr, struct pt_regs *regs)
{
unsigned long addr = instruction_pointer(regs);
siginfo_t info;
#ifdef CONFIG_DEBUG_USER
if (user_debug & UDBG_BADABORT) {
pr_err("[%d] %s: bad data abort: code %d instr 0x%08lx\n",
task_pid_nr(current), current->comm, code, instr);
dump_instr(KERN_ERR, regs);
show_pte(current->mm, addr);
}
#endif
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_ILLOPC;
info.si_addr = (void __user *)addr;
arm_notify_die("unknown data abort code", regs, &info, instr, 0);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 99 | 82.50% | 4 | 36.36% |
Russell King | 16 | 13.33% | 4 | 36.36% |
Alexey Dobriyan | 3 | 2.50% | 1 | 9.09% |
Christoph Hellwig | 1 | 0.83% | 1 | 9.09% |
Al Viro | 1 | 0.83% | 1 | 9.09% |
Total | 120 | 100.00% | 11 | 100.00% |
void __readwrite_bug(const char *fn)
{
pr_err("%s called, but not implemented\n", fn);
BUG();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 18 | 90.00% | 2 | 50.00% |
Russell King | 2 | 10.00% | 2 | 50.00% |
Total | 20 | 100.00% | 4 | 100.00% |
EXPORT_SYMBOL(__readwrite_bug);
void __pte_error(const char *file, int line, pte_t pte)
{
pr_err("%s:%d: bad pte %08llx.\n", file, line, (long long)pte_val(pte));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 22 | 64.71% | 1 | 25.00% |
Russell King | 7 | 20.59% | 2 | 50.00% |
Will Deacon | 5 | 14.71% | 1 | 25.00% |
Total | 34 | 100.00% | 4 | 100.00% |
void __pmd_error(const char *file, int line, pmd_t pmd)
{
pr_err("%s:%d: bad pmd %08llx.\n", file, line, (long long)pmd_val(pmd));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 22 | 64.71% | 1 | 25.00% |
Russell King | 7 | 20.59% | 2 | 50.00% |
Will Deacon | 5 | 14.71% | 1 | 25.00% |
Total | 34 | 100.00% | 4 | 100.00% |
void __pgd_error(const char *file, int line, pgd_t pgd)
{
pr_err("%s:%d: bad pgd %08llx.\n", file, line, (long long)pgd_val(pgd));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 22 | 64.71% | 1 | 25.00% |
Russell King | 7 | 20.59% | 2 | 50.00% |
Will Deacon | 5 | 14.71% | 1 | 25.00% |
Total | 34 | 100.00% | 4 | 100.00% |
asmlinkage void __div0(void)
{
pr_err("Division by zero in kernel.\n");
dump_stack();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 14 | 87.50% | 2 | 50.00% |
Russell King | 2 | 12.50% | 2 | 50.00% |
Total | 16 | 100.00% | 4 | 100.00% |
EXPORT_SYMBOL(__div0);
void abort(void)
{
BUG();
/* if that doesn't kill us, halt */
panic("Oops failed to kill thread");
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 16 | 100.00% | 2 | 100.00% |
Total | 16 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(abort);
void __init trap_init(void)
{
return;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 6 | 66.67% | 1 | 50.00% |
Jason Wessel | 3 | 33.33% | 1 | 50.00% |
Total | 9 | 100.00% | 2 | 100.00% |
#ifdef CONFIG_KUSER_HELPERS
static void __init kuser_init(void *vectors)
{
extern char __kuser_helper_start[], __kuser_helper_end[];
int kuser_sz = __kuser_helper_end - __kuser_helper_start;
memcpy(vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
/*
* vectors + 0xfe0 = __kuser_get_tls
* vectors + 0xfe8 = hardware TLS instruction at 0xffff0fe8
*/
if (tls_emu || has_tls_reg)
memcpy(vectors + 0xfe0, vectors + 0xfe8, 4);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Russell King | 31 | 52.54% | 1 | 50.00% |
Tony Lindgren | 28 | 47.46% | 1 | 50.00% |
Total | 59 | 100.00% | 2 | 100.00% |
#else
static inline void __init kuser_init(void *vectors)
{
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Russell King | 10 | 90.91% | 1 | 50.00% |
Olof Johansson | 1 | 9.09% | 1 | 50.00% |
Total | 11 | 100.00% | 2 | 100.00% |
#endif
void __init early_trap_init(void *vectors_base)
{
#ifndef CONFIG_CPU_V7M
unsigned long vectors = (unsigned long)vectors_base;
extern char __stubs_start[], __stubs_end[];
extern char __vectors_start[], __vectors_end[];
unsigned i;
vectors_page = vectors_base;
/*
* Poison the vectors page with an undefined instruction. This
* instruction is chosen to be undefined for both ARM and Thumb
* ISAs. The Thumb version is an undefined instruction with a
* branch back to the undefined instruction.
*/
for (i = 0; i < PAGE_SIZE / sizeof(u32); i++)
((u32 *)vectors_base)[i] = 0xe7fddef1;
/*
* Copy the vectors, stubs and kuser helpers (in entry-armv.S)
* into the vector page, mapped at 0xffff0000, and ensure these
* are visible to the instruction stream.
*/
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
memcpy((void *)vectors + 0x1000, __stubs_start, __stubs_end - __stubs_start);
kuser_init(vectors_base);
flush_icache_range(vectors, vectors + PAGE_SIZE * 2);
#else /* ifndef CONFIG_CPU_V7M */
/*
* on V7-M there is no need to copy the vector table to a dedicated
* memory area. The address is configurable and so a table in the kernel
* image can be used.
*/
#endif
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Russell King | 92 | 69.17% | 7 | 46.67% |
Catalin Marinas | 18 | 13.53% | 2 | 13.33% |
Jason Wessel | 6 | 4.51% | 1 | 6.67% |
Linus Torvalds (pre-git) | 6 | 4.51% | 1 | 6.67% |
Hyok S. Choi | 5 | 3.76% | 1 | 6.67% |
Tony Lindgren | 3 | 2.26% | 1 | 6.67% |
Linus Torvalds | 2 | 1.50% | 1 | 6.67% |
Nico Pitre | 1 | 0.75% | 1 | 6.67% |
Total | 133 | 100.00% | 15 | 100.00% |
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Russell King | 1321 | 37.22% | 58 | 43.94% |
Linus Torvalds (pre-git) | 935 | 26.35% | 13 | 9.85% |
Linus Torvalds | 305 | 8.59% | 6 | 4.55% |
Rabin Vincent | 198 | 5.58% | 1 | 0.76% |
Nico Pitre | 141 | 3.97% | 6 | 4.55% |
Catalin Marinas | 117 | 3.30% | 4 | 3.03% |
Will Deacon | 97 | 2.73% | 6 | 4.55% |
Jon Medhurst (Tixy) | 87 | 2.45% | 2 | 1.52% |
Ben Dooks | 71 | 2.00% | 2 | 1.52% |
Simon Glass | 54 | 1.52% | 1 | 0.76% |
Daniel R Thompson | 38 | 1.07% | 1 | 0.76% |
Tony Lindgren | 34 | 0.96% | 1 | 0.76% |
Dan J Williams | 21 | 0.59% | 1 | 0.76% |
Alexey Dobriyan | 15 | 0.42% | 1 | 0.76% |
Al Viro | 13 | 0.37% | 3 | 2.27% |
Joe Perches | 10 | 0.28% | 1 | 0.76% |
Thomas Gleixner | 10 | 0.28% | 2 | 1.52% |
Jason Wessel | 9 | 0.25% | 1 | 0.76% |
Nikolay Borisov | 9 | 0.25% | 1 | 0.76% |
Ingo Molnar | 7 | 0.20% | 3 | 2.27% |
Christoph Hellwig | 6 | 0.17% | 1 | 0.76% |
Richard Weinberger | 5 | 0.14% | 1 | 0.76% |
Stephen Boyd | 5 | 0.14% | 1 | 0.76% |
Hyok S. Choi | 5 | 0.14% | 1 | 0.76% |
Taras Kondratiuk | 5 | 0.14% | 1 | 0.76% |
Andrew Morton | 5 | 0.14% | 1 | 0.76% |
Pavel Emelyanov | 5 | 0.14% | 1 | 0.76% |
Jamie Iles | 3 | 0.08% | 1 | 0.76% |
André Hentschel | 3 | 0.08% | 1 | 0.76% |
Marc Singer | 3 | 0.08% | 1 | 0.76% |
Nathan Lynch | 3 | 0.08% | 1 | 0.76% |
Rusty Russell | 2 | 0.06% | 1 | 0.76% |
Vladimir Murzin | 2 | 0.06% | 1 | 0.76% |
Simon Horman | 1 | 0.03% | 1 | 0.76% |
Arun Sharma | 1 | 0.03% | 1 | 0.76% |
Olof Johansson | 1 | 0.03% | 1 | 0.76% |
Geert Uytterhoeven | 1 | 0.03% | 1 | 0.76% |
David Howells | 1 | 0.03% | 1 | 0.76% |
Total | 3549 | 100.00% | 132 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.