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 16*579ec9e1SEric 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 231599e8fcSAndi Kleen typedef void (*sys_call_ptr_t)(void); 241599e8fcSAndi Kleen extern const sys_call_ptr_t sys_call_table[]; 25e7b8e675SMike Frysinger 26bb898558SAl Viro /* 2718c1e2c8SRoland McGrath * Only the low 32 bits of orig_ax are meaningful, so we return int. 2818c1e2c8SRoland McGrath * This importantly ignores the high bits on 64-bit, so comparisons 2918c1e2c8SRoland McGrath * sign-extend the low 32 bits. 30bb898558SAl Viro */ 3118c1e2c8SRoland McGrath static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) 3218c1e2c8SRoland McGrath { 338b4b9f27SPaul Moore return regs->orig_ax; 34bb898558SAl Viro } 35bb898558SAl Viro 36bb898558SAl Viro static inline void syscall_rollback(struct task_struct *task, 37bb898558SAl Viro struct pt_regs *regs) 38bb898558SAl Viro { 398b4b9f27SPaul Moore regs->ax = regs->orig_ax; 40bb898558SAl Viro } 41bb898558SAl Viro 42bb898558SAl Viro static inline long syscall_get_error(struct task_struct *task, 43bb898558SAl Viro struct pt_regs *regs) 44bb898558SAl Viro { 45bb898558SAl Viro unsigned long error = regs->ax; 46bb898558SAl Viro #ifdef CONFIG_IA32_EMULATION 47bb898558SAl Viro /* 48bb898558SAl Viro * TS_COMPAT is set for 32-bit syscall entries and then 49bb898558SAl Viro * remains set until we return to user mode. 50bb898558SAl Viro */ 51bb898558SAl Viro if (task_thread_info(task)->status & TS_COMPAT) 52bb898558SAl Viro /* 53bb898558SAl Viro * Sign-extend the value so (int)-EFOO becomes (long)-EFOO 54bb898558SAl Viro * and will match correctly in comparisons. 55bb898558SAl Viro */ 56bb898558SAl Viro error = (long) (int) error; 57bb898558SAl Viro #endif 58bb898558SAl Viro return IS_ERR_VALUE(error) ? error : 0; 59bb898558SAl Viro } 60bb898558SAl Viro 61bb898558SAl Viro static inline long syscall_get_return_value(struct task_struct *task, 62bb898558SAl Viro struct pt_regs *regs) 63bb898558SAl Viro { 64bb898558SAl Viro return regs->ax; 65bb898558SAl Viro } 66bb898558SAl Viro 67bb898558SAl Viro static inline void syscall_set_return_value(struct task_struct *task, 68bb898558SAl Viro struct pt_regs *regs, 69bb898558SAl Viro int error, long val) 70bb898558SAl Viro { 71bb898558SAl Viro regs->ax = (long) error ?: val; 72bb898558SAl Viro } 73bb898558SAl Viro 74bb898558SAl Viro #ifdef CONFIG_X86_32 75bb898558SAl Viro 76bb898558SAl Viro static inline void syscall_get_arguments(struct task_struct *task, 77bb898558SAl Viro struct pt_regs *regs, 78bb898558SAl Viro unsigned int i, unsigned int n, 79bb898558SAl Viro unsigned long *args) 80bb898558SAl Viro { 81bb898558SAl Viro BUG_ON(i + n > 6); 82bb898558SAl Viro memcpy(args, ®s->bx + i, n * sizeof(args[0])); 83bb898558SAl Viro } 84bb898558SAl Viro 85bb898558SAl Viro static inline void syscall_set_arguments(struct task_struct *task, 86bb898558SAl Viro struct pt_regs *regs, 87bb898558SAl Viro unsigned int i, unsigned int n, 88bb898558SAl Viro const unsigned long *args) 89bb898558SAl Viro { 90bb898558SAl Viro BUG_ON(i + n > 6); 91bb898558SAl Viro memcpy(®s->bx + i, args, n * sizeof(args[0])); 92bb898558SAl Viro } 93bb898558SAl Viro 945e937a9aSEric Paris static inline int syscall_get_arch(void) 95b7456536SWill Drewry { 96b7456536SWill Drewry return AUDIT_ARCH_I386; 97b7456536SWill Drewry } 98b7456536SWill Drewry 99bb898558SAl Viro #else /* CONFIG_X86_64 */ 100bb898558SAl Viro 101bb898558SAl Viro static inline void syscall_get_arguments(struct task_struct *task, 102bb898558SAl Viro struct pt_regs *regs, 103bb898558SAl Viro unsigned int i, unsigned int n, 104bb898558SAl Viro unsigned long *args) 105bb898558SAl Viro { 106bb898558SAl Viro # ifdef CONFIG_IA32_EMULATION 107bb898558SAl Viro if (task_thread_info(task)->status & TS_COMPAT) 108c3c9897cSLinus Torvalds switch (i) { 109c3c9897cSLinus Torvalds case 0: 110bb898558SAl Viro if (!n--) break; 111bb898558SAl Viro *args++ = regs->bx; 112c3c9897cSLinus Torvalds case 1: 113c3c9897cSLinus Torvalds if (!n--) break; 114c3c9897cSLinus Torvalds *args++ = regs->cx; 115c3c9897cSLinus Torvalds case 2: 116c3c9897cSLinus Torvalds if (!n--) break; 117c3c9897cSLinus Torvalds *args++ = regs->dx; 118c3c9897cSLinus Torvalds case 3: 119c3c9897cSLinus Torvalds if (!n--) break; 120c3c9897cSLinus Torvalds *args++ = regs->si; 121c3c9897cSLinus Torvalds case 4: 122c3c9897cSLinus Torvalds if (!n--) break; 123c3c9897cSLinus Torvalds *args++ = regs->di; 124c3c9897cSLinus Torvalds case 5: 125c3c9897cSLinus Torvalds if (!n--) break; 126c3c9897cSLinus Torvalds *args++ = regs->bp; 127c3c9897cSLinus Torvalds case 6: 128bb898558SAl Viro if (!n--) break; 129bb898558SAl Viro default: 130bb898558SAl Viro BUG(); 131bb898558SAl Viro break; 132bb898558SAl Viro } 133bb898558SAl Viro else 134bb898558SAl Viro # endif 135c3c9897cSLinus Torvalds switch (i) { 136c3c9897cSLinus Torvalds case 0: 137bb898558SAl Viro if (!n--) break; 138bb898558SAl Viro *args++ = regs->di; 139c3c9897cSLinus Torvalds case 1: 140c3c9897cSLinus Torvalds if (!n--) break; 141c3c9897cSLinus Torvalds *args++ = regs->si; 142c3c9897cSLinus Torvalds case 2: 143c3c9897cSLinus Torvalds if (!n--) break; 144c3c9897cSLinus Torvalds *args++ = regs->dx; 145c3c9897cSLinus Torvalds case 3: 146c3c9897cSLinus Torvalds if (!n--) break; 147c3c9897cSLinus Torvalds *args++ = regs->r10; 148c3c9897cSLinus Torvalds case 4: 149c3c9897cSLinus Torvalds if (!n--) break; 150c3c9897cSLinus Torvalds *args++ = regs->r8; 151c3c9897cSLinus Torvalds case 5: 152c3c9897cSLinus Torvalds if (!n--) break; 153c3c9897cSLinus Torvalds *args++ = regs->r9; 154c3c9897cSLinus Torvalds case 6: 155bb898558SAl Viro if (!n--) break; 156bb898558SAl Viro default: 157bb898558SAl Viro BUG(); 158bb898558SAl Viro break; 159bb898558SAl Viro } 160bb898558SAl Viro } 161bb898558SAl Viro 162bb898558SAl Viro static inline void syscall_set_arguments(struct task_struct *task, 163bb898558SAl Viro struct pt_regs *regs, 164bb898558SAl Viro unsigned int i, unsigned int n, 165bb898558SAl Viro const unsigned long *args) 166bb898558SAl Viro { 167bb898558SAl Viro # ifdef CONFIG_IA32_EMULATION 168bb898558SAl Viro if (task_thread_info(task)->status & TS_COMPAT) 169c3c9897cSLinus Torvalds switch (i) { 170c3c9897cSLinus Torvalds case 0: 171bb898558SAl Viro if (!n--) break; 172bb898558SAl Viro regs->bx = *args++; 173c3c9897cSLinus Torvalds case 1: 174c3c9897cSLinus Torvalds if (!n--) break; 175c3c9897cSLinus Torvalds regs->cx = *args++; 176c3c9897cSLinus Torvalds case 2: 177c3c9897cSLinus Torvalds if (!n--) break; 178c3c9897cSLinus Torvalds regs->dx = *args++; 179c3c9897cSLinus Torvalds case 3: 180c3c9897cSLinus Torvalds if (!n--) break; 181c3c9897cSLinus Torvalds regs->si = *args++; 182c3c9897cSLinus Torvalds case 4: 183c3c9897cSLinus Torvalds if (!n--) break; 184c3c9897cSLinus Torvalds regs->di = *args++; 185c3c9897cSLinus Torvalds case 5: 186c3c9897cSLinus Torvalds if (!n--) break; 187c3c9897cSLinus Torvalds regs->bp = *args++; 188c3c9897cSLinus Torvalds case 6: 189bb898558SAl Viro if (!n--) break; 190bb898558SAl Viro default: 191bb898558SAl Viro BUG(); 192c3c9897cSLinus Torvalds break; 193bb898558SAl Viro } 194bb898558SAl Viro else 195bb898558SAl Viro # endif 196c3c9897cSLinus Torvalds switch (i) { 197c3c9897cSLinus Torvalds case 0: 198bb898558SAl Viro if (!n--) break; 199bb898558SAl Viro regs->di = *args++; 200c3c9897cSLinus Torvalds case 1: 201c3c9897cSLinus Torvalds if (!n--) break; 202c3c9897cSLinus Torvalds regs->si = *args++; 203c3c9897cSLinus Torvalds case 2: 204c3c9897cSLinus Torvalds if (!n--) break; 205c3c9897cSLinus Torvalds regs->dx = *args++; 206c3c9897cSLinus Torvalds case 3: 207c3c9897cSLinus Torvalds if (!n--) break; 208c3c9897cSLinus Torvalds regs->r10 = *args++; 209c3c9897cSLinus Torvalds case 4: 210c3c9897cSLinus Torvalds if (!n--) break; 211c3c9897cSLinus Torvalds regs->r8 = *args++; 212c3c9897cSLinus Torvalds case 5: 213c3c9897cSLinus Torvalds if (!n--) break; 214c3c9897cSLinus Torvalds regs->r9 = *args++; 215c3c9897cSLinus Torvalds case 6: 216bb898558SAl Viro if (!n--) break; 217bb898558SAl Viro default: 218bb898558SAl Viro BUG(); 219c3c9897cSLinus Torvalds break; 220bb898558SAl Viro } 221bb898558SAl Viro } 222bb898558SAl Viro 2235e937a9aSEric Paris static inline int syscall_get_arch(void) 224b7456536SWill Drewry { 225b7456536SWill Drewry #ifdef CONFIG_IA32_EMULATION 226b7456536SWill Drewry /* 227b7456536SWill Drewry * TS_COMPAT is set for 32-bit syscall entry and then 228b7456536SWill Drewry * remains set until we return to user mode. 229b7456536SWill Drewry * 230b7456536SWill Drewry * TIF_IA32 tasks should always have TS_COMPAT set at 231b7456536SWill Drewry * system call time. 232b7456536SWill Drewry * 233b7456536SWill Drewry * x32 tasks should be considered AUDIT_ARCH_X86_64. 234b7456536SWill Drewry */ 2355e937a9aSEric Paris if (task_thread_info(current)->status & TS_COMPAT) 236b7456536SWill Drewry return AUDIT_ARCH_I386; 237b7456536SWill Drewry #endif 238b7456536SWill Drewry /* Both x32 and x86_64 are considered "64-bit". */ 239b7456536SWill Drewry return AUDIT_ARCH_X86_64; 240b7456536SWill Drewry } 241bb898558SAl Viro #endif /* CONFIG_X86_32 */ 242bb898558SAl Viro 2435e1b0075SH. Peter Anvin #endif /* _ASM_X86_SYSCALL_H */ 244