2008-04-18 17:08:44 -07:00
/*
* Access to user system call parameters and results
*
2009-09-22 19:57:51 -07:00
* Copyright ( C ) 2008 - 2009 Red Hat , Inc . All rights reserved .
2008-04-18 17:08:44 -07:00
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU General Public License v .2 .
*
* See asm - generic / syscall . h for descriptions of what we must do here .
*/
2008-10-23 00:20:33 -07:00
# ifndef _ASM_X86_SYSCALL_H
# define _ASM_X86_SYSCALL_H
2008-04-18 17:08:44 -07:00
2012-04-12 16:47:56 -05:00
# include <linux/audit.h>
2008-04-18 17:08:44 -07:00
# include <linux/sched.h>
2008-09-03 13:31:42 +02:00
# include <linux/err.h>
2012-01-07 14:10:18 -08:00
# include <asm/asm-offsets.h> /* For NR_syscalls */
2012-04-12 16:47:56 -05:00
# include <asm/thread_info.h> /* for TS_COMPAT */
2012-02-19 07:56:26 -08:00
# include <asm/unistd.h>
2008-04-18 17:08:44 -07:00
2010-01-26 04:40:03 -05:00
extern const unsigned long sys_call_table [ ] ;
2009-09-22 19:57:51 -07:00
/*
* Only the low 32 bits of orig_ax are meaningful , so we return int .
* This importantly ignores the high bits on 64 - bit , so comparisons
* sign - extend the low 32 bits .
*/
static inline int syscall_get_nr ( struct task_struct * task , struct pt_regs * regs )
2008-04-18 17:08:44 -07:00
{
2012-02-19 07:56:26 -08:00
return regs - > orig_ax & __SYSCALL_MASK ;
2008-04-18 17:08:44 -07:00
}
static inline void syscall_rollback ( struct task_struct * task ,
struct pt_regs * regs )
{
2012-02-19 07:56:26 -08:00
regs - > ax = regs - > orig_ax & __SYSCALL_MASK ;
2008-04-18 17:08:44 -07:00
}
static inline long syscall_get_error ( struct task_struct * task ,
struct pt_regs * regs )
{
unsigned long error = regs - > ax ;
# ifdef CONFIG_IA32_EMULATION
/*
* TS_COMPAT is set for 32 - bit syscall entries and then
* remains set until we return to user mode .
*/
if ( task_thread_info ( task ) - > status & TS_COMPAT )
/*
* Sign - extend the value so ( int ) - EFOO becomes ( long ) - EFOO
* and will match correctly in comparisons .
*/
error = ( long ) ( int ) error ;
# endif
2008-09-03 13:31:42 +02:00
return IS_ERR_VALUE ( error ) ? error : 0 ;
2008-04-18 17:08:44 -07:00
}
static inline long syscall_get_return_value ( struct task_struct * task ,
struct pt_regs * regs )
{
return regs - > ax ;
}
static inline void syscall_set_return_value ( struct task_struct * task ,
struct pt_regs * regs ,
int error , long val )
{
regs - > ax = ( long ) error ? : val ;
}
# ifdef CONFIG_X86_32
static inline void syscall_get_arguments ( struct task_struct * task ,
struct pt_regs * regs ,
unsigned int i , unsigned int n ,
unsigned long * args )
{
BUG_ON ( i + n > 6 ) ;
memcpy ( args , & regs - > bx + i , n * sizeof ( args [ 0 ] ) ) ;
}
static inline void syscall_set_arguments ( struct task_struct * task ,
struct pt_regs * regs ,
unsigned int i , unsigned int n ,
const unsigned long * args )
{
BUG_ON ( i + n > 6 ) ;
memcpy ( & regs - > bx + i , args , n * sizeof ( args [ 0 ] ) ) ;
}
2012-04-12 16:47:56 -05:00
static inline int syscall_get_arch ( struct task_struct * task ,
struct pt_regs * regs )
{
return AUDIT_ARCH_I386 ;
}
2008-04-18 17:08:44 -07:00
# else /* CONFIG_X86_64 */
static inline void syscall_get_arguments ( struct task_struct * task ,
struct pt_regs * regs ,
unsigned int i , unsigned int n ,
unsigned long * args )
{
# ifdef CONFIG_IA32_EMULATION
if ( task_thread_info ( task ) - > status & TS_COMPAT )
2008-10-13 18:40:04 -07:00
switch ( i ) {
case 0 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
* args + + = regs - > bx ;
case 1 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
* args + + = regs - > cx ;
case 2 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
* args + + = regs - > dx ;
2008-04-18 17:08:44 -07:00
case 3 :
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
* args + + = regs - > si ;
case 4 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
* args + + = regs - > di ;
case 5 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
* args + + = regs - > bp ;
case 6 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
default :
BUG ( ) ;
break ;
}
else
# endif
2008-10-13 18:40:04 -07:00
switch ( i ) {
case 0 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
* args + + = regs - > di ;
case 1 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
* args + + = regs - > si ;
case 2 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
* args + + = regs - > dx ;
2008-04-18 17:08:44 -07:00
case 3 :
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
* args + + = regs - > r10 ;
case 4 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
* args + + = regs - > r8 ;
case 5 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
* args + + = regs - > r9 ;
case 6 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
default :
BUG ( ) ;
break ;
}
}
static inline void syscall_set_arguments ( struct task_struct * task ,
struct pt_regs * regs ,
unsigned int i , unsigned int n ,
const unsigned long * args )
{
# ifdef CONFIG_IA32_EMULATION
if ( task_thread_info ( task ) - > status & TS_COMPAT )
2008-10-13 18:40:04 -07:00
switch ( i ) {
case 0 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
regs - > bx = * args + + ;
case 1 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
regs - > cx = * args + + ;
case 2 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
regs - > dx = * args + + ;
2008-04-18 17:08:44 -07:00
case 3 :
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
regs - > si = * args + + ;
case 4 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
regs - > di = * args + + ;
case 5 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
regs - > bp = * args + + ;
case 6 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
default :
BUG ( ) ;
2008-10-13 18:40:04 -07:00
break ;
2008-04-18 17:08:44 -07:00
}
else
# endif
2008-10-13 18:40:04 -07:00
switch ( i ) {
case 0 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
regs - > di = * args + + ;
case 1 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
regs - > si = * args + + ;
case 2 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
regs - > dx = * args + + ;
2008-04-18 17:08:44 -07:00
case 3 :
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
regs - > r10 = * args + + ;
case 4 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
regs - > r8 = * args + + ;
case 5 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
2008-10-13 18:40:04 -07:00
regs - > r9 = * args + + ;
case 6 :
2008-04-18 17:08:44 -07:00
if ( ! n - - ) break ;
default :
BUG ( ) ;
2008-10-13 18:40:04 -07:00
break ;
2008-04-18 17:08:44 -07:00
}
}
2012-04-12 16:47:56 -05:00
static inline int syscall_get_arch ( struct task_struct * task ,
struct pt_regs * regs )
{
# ifdef CONFIG_IA32_EMULATION
/*
* TS_COMPAT is set for 32 - bit syscall entry and then
* remains set until we return to user mode .
*
* TIF_IA32 tasks should always have TS_COMPAT set at
* system call time .
*
* x32 tasks should be considered AUDIT_ARCH_X86_64 .
*/
if ( task_thread_info ( task ) - > status & TS_COMPAT )
return AUDIT_ARCH_I386 ;
# endif
/* Both x32 and x86_64 are considered "64-bit". */
return AUDIT_ARCH_X86_64 ;
}
2008-04-18 17:08:44 -07:00
# endif /* CONFIG_X86_32 */
2008-10-23 00:20:33 -07:00
# endif /* _ASM_X86_SYSCALL_H */