2018-09-05 09:25:08 +03:00
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
# include <linux/sched.h>
# include <linux/signal.h>
# include <linux/kernel.h>
# include <linux/mm.h>
# include <linux/module.h>
# include <linux/user.h>
# include <linux/string.h>
# include <linux/linkage.h>
# include <linux/init.h>
# include <linux/ptrace.h>
# include <linux/kallsyms.h>
# include <linux/rtc.h>
# include <linux/uaccess.h>
2020-04-01 04:17:02 +03:00
# include <linux/kprobes.h>
2020-07-30 14:09:51 +03:00
# include <linux/kdebug.h>
# include <linux/sched/debug.h>
2018-09-05 09:25:08 +03:00
# include <asm/setup.h>
# include <asm/traps.h>
# include <asm/pgalloc.h>
# include <asm/siginfo.h>
# include <asm/mmu_context.h>
# ifdef CONFIG_CPU_HAS_FPU
# include <abi/fpu.h>
# endif
2020-07-30 14:09:51 +03:00
int show_unhandled_signals = 1 ;
2018-09-05 09:25:08 +03:00
/* Defined in entry.S */
asmlinkage void csky_trap ( void ) ;
asmlinkage void csky_systemcall ( void ) ;
asmlinkage void csky_cmpxchg ( void ) ;
asmlinkage void csky_get_tls ( void ) ;
asmlinkage void csky_irq ( void ) ;
asmlinkage void csky_tlbinvalidl ( void ) ;
asmlinkage void csky_tlbinvalids ( void ) ;
asmlinkage void csky_tlbmodified ( void ) ;
/* Defined in head.S */
asmlinkage void _start_smp_secondary ( void ) ;
void __init pre_trap_init ( void )
{
int i ;
mtcr ( " vbr " , vec_base ) ;
for ( i = 1 ; i < 128 ; i + + )
VEC_INIT ( i , csky_trap ) ;
}
void __init trap_init ( void )
{
VEC_INIT ( VEC_AUTOVEC , csky_irq ) ;
/* setup trap0 trap2 trap3 */
VEC_INIT ( VEC_TRAP0 , csky_systemcall ) ;
VEC_INIT ( VEC_TRAP2 , csky_cmpxchg ) ;
VEC_INIT ( VEC_TRAP3 , csky_get_tls ) ;
/* setup MMU TLB exception */
VEC_INIT ( VEC_TLBINVALIDL , csky_tlbinvalidl ) ;
VEC_INIT ( VEC_TLBINVALIDS , csky_tlbinvalids ) ;
VEC_INIT ( VEC_TLBMODIFIED , csky_tlbmodified ) ;
# ifdef CONFIG_CPU_HAS_FPU
init_fpu ( ) ;
# endif
# ifdef CONFIG_SMP
mtcr ( " cr<28, 0> " , virt_to_phys ( vec_base ) ) ;
VEC_INIT ( VEC_RESET , ( void * ) virt_to_phys ( _start_smp_secondary ) ) ;
# endif
}
2020-07-30 14:09:51 +03:00
static DEFINE_SPINLOCK ( die_lock ) ;
void die ( struct pt_regs * regs , const char * str )
2018-09-05 09:25:08 +03:00
{
2020-07-30 14:09:51 +03:00
static int die_counter ;
int ret ;
2018-09-05 09:25:08 +03:00
2020-07-30 14:09:51 +03:00
oops_enter ( ) ;
spin_lock_irq ( & die_lock ) ;
2018-09-05 09:25:08 +03:00
console_verbose ( ) ;
2020-07-30 14:09:51 +03:00
bust_spinlocks ( 1 ) ;
pr_emerg ( " %s [#%d] \n " , str , + + die_counter ) ;
print_modules ( ) ;
2018-09-05 09:25:08 +03:00
show_regs ( regs ) ;
2020-07-30 14:09:51 +03:00
show_stack ( current , ( unsigned long * ) regs - > regs [ 4 ] , KERN_INFO ) ;
ret = notify_die ( DIE_OOPS , str , regs , 0 , trap_no ( regs ) , SIGSEGV ) ;
bust_spinlocks ( 0 ) ;
2018-09-05 09:25:08 +03:00
add_taint ( TAINT_DIE , LOCKDEP_NOW_UNRELIABLE ) ;
2020-07-30 14:09:51 +03:00
spin_unlock_irq ( & die_lock ) ;
oops_exit ( ) ;
if ( in_interrupt ( ) )
panic ( " Fatal exception in interrupt " ) ;
if ( panic_on_oops )
panic ( " Fatal exception " ) ;
if ( ret ! = NOTIFY_STOP )
do_exit ( SIGSEGV ) ;
2018-09-05 09:25:08 +03:00
}
2020-07-30 14:09:51 +03:00
void do_trap ( struct pt_regs * regs , int signo , int code , unsigned long addr )
2018-09-05 09:25:08 +03:00
{
2020-07-30 14:09:51 +03:00
struct task_struct * tsk = current ;
2018-09-05 09:25:08 +03:00
2020-07-30 14:09:51 +03:00
if ( show_unhandled_signals & & unhandled_signal ( tsk , signo )
& & printk_ratelimit ( ) ) {
pr_info ( " %s[%d]: unhandled signal %d code 0x%x at 0x%08lx " ,
tsk - > comm , task_pid_nr ( tsk ) , signo , code , addr ) ;
print_vma_addr ( KERN_CONT " in " , instruction_pointer ( regs ) ) ;
pr_cont ( " \n " ) ;
show_regs ( regs ) ;
2018-09-05 09:25:08 +03:00
}
2020-07-30 14:09:51 +03:00
force_sig_fault ( signo , code , ( void __user * ) addr ) ;
}
2018-09-05 09:25:08 +03:00
2020-07-30 14:09:51 +03:00
static void do_trap_error ( struct pt_regs * regs , int signo , int code ,
unsigned long addr , const char * str )
{
current - > thread . trap_no = trap_no ( regs ) ;
2018-09-05 09:25:08 +03:00
2020-07-30 14:09:51 +03:00
if ( user_mode ( regs ) ) {
do_trap ( regs , signo , code , addr ) ;
} else {
if ( ! fixup_exception ( regs ) )
die ( regs , str ) ;
}
2018-09-05 09:25:08 +03:00
}
2020-07-30 14:09:51 +03:00
# define DO_ERROR_INFO(name, signo, code, str) \
asmlinkage __visible void name ( struct pt_regs * regs ) \
{ \
do_trap_error ( regs , signo , code , regs - > pc , " Oops - " str ) ; \
}
2018-09-05 09:25:08 +03:00
2020-07-30 14:09:51 +03:00
DO_ERROR_INFO ( do_trap_unknown ,
SIGILL , ILL_ILLTRP , " unknown exception " ) ;
DO_ERROR_INFO ( do_trap_zdiv ,
SIGFPE , FPE_INTDIV , " error zero div exception " ) ;
DO_ERROR_INFO ( do_trap_buserr ,
SIGSEGV , ILL_ILLADR , " error bus error exception " ) ;
2018-09-05 09:25:08 +03:00
2020-07-30 14:09:51 +03:00
asmlinkage void do_trap_misaligned ( struct pt_regs * regs )
{
# ifdef CONFIG_CPU_NEED_SOFTALIGN
csky_alignment ( regs ) ;
# else
current - > thread . trap_no = trap_no ( regs ) ;
do_trap_error ( regs , SIGBUS , BUS_ADRALN , regs - > pc ,
" Oops - load/store address misaligned " ) ;
# endif
}
asmlinkage void do_trap_bkpt ( struct pt_regs * regs )
{
2020-04-01 04:17:02 +03:00
# ifdef CONFIG_KPROBES
2020-07-30 14:09:51 +03:00
if ( kprobe_single_step_handler ( regs ) )
return ;
2020-04-02 14:52:27 +03:00
# endif
# ifdef CONFIG_UPROBES
2020-07-30 14:09:51 +03:00
if ( uprobe_single_step_handler ( regs ) )
return ;
2020-04-01 04:17:02 +03:00
# endif
2020-07-30 14:09:51 +03:00
if ( user_mode ( regs ) ) {
send_sig ( SIGTRAP , current , 0 ) ;
return ;
}
do_trap_error ( regs , SIGILL , ILL_ILLTRP , regs - > pc ,
" Oops - illegal trap exception " ) ;
}
asmlinkage void do_trap_illinsn ( struct pt_regs * regs )
{
current - > thread . trap_no = trap_no ( regs ) ;
2020-04-01 04:17:02 +03:00
# ifdef CONFIG_KPROBES
2020-07-30 14:09:51 +03:00
if ( kprobe_breakpoint_handler ( regs ) )
return ;
2020-04-02 14:52:27 +03:00
# endif
# ifdef CONFIG_UPROBES
2020-07-30 14:09:51 +03:00
if ( uprobe_breakpoint_handler ( regs ) )
return ;
2020-04-01 04:17:02 +03:00
# endif
2018-09-05 09:25:08 +03:00
# ifndef CONFIG_CPU_NO_USER_BKPT
2020-07-30 14:09:51 +03:00
if ( * ( uint16_t * ) instruction_pointer ( regs ) ! = USR_BKPT ) {
send_sig ( SIGTRAP , current , 0 ) ;
return ;
}
2018-09-05 09:25:08 +03:00
# endif
2020-07-30 14:09:51 +03:00
do_trap_error ( regs , SIGILL , ILL_ILLOPC , regs - > pc ,
" Oops - illegal instruction exception " ) ;
}
asmlinkage void do_trap_fpe ( struct pt_regs * regs )
{
# ifdef CONFIG_CPU_HAS_FP
return fpu_fpe ( regs ) ;
# else
do_trap_error ( regs , SIGILL , ILL_ILLOPC , regs - > pc ,
" Oops - fpu instruction exception " ) ;
# endif
}
asmlinkage void do_trap_priv ( struct pt_regs * regs )
{
# ifdef CONFIG_CPU_HAS_FP
if ( user_mode ( regs ) & & fpu_libc_helper ( regs ) )
return ;
# endif
do_trap_error ( regs , SIGILL , ILL_PRVOPC , regs - > pc ,
" Oops - illegal privileged exception " ) ;
}
asmlinkage void trap_c ( struct pt_regs * regs )
{
switch ( trap_no ( regs ) ) {
case VEC_ZERODIV :
do_trap_zdiv ( regs ) ;
break ;
case VEC_TRACE :
do_trap_bkpt ( regs ) ;
break ;
case VEC_ILLEGAL :
do_trap_illinsn ( regs ) ;
break ;
2018-09-05 09:25:08 +03:00
case VEC_TRAP1 :
case VEC_BREAKPOINT :
2020-07-30 14:09:51 +03:00
do_trap_bkpt ( regs ) ;
2018-09-05 09:25:08 +03:00
break ;
case VEC_ACCESS :
2020-07-30 14:09:51 +03:00
do_trap_buserr ( regs ) ;
break ;
2018-09-05 09:25:08 +03:00
case VEC_ALIGN :
2020-07-30 14:09:51 +03:00
do_trap_misaligned ( regs ) ;
break ;
2018-09-05 09:25:08 +03:00
case VEC_FPE :
2020-07-30 14:09:51 +03:00
do_trap_fpe ( regs ) ;
break ;
2018-09-05 09:25:08 +03:00
case VEC_PRIV :
2020-07-30 14:09:51 +03:00
do_trap_priv ( regs ) ;
break ;
2018-09-05 09:25:08 +03:00
default :
2020-07-30 14:09:51 +03:00
do_trap_unknown ( regs ) ;
2018-09-05 09:25:08 +03:00
break ;
}
}