Commit bb130ab0 authored by Philippe Gerum's avatar Philippe Gerum

ARM: ipipe: route traps to co-kernel

parent a3f9c6d4
......@@ -74,6 +74,18 @@ unsigned __ipipe_processor_id(void);
#define IPIPE_TRAP_MAYDAY 0 /* Internal recovery trap */
/* ARM traps */
#define IPIPE_TRAP_ACCESS 1 /* Data or instruction access exception */
#define IPIPE_TRAP_SECTION 2 /* Section fault */
#define IPIPE_TRAP_DABT 3 /* Generic data abort */
#define IPIPE_TRAP_UNKNOWN 4 /* Unknown exception */
#define IPIPE_TRAP_BREAK 5 /* Instruction breakpoint */
#define IPIPE_TRAP_FPU 6 /* Floating point exception */
#define IPIPE_TRAP_VFP 7 /* VFP floating point exception */
#define IPIPE_TRAP_UNDEFINSTR 8 /* Undefined instruction */
#define IPIPE_TRAP_ALIGNMENT 9 /* Unaligned access exception */
#define IPIPE_NR_FAULTS 10
#endif /* CONFIG_IPIPE */
#endif /* __ASM_ARM_IPIPE_BASE_H */
......@@ -286,6 +286,13 @@ __und_svc:
svc_entry
#endif
#ifdef CONFIG_IPIPE
mov r0, #7 @ r0 = IPIPE_TRAP_UNDEFINSTR
mov r1, sp @ r1 = &regs
bl __ipipe_notify_trap @ branch to trap handler
cmp r0, #0
bne __und_svc_finish
#endif /* CONFIG_IPIPE */
@
@ call emulation code, which returns using r9 if it has emulated
@ the instruction, or the more conventional lr if we are to treat
......@@ -507,6 +514,15 @@ ENDPROC(__irq_usr)
__und_usr:
usr_entry uaccess=0
#ifdef CONFIG_IPIPE
mov r0, #7 @ r0 = IPIPE_TRAP_UNDEFINSTR
mov r1, sp @ r1 = &regs
bl __ipipe_notify_trap @ branch to trap handler
cmp r0, #0
bne ret_from_exception
uaccess_enable ip
#endif /* CONFIG_IPIPE */
mov r2, r4
mov r3, r5
......
......@@ -216,6 +216,10 @@ void ptrace_break(struct task_struct *tsk, struct pt_regs *regs)
static int break_trap(struct pt_regs *regs, unsigned int instr)
{
if (__ipipe_report_trap(IPIPE_TRAP_BREAK,regs))
return 0;
ptrace_break(current, regs);
return 0;
}
......
......@@ -528,6 +528,9 @@ asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
*/
asmlinkage void bad_mode(struct pt_regs *regs, int reason)
{
if (__ipipe_report_trap(IPIPE_TRAP_UNKNOWN,regs))
return;
console_verbose();
pr_crit("Bad mode in %s handler detected\n", handler[reason]);
......
......@@ -14,6 +14,7 @@
#include <linux/moduleparam.h>
#include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/ipipe.h>
#include <linux/sched/debug.h>
#include <linux/errno.h>
#include <linux/string.h>
......@@ -781,7 +782,10 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
int thumb2_32b = 0;
if (interrupts_enabled(regs))
local_irq_enable();
hard_local_irq_enable();
if (__ipipe_report_trap(IPIPE_TRAP_ALIGNMENT,regs))
return 0;
instrptr = instruction_pointer(regs);
......@@ -970,7 +974,7 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
* entry-common.S) and disable the alignment trap only if
* there is no work pending for this thread.
*/
raw_local_irq_disable();
hard_local_irq_disable();
if (!(current_thread_info()->flags & _TIF_WORK_MASK))
set_cr(cr_no_alignment);
}
......
......@@ -30,6 +30,39 @@
#ifdef CONFIG_MMU
#ifdef CONFIG_IPIPE
static inline unsigned long ipipe_fault_entry(void)
{
unsigned long flags;
int s;
flags = hard_local_irq_save();
s = __test_and_set_bit(IPIPE_STALL_FLAG, &__ipipe_root_status);
hard_local_irq_enable();
return arch_mangle_irq_bits(s, flags);
}
static inline void ipipe_fault_exit(unsigned long x)
{
if (!arch_demangle_irq_bits(&x))
local_irq_enable();
else
hard_local_irq_restore(x);
}
#else
static inline unsigned long ipipe_fault_entry(void)
{
return 0;
}
static inline void ipipe_fault_exit(unsigned long x) { }
#endif
#ifdef CONFIG_KPROBES
static inline int notify_page_fault(struct pt_regs *regs, unsigned int fsr)
{
......@@ -267,10 +300,16 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
int sig, code;
vm_fault_t fault;
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
unsigned long irqflags;
if (notify_page_fault(regs, fsr))
if (__ipipe_report_trap(IPIPE_TRAP_ACCESS, regs))
return 0;
irqflags = ipipe_fault_entry();
if (notify_page_fault(regs, fsr))
goto out;
tsk = current;
mm = tsk->mm;
......@@ -323,7 +362,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
if (!user_mode(regs))
goto no_context;
return 0;
goto out;
}
/*
......@@ -358,7 +397,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
* Handle the "normal" case first - VM_FAULT_MAJOR
*/
if (likely(!(fault & (VM_FAULT_ERROR | VM_FAULT_BADMAP | VM_FAULT_BADACCESS))))
return 0;
goto out;
/*
* If we are in kernel mode at this point, we
......@@ -374,7 +413,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
* got oom-killed)
*/
pagefault_out_of_memory();
return 0;
goto out;
}
if (fault & VM_FAULT_SIGBUS) {
......@@ -395,10 +434,13 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
}
__do_user_fault(tsk, addr, fsr, sig, code, regs);
return 0;
goto out;
no_context:
__do_kernel_fault(mm, addr, fsr, regs);
out:
ipipe_fault_exit(irqflags);
return 0;
}
#else /* CONFIG_MMU */
......@@ -431,11 +473,14 @@ static int __kprobes
do_translation_fault(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
unsigned long irqflags;
unsigned int index;
pgd_t *pgd, *pgd_k;
pud_t *pud, *pud_k;
pmd_t *pmd, *pmd_k;
IPIPE_BUG_ON(!hard_irqs_disabled());
if (addr < TASK_SIZE)
return do_page_fault(addr, fsr, regs);
......@@ -483,10 +528,19 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
goto bad_area;
copy_pmd(pmd, pmd_k);
return 0;
bad_area:
if (__ipipe_report_trap(IPIPE_TRAP_ACCESS, regs))
return 0;
irqflags = ipipe_fault_entry();
do_bad_area(addr, fsr, regs);
ipipe_fault_exit(irqflags);
return 0;
}
#else /* CONFIG_MMU */
......@@ -506,7 +560,17 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
static int
do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
unsigned long irqflags;
if (__ipipe_report_trap(IPIPE_TRAP_SECTION, regs))
return 0;
irqflags = ipipe_fault_entry();
do_bad_area(addr, fsr, regs);
ipipe_fault_exit(irqflags);
return 0;
}
#endif /* CONFIG_ARM_LPAE */
......@@ -517,6 +581,9 @@ do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
static int
do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
if (__ipipe_report_trap(IPIPE_TRAP_DABT,regs))
return 0;
return 1;
}
......@@ -554,11 +621,17 @@ asmlinkage void
do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
const struct fsr_info *inf = fsr_info + fsr_fs(fsr);
unsigned long irqflags;
struct siginfo info;
if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))
return;
if (__ipipe_report_trap(IPIPE_TRAP_UNKNOWN, regs))
return;
irqflags = ipipe_fault_entry();
pr_alert("Unhandled fault: %s (0x%03x) at 0x%08lx\n",
inf->name, fsr, addr);
show_pte(current->mm, addr);
......@@ -569,6 +642,8 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
info.si_code = inf->code;
info.si_addr = (void __user *)addr;
arm_notify_die("", regs, &info, fsr, 0);
ipipe_fault_exit(irqflags);
}
void __init
......@@ -588,11 +663,17 @@ asmlinkage void
do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
{
const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr);
unsigned long irqflags;
struct siginfo info;
if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
return;
if (__ipipe_report_trap(IPIPE_TRAP_UNKNOWN, regs))
return;
irqflags = ipipe_fault_entry();
pr_alert("Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n",
inf->name, ifsr, addr);
......@@ -602,6 +683,8 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
info.si_code = inf->code;
info.si_addr = (void __user *)addr;
arm_notify_die("", regs, &info, ifsr, 0);
ipipe_fault_exit(irqflags);
}
/*
......
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