2011-01-15 13:20:01 +03:00
/*
* linux / arch / unicore32 / kernel / signal . c
*
* Code specific to PKUnity SoC and UniCore ISA
*
* Copyright ( C ) 2001 - 2010 GUAN Xue - tao
*
* 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 .
*/
# include <linux/errno.h>
# include <linux/signal.h>
# include <linux/personality.h>
# include <linux/uaccess.h>
# include <linux/tracehook.h>
# include <linux/elf.h>
# include <linux/unistd.h>
# include <asm/cacheflush.h>
# include <asm/ucontext.h>
/*
* For UniCore syscalls , we encode the syscall number into the instruction .
*/
# define SWI_SYS_SIGRETURN (0xff000000) /* error number for new abi */
# define SWI_SYS_RT_SIGRETURN (0xff000000 | (__NR_rt_sigreturn))
# define SWI_SYS_RESTART (0xff000000 | (__NR_restart_syscall))
# define KERN_SIGRETURN_CODE (KUSER_VECPAGE_BASE + 0x00000500)
# define KERN_RESTART_CODE (KERN_SIGRETURN_CODE + sizeof(sigreturn_codes))
const unsigned long sigreturn_codes [ 3 ] = {
SWI_SYS_SIGRETURN , SWI_SYS_RT_SIGRETURN ,
} ;
const unsigned long syscall_restart_code [ 2 ] = {
SWI_SYS_RESTART , /* swi __NR_restart_syscall */
0x69efc004 , /* ldr pc, [sp], #4 */
} ;
/*
* Do a signal return ; undo the signal stack . These are aligned to 64 - bit .
*/
struct sigframe {
struct ucontext uc ;
unsigned long retcode [ 2 ] ;
} ;
struct rt_sigframe {
struct siginfo info ;
struct sigframe sig ;
} ;
static int restore_sigframe ( struct pt_regs * regs , struct sigframe __user * sf )
{
sigset_t set ;
int err ;
err = __copy_from_user ( & set , & sf - > uc . uc_sigmask , sizeof ( set ) ) ;
2012-04-27 21:58:59 +04:00
if ( err = = 0 )
2011-08-11 17:57:06 +04:00
set_current_blocked ( & set ) ;
2011-01-15 13:20:01 +03:00
err | = __get_user ( regs - > UCreg_00 , & sf - > uc . uc_mcontext . regs . UCreg_00 ) ;
err | = __get_user ( regs - > UCreg_01 , & sf - > uc . uc_mcontext . regs . UCreg_01 ) ;
err | = __get_user ( regs - > UCreg_02 , & sf - > uc . uc_mcontext . regs . UCreg_02 ) ;
err | = __get_user ( regs - > UCreg_03 , & sf - > uc . uc_mcontext . regs . UCreg_03 ) ;
err | = __get_user ( regs - > UCreg_04 , & sf - > uc . uc_mcontext . regs . UCreg_04 ) ;
err | = __get_user ( regs - > UCreg_05 , & sf - > uc . uc_mcontext . regs . UCreg_05 ) ;
err | = __get_user ( regs - > UCreg_06 , & sf - > uc . uc_mcontext . regs . UCreg_06 ) ;
err | = __get_user ( regs - > UCreg_07 , & sf - > uc . uc_mcontext . regs . UCreg_07 ) ;
err | = __get_user ( regs - > UCreg_08 , & sf - > uc . uc_mcontext . regs . UCreg_08 ) ;
err | = __get_user ( regs - > UCreg_09 , & sf - > uc . uc_mcontext . regs . UCreg_09 ) ;
err | = __get_user ( regs - > UCreg_10 , & sf - > uc . uc_mcontext . regs . UCreg_10 ) ;
err | = __get_user ( regs - > UCreg_11 , & sf - > uc . uc_mcontext . regs . UCreg_11 ) ;
err | = __get_user ( regs - > UCreg_12 , & sf - > uc . uc_mcontext . regs . UCreg_12 ) ;
err | = __get_user ( regs - > UCreg_13 , & sf - > uc . uc_mcontext . regs . UCreg_13 ) ;
err | = __get_user ( regs - > UCreg_14 , & sf - > uc . uc_mcontext . regs . UCreg_14 ) ;
err | = __get_user ( regs - > UCreg_15 , & sf - > uc . uc_mcontext . regs . UCreg_15 ) ;
err | = __get_user ( regs - > UCreg_16 , & sf - > uc . uc_mcontext . regs . UCreg_16 ) ;
err | = __get_user ( regs - > UCreg_17 , & sf - > uc . uc_mcontext . regs . UCreg_17 ) ;
err | = __get_user ( regs - > UCreg_18 , & sf - > uc . uc_mcontext . regs . UCreg_18 ) ;
err | = __get_user ( regs - > UCreg_19 , & sf - > uc . uc_mcontext . regs . UCreg_19 ) ;
err | = __get_user ( regs - > UCreg_20 , & sf - > uc . uc_mcontext . regs . UCreg_20 ) ;
err | = __get_user ( regs - > UCreg_21 , & sf - > uc . uc_mcontext . regs . UCreg_21 ) ;
err | = __get_user ( regs - > UCreg_22 , & sf - > uc . uc_mcontext . regs . UCreg_22 ) ;
err | = __get_user ( regs - > UCreg_23 , & sf - > uc . uc_mcontext . regs . UCreg_23 ) ;
err | = __get_user ( regs - > UCreg_24 , & sf - > uc . uc_mcontext . regs . UCreg_24 ) ;
err | = __get_user ( regs - > UCreg_25 , & sf - > uc . uc_mcontext . regs . UCreg_25 ) ;
err | = __get_user ( regs - > UCreg_26 , & sf - > uc . uc_mcontext . regs . UCreg_26 ) ;
err | = __get_user ( regs - > UCreg_fp , & sf - > uc . uc_mcontext . regs . UCreg_fp ) ;
err | = __get_user ( regs - > UCreg_ip , & sf - > uc . uc_mcontext . regs . UCreg_ip ) ;
err | = __get_user ( regs - > UCreg_sp , & sf - > uc . uc_mcontext . regs . UCreg_sp ) ;
err | = __get_user ( regs - > UCreg_lr , & sf - > uc . uc_mcontext . regs . UCreg_lr ) ;
err | = __get_user ( regs - > UCreg_pc , & sf - > uc . uc_mcontext . regs . UCreg_pc ) ;
err | = __get_user ( regs - > UCreg_asr , & sf - > uc . uc_mcontext . regs . UCreg_asr ) ;
err | = ! valid_user_regs ( regs ) ;
return err ;
}
asmlinkage int __sys_rt_sigreturn ( struct pt_regs * regs )
{
struct rt_sigframe __user * frame ;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info ( ) - > restart_block . fn = do_no_restart_syscall ;
/*
* Since we stacked the signal on a 64 - bit boundary ,
* then ' sp ' should be word aligned here . If it ' s
* not , then the user is trying to mess with us .
*/
if ( regs - > UCreg_sp & 7 )
goto badframe ;
frame = ( struct rt_sigframe __user * ) regs - > UCreg_sp ;
if ( ! access_ok ( VERIFY_READ , frame , sizeof ( * frame ) ) )
goto badframe ;
if ( restore_sigframe ( regs , & frame - > sig ) )
goto badframe ;
2012-12-23 12:52:33 +04:00
if ( restore_altstack ( & frame - > sig . uc . uc_stack ) )
2011-01-15 13:20:01 +03:00
goto badframe ;
return regs - > UCreg_00 ;
badframe :
force_sig ( SIGSEGV , current ) ;
return 0 ;
}
static int setup_sigframe ( struct sigframe __user * sf , struct pt_regs * regs ,
sigset_t * set )
{
int err = 0 ;
err | = __put_user ( regs - > UCreg_00 , & sf - > uc . uc_mcontext . regs . UCreg_00 ) ;
err | = __put_user ( regs - > UCreg_01 , & sf - > uc . uc_mcontext . regs . UCreg_01 ) ;
err | = __put_user ( regs - > UCreg_02 , & sf - > uc . uc_mcontext . regs . UCreg_02 ) ;
err | = __put_user ( regs - > UCreg_03 , & sf - > uc . uc_mcontext . regs . UCreg_03 ) ;
err | = __put_user ( regs - > UCreg_04 , & sf - > uc . uc_mcontext . regs . UCreg_04 ) ;
err | = __put_user ( regs - > UCreg_05 , & sf - > uc . uc_mcontext . regs . UCreg_05 ) ;
err | = __put_user ( regs - > UCreg_06 , & sf - > uc . uc_mcontext . regs . UCreg_06 ) ;
err | = __put_user ( regs - > UCreg_07 , & sf - > uc . uc_mcontext . regs . UCreg_07 ) ;
err | = __put_user ( regs - > UCreg_08 , & sf - > uc . uc_mcontext . regs . UCreg_08 ) ;
err | = __put_user ( regs - > UCreg_09 , & sf - > uc . uc_mcontext . regs . UCreg_09 ) ;
err | = __put_user ( regs - > UCreg_10 , & sf - > uc . uc_mcontext . regs . UCreg_10 ) ;
err | = __put_user ( regs - > UCreg_11 , & sf - > uc . uc_mcontext . regs . UCreg_11 ) ;
err | = __put_user ( regs - > UCreg_12 , & sf - > uc . uc_mcontext . regs . UCreg_12 ) ;
err | = __put_user ( regs - > UCreg_13 , & sf - > uc . uc_mcontext . regs . UCreg_13 ) ;
err | = __put_user ( regs - > UCreg_14 , & sf - > uc . uc_mcontext . regs . UCreg_14 ) ;
err | = __put_user ( regs - > UCreg_15 , & sf - > uc . uc_mcontext . regs . UCreg_15 ) ;
err | = __put_user ( regs - > UCreg_16 , & sf - > uc . uc_mcontext . regs . UCreg_16 ) ;
err | = __put_user ( regs - > UCreg_17 , & sf - > uc . uc_mcontext . regs . UCreg_17 ) ;
err | = __put_user ( regs - > UCreg_18 , & sf - > uc . uc_mcontext . regs . UCreg_18 ) ;
err | = __put_user ( regs - > UCreg_19 , & sf - > uc . uc_mcontext . regs . UCreg_19 ) ;
err | = __put_user ( regs - > UCreg_20 , & sf - > uc . uc_mcontext . regs . UCreg_20 ) ;
err | = __put_user ( regs - > UCreg_21 , & sf - > uc . uc_mcontext . regs . UCreg_21 ) ;
err | = __put_user ( regs - > UCreg_22 , & sf - > uc . uc_mcontext . regs . UCreg_22 ) ;
err | = __put_user ( regs - > UCreg_23 , & sf - > uc . uc_mcontext . regs . UCreg_23 ) ;
err | = __put_user ( regs - > UCreg_24 , & sf - > uc . uc_mcontext . regs . UCreg_24 ) ;
err | = __put_user ( regs - > UCreg_25 , & sf - > uc . uc_mcontext . regs . UCreg_25 ) ;
err | = __put_user ( regs - > UCreg_26 , & sf - > uc . uc_mcontext . regs . UCreg_26 ) ;
err | = __put_user ( regs - > UCreg_fp , & sf - > uc . uc_mcontext . regs . UCreg_fp ) ;
err | = __put_user ( regs - > UCreg_ip , & sf - > uc . uc_mcontext . regs . UCreg_ip ) ;
err | = __put_user ( regs - > UCreg_sp , & sf - > uc . uc_mcontext . regs . UCreg_sp ) ;
err | = __put_user ( regs - > UCreg_lr , & sf - > uc . uc_mcontext . regs . UCreg_lr ) ;
err | = __put_user ( regs - > UCreg_pc , & sf - > uc . uc_mcontext . regs . UCreg_pc ) ;
err | = __put_user ( regs - > UCreg_asr , & sf - > uc . uc_mcontext . regs . UCreg_asr ) ;
err | = __put_user ( current - > thread . trap_no ,
& sf - > uc . uc_mcontext . trap_no ) ;
err | = __put_user ( current - > thread . error_code ,
& sf - > uc . uc_mcontext . error_code ) ;
err | = __put_user ( current - > thread . address ,
& sf - > uc . uc_mcontext . fault_address ) ;
err | = __put_user ( set - > sig [ 0 ] , & sf - > uc . uc_mcontext . oldmask ) ;
err | = __copy_to_user ( & sf - > uc . uc_sigmask , set , sizeof ( * set ) ) ;
return err ;
}
static inline void __user * get_sigframe ( struct k_sigaction * ka ,
struct pt_regs * regs , int framesize )
{
unsigned long sp = regs - > UCreg_sp ;
void __user * frame ;
/*
* This is the X / Open sanctioned signal stack switching .
*/
if ( ( ka - > sa . sa_flags & SA_ONSTACK ) & & ! sas_ss_flags ( sp ) )
sp = current - > sas_ss_sp + current - > sas_ss_size ;
/*
* ATPCS B01 mandates 8 - byte alignment
*/
frame = ( void __user * ) ( ( sp - framesize ) & ~ 7 ) ;
/*
* Check that we can actually write to the signal frame .
*/
if ( ! access_ok ( VERIFY_WRITE , frame , framesize ) )
frame = NULL ;
return frame ;
}
static int setup_return ( struct pt_regs * regs , struct k_sigaction * ka ,
unsigned long __user * rc , void __user * frame , int usig )
{
unsigned long handler = ( unsigned long ) ka - > sa . sa_handler ;
unsigned long retcode ;
unsigned long asr = regs - > UCreg_asr & ~ PSR_f ;
unsigned int idx = 0 ;
if ( ka - > sa . sa_flags & SA_SIGINFO )
idx + = 1 ;
if ( __put_user ( sigreturn_codes [ idx ] , rc ) | |
__put_user ( sigreturn_codes [ idx + 1 ] , rc + 1 ) )
return 1 ;
retcode = KERN_SIGRETURN_CODE + ( idx < < 2 ) ;
regs - > UCreg_00 = usig ;
regs - > UCreg_sp = ( unsigned long ) frame ;
regs - > UCreg_lr = retcode ;
regs - > UCreg_pc = handler ;
regs - > UCreg_asr = asr ;
return 0 ;
}
2013-10-07 17:05:57 +04:00
static int setup_frame ( struct ksignal * ksig , sigset_t * set ,
struct pt_regs * regs )
2011-01-15 13:20:01 +03:00
{
2013-10-07 17:05:57 +04:00
struct sigframe __user * frame = get_sigframe ( & ksig - > ka , regs , sizeof ( * frame ) ) ;
2011-01-15 13:20:01 +03:00
int err = 0 ;
if ( ! frame )
return 1 ;
/*
* Set uc . uc_flags to a value which sc . trap_no would never have .
*/
err | = __put_user ( 0x5ac3c35a , & frame - > uc . uc_flags ) ;
err | = setup_sigframe ( frame , regs , set ) ;
if ( err = = 0 )
2014-08-31 22:14:26 +04:00
err | = setup_return ( regs , & ksig - > ka , frame - > retcode , frame ,
ksig - > sig ) ;
2011-01-15 13:20:01 +03:00
return err ;
}
2013-10-07 17:05:57 +04:00
static int setup_rt_frame ( struct ksignal * ksig , sigset_t * set ,
struct pt_regs * regs )
2011-01-15 13:20:01 +03:00
{
struct rt_sigframe __user * frame =
2013-10-07 17:05:57 +04:00
get_sigframe ( & ksig - > ka , regs , sizeof ( * frame ) ) ;
2011-01-15 13:20:01 +03:00
int err = 0 ;
if ( ! frame )
return 1 ;
2013-10-07 17:05:57 +04:00
err | = copy_siginfo_to_user ( & frame - > info , & ksig - > info ) ;
2011-01-15 13:20:01 +03:00
err | = __put_user ( 0 , & frame - > sig . uc . uc_flags ) ;
err | = __put_user ( NULL , & frame - > sig . uc . uc_link ) ;
2012-12-23 12:52:33 +04:00
err | = __save_altstack ( & frame - > sig . uc . uc_stack , regs - > UCreg_sp ) ;
2011-01-15 13:20:01 +03:00
err | = setup_sigframe ( & frame - > sig , regs , set ) ;
if ( err = = 0 )
2014-08-31 22:14:26 +04:00
err | = setup_return ( regs , & ksig - > ka , frame - > sig . retcode , frame ,
ksig - > sig ) ;
2011-01-15 13:20:01 +03:00
if ( err = = 0 ) {
/*
* For realtime signals we must also set the second and third
* arguments for the signal handler .
*/
regs - > UCreg_01 = ( unsigned long ) & frame - > info ;
regs - > UCreg_02 = ( unsigned long ) & frame - > sig . uc ;
}
return err ;
}
static inline void setup_syscall_restart ( struct pt_regs * regs )
{
regs - > UCreg_00 = regs - > UCreg_ORIG_00 ;
regs - > UCreg_pc - = 4 ;
}
/*
* OK , we ' re invoking a handler
*/
2013-10-07 17:05:57 +04:00
static void handle_signal ( struct ksignal * ksig , struct pt_regs * regs ,
int syscall )
2011-01-15 13:20:01 +03:00
{
struct thread_info * thread = current_thread_info ( ) ;
2012-05-02 17:59:21 +04:00
sigset_t * oldset = sigmask_to_save ( ) ;
2013-10-07 17:05:57 +04:00
int usig = ksig - > sig ;
2011-01-15 13:20:01 +03:00
int ret ;
/*
* If we were from a system call , check for system call restarting . . .
*/
if ( syscall ) {
switch ( regs - > UCreg_00 ) {
case - ERESTART_RESTARTBLOCK :
case - ERESTARTNOHAND :
regs - > UCreg_00 = - EINTR ;
break ;
case - ERESTARTSYS :
2013-10-07 17:05:57 +04:00
if ( ! ( ksig - > ka . sa . sa_flags & SA_RESTART ) ) {
2011-01-15 13:20:01 +03:00
regs - > UCreg_00 = - EINTR ;
break ;
}
/* fallthrough */
case - ERESTARTNOINTR :
setup_syscall_restart ( regs ) ;
}
}
/*
* translate the signal
*/
if ( usig < 32 & & thread - > exec_domain
& & thread - > exec_domain - > signal_invmap )
usig = thread - > exec_domain - > signal_invmap [ usig ] ;
/*
* Set up the stack frame
*/
2013-10-07 17:05:57 +04:00
if ( ksig - > ka . sa . sa_flags & SA_SIGINFO )
ret = setup_rt_frame ( ksig , oldset , regs ) ;
2011-01-15 13:20:01 +03:00
else
2013-10-07 17:05:57 +04:00
ret = setup_frame ( ksig , oldset , regs ) ;
2011-01-15 13:20:01 +03:00
/*
* Check that the resulting registers are actually sane .
*/
ret | = ! valid_user_regs ( regs ) ;
2013-10-07 17:05:57 +04:00
signal_setup_done ( ret , ksig , 0 ) ;
2011-01-15 13:20:01 +03:00
}
/*
* Note that ' init ' is a special process : it doesn ' t get signals it doesn ' t
* want to handle . Thus you cannot kill init even with a SIGKILL even by
* mistake .
*
* Note that we go through the signals twice : once to check the signals that
* the kernel can handle , and then we build all the user - level signal handling
* stack - frames in one go after that .
*/
static void do_signal ( struct pt_regs * regs , int syscall )
{
2013-10-07 17:05:57 +04:00
struct ksignal ksig ;
2011-01-15 13:20:01 +03:00
/*
* We want the common case to go fast , which
* is why we may in certain cases get here from
* kernel mode . Just return without doing anything
* if so .
*/
if ( ! user_mode ( regs ) )
return ;
2014-08-31 22:14:26 +04:00
if ( get_signal ( & ksig ) ) {
2013-10-07 17:05:57 +04:00
handle_signal ( & ksig , regs , syscall ) ;
2011-01-15 13:20:01 +03:00
return ;
}
/*
* No signal to deliver to the process - restart the syscall .
*/
if ( syscall ) {
if ( regs - > UCreg_00 = = - ERESTART_RESTARTBLOCK ) {
u32 __user * usp ;
regs - > UCreg_sp - = 4 ;
usp = ( u32 __user * ) regs - > UCreg_sp ;
if ( put_user ( regs - > UCreg_pc , usp ) = = 0 ) {
regs - > UCreg_pc = KERN_RESTART_CODE ;
} else {
regs - > UCreg_sp + = 4 ;
force_sigsegv ( 0 , current ) ;
}
}
if ( regs - > UCreg_00 = = - ERESTARTNOHAND | |
regs - > UCreg_00 = = - ERESTARTSYS | |
regs - > UCreg_00 = = - ERESTARTNOINTR ) {
setup_syscall_restart ( regs ) ;
}
}
2012-04-27 02:17:28 +04:00
/* If there's no signal to deliver, we just put the saved
* sigmask back .
*/
2012-05-22 07:33:55 +04:00
restore_saved_sigmask ( ) ;
2011-01-15 13:20:01 +03:00
}
asmlinkage void do_notify_resume ( struct pt_regs * regs ,
unsigned int thread_flags , int syscall )
{
if ( thread_flags & _TIF_SIGPENDING )
do_signal ( regs , syscall ) ;
if ( thread_flags & _TIF_NOTIFY_RESUME ) {
clear_thread_flag ( TIF_NOTIFY_RESUME ) ;
tracehook_notify_resume ( regs ) ;
}
}
/*
* Copy signal return handlers into the vector page , and
* set sigreturn to be a pointer to these .
*/
void __init early_signal_init ( void )
{
memcpy ( ( void * ) kuser_vecpage_to_vectors ( KERN_SIGRETURN_CODE ) ,
sigreturn_codes , sizeof ( sigreturn_codes ) ) ;
memcpy ( ( void * ) kuser_vecpage_to_vectors ( KERN_RESTART_CODE ) ,
syscall_restart_code , sizeof ( syscall_restart_code ) ) ;
/* Need not to flush icache, since early_trap_init will do it last. */
}