1bb898558SAl Viro /* 2bb898558SAl Viro * Access to user system call parameters and results 3bb898558SAl Viro * 418c1e2c8SRoland McGrath * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. 5bb898558SAl Viro * 6bb898558SAl Viro * This copyrighted material is made available to anyone wishing to use, 7bb898558SAl Viro * modify, copy, or redistribute it subject to the terms and conditions 8bb898558SAl Viro * of the GNU General Public License v.2. 9bb898558SAl Viro * 10bb898558SAl Viro * See asm-generic/syscall.h for descriptions of what we must do here. 11bb898558SAl Viro */ 12bb898558SAl Viro 135e1b0075SH. Peter Anvin #ifndef _ASM_X86_SYSCALL_H 145e1b0075SH. Peter Anvin #define _ASM_X86_SYSCALL_H 15bb898558SAl Viro 16579ec9e1SEric Paris #include <uapi/linux/audit.h> 17bb898558SAl Viro #include <linux/sched.h> 18bb898558SAl Viro #include <linux/err.h> 1972142fd4SH. Peter Anvin #include <asm/asm-offsets.h> /* For NR_syscalls */ 20b7456536SWill Drewry #include <asm/thread_info.h> /* for TS_COMPAT */ 21fca460f9SH. Peter Anvin #include <asm/unistd.h> 22bb898558SAl Viro 23f8781c4aSDominik Brodowski #ifdef CONFIG_X86_64 24fa697140SDominik Brodowski typedef asmlinkage long (*sys_call_ptr_t)(const struct pt_regs *); 25fa697140SDominik Brodowski #else 26eb974c62SAndy Lutomirski typedef asmlinkage long (*sys_call_ptr_t)(unsigned long, unsigned long, 27eb974c62SAndy Lutomirski unsigned long, unsigned long, 28eb974c62SAndy Lutomirski unsigned long, unsigned long); 29f8781c4aSDominik Brodowski #endif /* CONFIG_X86_64 */ 301599e8fcSAndi Kleen extern const sys_call_ptr_t sys_call_table[]; 31e7b8e675SMike Frysinger 32034042ccSAndy Lutomirski #if defined(CONFIG_X86_32) 33034042ccSAndy Lutomirski #define ia32_sys_call_table sys_call_table 34034042ccSAndy Lutomirski #define __NR_syscall_compat_max __NR_syscall_max 35034042ccSAndy Lutomirski #define IA32_NR_syscalls NR_syscalls 36034042ccSAndy Lutomirski #endif 37034042ccSAndy Lutomirski 38034042ccSAndy Lutomirski #if defined(CONFIG_IA32_EMULATION) 39034042ccSAndy Lutomirski extern const sys_call_ptr_t ia32_sys_call_table[]; 40034042ccSAndy Lutomirski #endif 41034042ccSAndy Lutomirski 42bb898558SAl Viro /* 4318c1e2c8SRoland McGrath * Only the low 32 bits of orig_ax are meaningful, so we return int. 4418c1e2c8SRoland McGrath * This importantly ignores the high bits on 64-bit, so comparisons 4518c1e2c8SRoland McGrath * sign-extend the low 32 bits. 46bb898558SAl Viro */ 4718c1e2c8SRoland McGrath static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) 4818c1e2c8SRoland McGrath { 498b4b9f27SPaul Moore return regs->orig_ax; 50bb898558SAl Viro } 51bb898558SAl Viro 52bb898558SAl Viro static inline void syscall_rollback(struct task_struct *task, 53bb898558SAl Viro struct pt_regs *regs) 54bb898558SAl Viro { 558b4b9f27SPaul Moore regs->ax = regs->orig_ax; 56bb898558SAl Viro } 57bb898558SAl Viro 58bb898558SAl Viro static inline long syscall_get_error(struct task_struct *task, 59bb898558SAl Viro struct pt_regs *regs) 60bb898558SAl Viro { 61bb898558SAl Viro unsigned long error = regs->ax; 62bb898558SAl Viro #ifdef CONFIG_IA32_EMULATION 63bb898558SAl Viro /* 64bb898558SAl Viro * TS_COMPAT is set for 32-bit syscall entries and then 65bb898558SAl Viro * remains set until we return to user mode. 66bb898558SAl Viro */ 6737a8f7c3SAndy Lutomirski if (task->thread_info.status & (TS_COMPAT|TS_I386_REGS_POKED)) 68bb898558SAl Viro /* 69bb898558SAl Viro * Sign-extend the value so (int)-EFOO becomes (long)-EFOO 70bb898558SAl Viro * and will match correctly in comparisons. 71bb898558SAl Viro */ 72bb898558SAl Viro error = (long) (int) error; 73bb898558SAl Viro #endif 74bb898558SAl Viro return IS_ERR_VALUE(error) ? error : 0; 75bb898558SAl Viro } 76bb898558SAl Viro 77bb898558SAl Viro static inline long syscall_get_return_value(struct task_struct *task, 78bb898558SAl Viro struct pt_regs *regs) 79bb898558SAl Viro { 80bb898558SAl Viro return regs->ax; 81bb898558SAl Viro } 82bb898558SAl Viro 83bb898558SAl Viro static inline void syscall_set_return_value(struct task_struct *task, 84bb898558SAl Viro struct pt_regs *regs, 85bb898558SAl Viro int error, long val) 86bb898558SAl Viro { 87bb898558SAl Viro regs->ax = (long) error ?: val; 88bb898558SAl Viro } 89bb898558SAl Viro 90bb898558SAl Viro #ifdef CONFIG_X86_32 91bb898558SAl Viro 92bb898558SAl Viro static inline void syscall_get_arguments(struct task_struct *task, 93bb898558SAl Viro struct pt_regs *regs, 94bb898558SAl Viro unsigned long *args) 95bb898558SAl Viro { 96*b35f549dSSteven Rostedt (Red Hat) memcpy(args, ®s->bx, 6 * sizeof(args[0])); 97bb898558SAl Viro } 98bb898558SAl Viro 99bb898558SAl Viro static inline void syscall_set_arguments(struct task_struct *task, 100bb898558SAl Viro struct pt_regs *regs, 101bb898558SAl Viro unsigned int i, unsigned int n, 102bb898558SAl Viro const unsigned long *args) 103bb898558SAl Viro { 104bb898558SAl Viro BUG_ON(i + n > 6); 105bb898558SAl Viro memcpy(®s->bx + i, args, n * sizeof(args[0])); 106bb898558SAl Viro } 107bb898558SAl Viro 1085e937a9aSEric Paris static inline int syscall_get_arch(void) 109b7456536SWill Drewry { 110b7456536SWill Drewry return AUDIT_ARCH_I386; 111b7456536SWill Drewry } 112b7456536SWill Drewry 113bb898558SAl Viro #else /* CONFIG_X86_64 */ 114bb898558SAl Viro 115bb898558SAl Viro static inline void syscall_get_arguments(struct task_struct *task, 116bb898558SAl Viro struct pt_regs *regs, 117bb898558SAl Viro unsigned long *args) 118bb898558SAl Viro { 119bb898558SAl Viro # ifdef CONFIG_IA32_EMULATION 120*b35f549dSSteven Rostedt (Red Hat) if (task->thread_info.status & TS_COMPAT) { 121bb898558SAl Viro *args++ = regs->bx; 122c3c9897cSLinus Torvalds *args++ = regs->cx; 123c3c9897cSLinus Torvalds *args++ = regs->dx; 124c3c9897cSLinus Torvalds *args++ = regs->si; 125c3c9897cSLinus Torvalds *args++ = regs->di; 126*b35f549dSSteven Rostedt (Red Hat) *args = regs->bp; 127*b35f549dSSteven Rostedt (Red Hat) } else 128bb898558SAl Viro # endif 129*b35f549dSSteven Rostedt (Red Hat) { 130bb898558SAl Viro *args++ = regs->di; 131c3c9897cSLinus Torvalds *args++ = regs->si; 132c3c9897cSLinus Torvalds *args++ = regs->dx; 133c3c9897cSLinus Torvalds *args++ = regs->r10; 134c3c9897cSLinus Torvalds *args++ = regs->r8; 135*b35f549dSSteven Rostedt (Red Hat) *args = regs->r9; 136bb898558SAl Viro } 137bb898558SAl Viro } 138bb898558SAl Viro 139bb898558SAl Viro static inline void syscall_set_arguments(struct task_struct *task, 140bb898558SAl Viro struct pt_regs *regs, 141bb898558SAl Viro unsigned int i, unsigned int n, 142bb898558SAl Viro const unsigned long *args) 143bb898558SAl Viro { 144bb898558SAl Viro # ifdef CONFIG_IA32_EMULATION 14537a8f7c3SAndy Lutomirski if (task->thread_info.status & TS_COMPAT) 146c3c9897cSLinus Torvalds switch (i) { 147c3c9897cSLinus Torvalds case 0: 148bb898558SAl Viro if (!n--) break; 149bb898558SAl Viro regs->bx = *args++; 150c3c9897cSLinus Torvalds case 1: 151c3c9897cSLinus Torvalds if (!n--) break; 152c3c9897cSLinus Torvalds regs->cx = *args++; 153c3c9897cSLinus Torvalds case 2: 154c3c9897cSLinus Torvalds if (!n--) break; 155c3c9897cSLinus Torvalds regs->dx = *args++; 156c3c9897cSLinus Torvalds case 3: 157c3c9897cSLinus Torvalds if (!n--) break; 158c3c9897cSLinus Torvalds regs->si = *args++; 159c3c9897cSLinus Torvalds case 4: 160c3c9897cSLinus Torvalds if (!n--) break; 161c3c9897cSLinus Torvalds regs->di = *args++; 162c3c9897cSLinus Torvalds case 5: 163c3c9897cSLinus Torvalds if (!n--) break; 164c3c9897cSLinus Torvalds regs->bp = *args++; 165c3c9897cSLinus Torvalds case 6: 166bb898558SAl Viro if (!n--) break; 167bb898558SAl Viro default: 168bb898558SAl Viro BUG(); 169c3c9897cSLinus Torvalds break; 170bb898558SAl Viro } 171bb898558SAl Viro else 172bb898558SAl Viro # endif 173c3c9897cSLinus Torvalds switch (i) { 174c3c9897cSLinus Torvalds case 0: 175bb898558SAl Viro if (!n--) break; 176bb898558SAl Viro regs->di = *args++; 177c3c9897cSLinus Torvalds case 1: 178c3c9897cSLinus Torvalds if (!n--) break; 179c3c9897cSLinus Torvalds regs->si = *args++; 180c3c9897cSLinus Torvalds case 2: 181c3c9897cSLinus Torvalds if (!n--) break; 182c3c9897cSLinus Torvalds regs->dx = *args++; 183c3c9897cSLinus Torvalds case 3: 184c3c9897cSLinus Torvalds if (!n--) break; 185c3c9897cSLinus Torvalds regs->r10 = *args++; 186c3c9897cSLinus Torvalds case 4: 187c3c9897cSLinus Torvalds if (!n--) break; 188c3c9897cSLinus Torvalds regs->r8 = *args++; 189c3c9897cSLinus Torvalds case 5: 190c3c9897cSLinus Torvalds if (!n--) break; 191c3c9897cSLinus Torvalds regs->r9 = *args++; 192c3c9897cSLinus Torvalds case 6: 193bb898558SAl Viro if (!n--) break; 194bb898558SAl Viro default: 195bb898558SAl Viro BUG(); 196c3c9897cSLinus Torvalds break; 197bb898558SAl Viro } 198bb898558SAl Viro } 199bb898558SAl Viro 2005e937a9aSEric Paris static inline int syscall_get_arch(void) 201b7456536SWill Drewry { 202b9d989c7SAndy Lutomirski /* x32 tasks should be considered AUDIT_ARCH_X86_64. */ 203b9d989c7SAndy Lutomirski return in_ia32_syscall() ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64; 204b7456536SWill Drewry } 205bb898558SAl Viro #endif /* CONFIG_X86_32 */ 206bb898558SAl Viro 2075e1b0075SH. Peter Anvin #endif /* _ASM_X86_SYSCALL_H */ 208