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 16b7456536SWill Drewry #include <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 23e7b8e675SMike Frysinger extern const unsigned long sys_call_table[]; 24e7b8e675SMike Frysinger 25bb898558SAl Viro /* 2618c1e2c8SRoland McGrath * Only the low 32 bits of orig_ax are meaningful, so we return int. 2718c1e2c8SRoland McGrath * This importantly ignores the high bits on 64-bit, so comparisons 2818c1e2c8SRoland McGrath * sign-extend the low 32 bits. 29bb898558SAl Viro */ 3018c1e2c8SRoland McGrath static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) 3118c1e2c8SRoland McGrath { 32*8b4b9f27SPaul Moore return regs->orig_ax; 33bb898558SAl Viro } 34bb898558SAl Viro 35bb898558SAl Viro static inline void syscall_rollback(struct task_struct *task, 36bb898558SAl Viro struct pt_regs *regs) 37bb898558SAl Viro { 38*8b4b9f27SPaul Moore regs->ax = regs->orig_ax; 39bb898558SAl Viro } 40bb898558SAl Viro 41bb898558SAl Viro static inline long syscall_get_error(struct task_struct *task, 42bb898558SAl Viro struct pt_regs *regs) 43bb898558SAl Viro { 44bb898558SAl Viro unsigned long error = regs->ax; 45bb898558SAl Viro #ifdef CONFIG_IA32_EMULATION 46bb898558SAl Viro /* 47bb898558SAl Viro * TS_COMPAT is set for 32-bit syscall entries and then 48bb898558SAl Viro * remains set until we return to user mode. 49bb898558SAl Viro */ 50bb898558SAl Viro if (task_thread_info(task)->status & TS_COMPAT) 51bb898558SAl Viro /* 52bb898558SAl Viro * Sign-extend the value so (int)-EFOO becomes (long)-EFOO 53bb898558SAl Viro * and will match correctly in comparisons. 54bb898558SAl Viro */ 55bb898558SAl Viro error = (long) (int) error; 56bb898558SAl Viro #endif 57bb898558SAl Viro return IS_ERR_VALUE(error) ? error : 0; 58bb898558SAl Viro } 59bb898558SAl Viro 60bb898558SAl Viro static inline long syscall_get_return_value(struct task_struct *task, 61bb898558SAl Viro struct pt_regs *regs) 62bb898558SAl Viro { 63bb898558SAl Viro return regs->ax; 64bb898558SAl Viro } 65bb898558SAl Viro 66bb898558SAl Viro static inline void syscall_set_return_value(struct task_struct *task, 67bb898558SAl Viro struct pt_regs *regs, 68bb898558SAl Viro int error, long val) 69bb898558SAl Viro { 70bb898558SAl Viro regs->ax = (long) error ?: val; 71bb898558SAl Viro } 72bb898558SAl Viro 73bb898558SAl Viro #ifdef CONFIG_X86_32 74bb898558SAl Viro 75bb898558SAl Viro static inline void syscall_get_arguments(struct task_struct *task, 76bb898558SAl Viro struct pt_regs *regs, 77bb898558SAl Viro unsigned int i, unsigned int n, 78bb898558SAl Viro unsigned long *args) 79bb898558SAl Viro { 80bb898558SAl Viro BUG_ON(i + n > 6); 81bb898558SAl Viro memcpy(args, ®s->bx + i, n * sizeof(args[0])); 82bb898558SAl Viro } 83bb898558SAl Viro 84bb898558SAl Viro static inline void syscall_set_arguments(struct task_struct *task, 85bb898558SAl Viro struct pt_regs *regs, 86bb898558SAl Viro unsigned int i, unsigned int n, 87bb898558SAl Viro const unsigned long *args) 88bb898558SAl Viro { 89bb898558SAl Viro BUG_ON(i + n > 6); 90bb898558SAl Viro memcpy(®s->bx + i, args, n * sizeof(args[0])); 91bb898558SAl Viro } 92bb898558SAl Viro 93b7456536SWill Drewry static inline int syscall_get_arch(struct task_struct *task, 94b7456536SWill Drewry struct pt_regs *regs) 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 223b7456536SWill Drewry static inline int syscall_get_arch(struct task_struct *task, 224b7456536SWill Drewry struct pt_regs *regs) 225b7456536SWill Drewry { 226b7456536SWill Drewry #ifdef CONFIG_IA32_EMULATION 227b7456536SWill Drewry /* 228b7456536SWill Drewry * TS_COMPAT is set for 32-bit syscall entry and then 229b7456536SWill Drewry * remains set until we return to user mode. 230b7456536SWill Drewry * 231b7456536SWill Drewry * TIF_IA32 tasks should always have TS_COMPAT set at 232b7456536SWill Drewry * system call time. 233b7456536SWill Drewry * 234b7456536SWill Drewry * x32 tasks should be considered AUDIT_ARCH_X86_64. 235b7456536SWill Drewry */ 236b7456536SWill Drewry if (task_thread_info(task)->status & TS_COMPAT) 237b7456536SWill Drewry return AUDIT_ARCH_I386; 238b7456536SWill Drewry #endif 239b7456536SWill Drewry /* Both x32 and x86_64 are considered "64-bit". */ 240b7456536SWill Drewry return AUDIT_ARCH_X86_64; 241b7456536SWill Drewry } 242bb898558SAl Viro #endif /* CONFIG_X86_32 */ 243bb898558SAl Viro 2445e1b0075SH. Peter Anvin #endif /* _ASM_X86_SYSCALL_H */ 245