2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2013-01-18 15:12:18 +05:30
/*
* Traps / Non - MMU Exception handling for ARC
*
* Copyright ( C ) 2004 , 2007 - 2010 , 2011 - 2012 Synopsys , Inc . ( www . synopsys . com )
*
2013-01-23 16:30:36 +05:30
* vineetg : May 2011
* - user - space unaligned access emulation
*
2013-01-18 15:12:18 +05:30
* Rahul Trivedi : Codito Technologies 2004
*/
2017-02-08 18:51:30 +01:00
# include <linux/sched/signal.h>
2013-01-18 15:12:18 +05:30
# include <linux/kdebug.h>
# include <linux/uaccess.h>
2013-03-06 16:53:44 +05:30
# include <linux/ptrace.h>
# include <linux/kprobes.h>
# include <linux/kgdb.h>
2013-01-18 15:12:18 +05:30
# include <asm/setup.h>
2013-01-23 16:30:36 +05:30
# include <asm/unaligned.h>
2013-04-09 11:50:45 +02:00
# include <asm/kprobes.h>
2013-01-18 15:12:18 +05:30
2013-06-12 15:13:40 +05:30
void die ( const char * str , struct pt_regs * regs , unsigned long address )
2013-01-18 15:12:18 +05:30
{
2013-06-12 15:13:40 +05:30
show_kernel_fault_diag ( str , regs , address ) ;
2013-01-18 15:12:18 +05:30
/* DEAD END */
__asm__ ( " flag 1 " ) ;
}
/*
* Helper called for bulk of exceptions NOT needing specific handling
* - for user faults enqueues requested signal
* - for kernel , chk if due to copy_ ( to | from ) _user , otherwise die ( )
*/
2013-06-12 15:13:40 +05:30
static noinline int
2018-04-19 19:20:58 -05:00
unhandled_exception ( const char * str , struct pt_regs * regs ,
int signo , int si_code , void __user * addr )
2013-01-18 15:12:18 +05:30
{
if ( user_mode ( regs ) ) {
struct task_struct * tsk = current ;
2018-04-19 19:20:58 -05:00
tsk - > thread . fault_address = ( __force unsigned int ) addr ;
2013-01-18 15:12:18 +05:30
2019-05-23 11:04:24 -05:00
force_sig_fault ( signo , si_code , addr ) ;
2013-01-18 15:12:18 +05:30
} else {
/* If not due to copy_(to|from)_user, we are doomed */
if ( fixup_exception ( regs ) )
return 0 ;
2018-04-19 19:20:58 -05:00
die ( str , regs , ( unsigned long ) addr ) ;
2013-01-18 15:12:18 +05:30
}
return 1 ;
}
# define DO_ERROR_INFO(signr, str, name, sicode) \
2013-06-12 15:13:40 +05:30
int name ( unsigned long address , struct pt_regs * regs ) \
2018-04-19 19:20:58 -05:00
{ \
return unhandled_exception ( str , regs , signr , sicode , \
( void __user * ) address ) ; \
2013-01-18 15:12:18 +05:30
}
/*
* Entry points for exceptions NOT needing specific handling
*/
DO_ERROR_INFO ( SIGILL , " Priv Op/Disabled Extn " , do_privilege_fault , ILL_PRVOPC )
DO_ERROR_INFO ( SIGILL , " Invalid Extn Insn " , do_extension_fault , ILL_ILLOPC )
DO_ERROR_INFO ( SIGILL , " Illegal Insn (or Seq) " , insterror_is_error , ILL_ILLOPC )
2017-06-13 17:03:45 +03:00
DO_ERROR_INFO ( SIGBUS , " Invalid Mem Access " , __weak do_memory_error , BUS_ADRERR )
2013-01-18 15:12:18 +05:30
DO_ERROR_INFO ( SIGTRAP , " Breakpoint Set " , trap_is_brkpt , TRAP_BRKPT )
2013-04-04 14:37:52 +05:30
DO_ERROR_INFO ( SIGBUS , " Misaligned Access " , do_misaligned_error , BUS_ADRALN )
2017-12-20 12:37:54 -08:00
DO_ERROR_INFO ( SIGSEGV , " gcc generated __builtin_trap " , do_trap5_error , 0 )
2013-01-18 15:12:18 +05:30
2013-01-23 16:30:36 +05:30
/*
* Entry Point for Misaligned Data access Exception , for emulating in software
*/
2013-06-12 15:13:40 +05:30
int do_misaligned_access ( unsigned long address , struct pt_regs * regs ,
struct callee_regs * cregs )
2013-01-23 16:30:36 +05:30
{
2013-09-18 18:08:01 +05:30
/* If emulation not enabled, or failed, kill the task */
2013-06-12 15:13:40 +05:30
if ( misaligned_fixup ( address , regs , cregs ) ! = 0 )
return do_misaligned_error ( address , regs ) ;
2013-04-04 14:37:52 +05:30
2013-01-23 16:30:36 +05:30
return 0 ;
}
2013-01-18 15:12:18 +05:30
/*
* Entry point for miscll errors such as Nested Exceptions
* - Duplicate TLB entry is handled seperately though
*/
2013-06-12 15:13:40 +05:30
void do_machine_check_fault ( unsigned long address , struct pt_regs * regs )
2013-01-18 15:12:18 +05:30
{
2017-08-29 10:14:20 +01:00
die ( " Unhandled Machine Check Exception " , regs , address ) ;
2013-01-18 15:12:18 +05:30
}
2013-01-22 17:03:59 +05:30
2013-01-18 15:12:18 +05:30
/*
* Entry point for traps induced by ARCompact TRAP_S < n > insn
* This is same family as TRAP0 / SWI insn ( use the same vector ) .
* The only difference being SWI insn take no operand , while TRAP_S does
* which reflects in ECR Reg as 8 bit param .
* Thus TRAP_S < n > can be used for specific purpose
* - 1 used for software breakpointing ( gdb )
* - 2 used by kprobes
2017-12-20 12:37:54 -08:00
* - 5 __builtin_trap ( ) generated by gcc ( 2018.03 onwards ) for toggle such as
* - fno - isolate - erroneous - paths - dereference
2013-01-18 15:12:18 +05:30
*/
2013-06-12 15:13:40 +05:30
void do_non_swi_trap ( unsigned long address , struct pt_regs * regs )
2013-01-18 15:12:18 +05:30
{
2013-06-12 15:13:40 +05:30
unsigned int param = regs - > ecr_param ;
2013-01-18 15:12:18 +05:30
switch ( param ) {
case 1 :
2013-06-12 15:13:40 +05:30
trap_is_brkpt ( address , regs ) ;
2013-01-18 15:12:18 +05:30
break ;
2013-01-22 17:03:59 +05:30
case 2 :
2013-06-12 15:13:40 +05:30
trap_is_kprobe ( address , regs ) ;
2013-01-22 17:03:59 +05:30
break ;
2013-01-18 15:12:24 +05:30
case 3 :
case 4 :
2013-06-12 15:13:40 +05:30
kgdb_trap ( regs ) ;
2013-01-18 15:12:24 +05:30
break ;
2017-12-20 12:37:54 -08:00
case 5 :
do_trap5_error ( address , regs ) ;
break ;
2013-01-18 15:12:18 +05:30
default :
break ;
}
}
/*
* Entry point for Instruction Error Exception
2013-01-22 17:03:59 +05:30
* - For a corner case , ARC kprobes implementation resorts to using
* this exception , hence the check
2013-01-18 15:12:18 +05:30
*/
2013-06-12 15:13:40 +05:30
void do_insterror_or_kprobe ( unsigned long address , struct pt_regs * regs )
2013-01-18 15:12:18 +05:30
{
2013-06-12 15:13:40 +05:30
int rc ;
2013-01-22 17:03:59 +05:30
/* Check if this exception is caused by kprobes */
2013-06-12 15:13:40 +05:30
rc = notify_die ( DIE_IERR , " kprobe_ierr " , regs , address , 0 , SIGILL ) ;
if ( rc = = NOTIFY_STOP )
2013-01-22 17:03:59 +05:30
return ;
2013-06-12 15:13:40 +05:30
insterror_is_error ( address , regs ) ;
2013-01-18 15:12:18 +05:30
}
2017-12-08 08:45:57 -08:00
/*
* abort ( ) call generated by older gcc for __builtin_trap ( )
*/
void abort ( void )
{
__asm__ __volatile__ ( " trap_s 5 \n " ) ;
}