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 int i, unsigned int n, 95bb898558SAl Viro unsigned long *args) 96bb898558SAl Viro { 97bb898558SAl Viro BUG_ON(i + n > 6); 98bb898558SAl Viro memcpy(args, ®s->bx + i, n * sizeof(args[0])); 99bb898558SAl Viro } 100bb898558SAl Viro 101bb898558SAl Viro static inline void syscall_set_arguments(struct task_struct *task, 102bb898558SAl Viro struct pt_regs *regs, 103bb898558SAl Viro unsigned int i, unsigned int n, 104bb898558SAl Viro const unsigned long *args) 105bb898558SAl Viro { 106bb898558SAl Viro BUG_ON(i + n > 6); 107bb898558SAl Viro memcpy(®s->bx + i, args, n * sizeof(args[0])); 108bb898558SAl Viro } 109bb898558SAl Viro 110*16add411SDmitry V. Levin static inline int syscall_get_arch(struct task_struct *task) 111b7456536SWill Drewry { 112b7456536SWill Drewry return AUDIT_ARCH_I386; 113b7456536SWill Drewry } 114b7456536SWill Drewry 115bb898558SAl Viro #else /* CONFIG_X86_64 */ 116bb898558SAl Viro 117bb898558SAl Viro static inline void syscall_get_arguments(struct task_struct *task, 118bb898558SAl Viro struct pt_regs *regs, 119bb898558SAl Viro unsigned int i, unsigned int n, 120bb898558SAl Viro unsigned long *args) 121bb898558SAl Viro { 122bb898558SAl Viro # ifdef CONFIG_IA32_EMULATION 12337a8f7c3SAndy Lutomirski if (task->thread_info.status & TS_COMPAT) 124c3c9897cSLinus Torvalds switch (i) { 125c3c9897cSLinus Torvalds case 0: 126bb898558SAl Viro if (!n--) break; 127bb898558SAl Viro *args++ = regs->bx; 128c3c9897cSLinus Torvalds case 1: 129c3c9897cSLinus Torvalds if (!n--) break; 130c3c9897cSLinus Torvalds *args++ = regs->cx; 131c3c9897cSLinus Torvalds case 2: 132c3c9897cSLinus Torvalds if (!n--) break; 133c3c9897cSLinus Torvalds *args++ = regs->dx; 134c3c9897cSLinus Torvalds case 3: 135c3c9897cSLinus Torvalds if (!n--) break; 136c3c9897cSLinus Torvalds *args++ = regs->si; 137c3c9897cSLinus Torvalds case 4: 138c3c9897cSLinus Torvalds if (!n--) break; 139c3c9897cSLinus Torvalds *args++ = regs->di; 140c3c9897cSLinus Torvalds case 5: 141c3c9897cSLinus Torvalds if (!n--) break; 142c3c9897cSLinus Torvalds *args++ = regs->bp; 143c3c9897cSLinus Torvalds case 6: 144bb898558SAl Viro if (!n--) break; 145bb898558SAl Viro default: 146bb898558SAl Viro BUG(); 147bb898558SAl Viro break; 148bb898558SAl Viro } 149bb898558SAl Viro else 150bb898558SAl Viro # endif 151c3c9897cSLinus Torvalds switch (i) { 152c3c9897cSLinus Torvalds case 0: 153bb898558SAl Viro if (!n--) break; 154bb898558SAl Viro *args++ = regs->di; 155c3c9897cSLinus Torvalds case 1: 156c3c9897cSLinus Torvalds if (!n--) break; 157c3c9897cSLinus Torvalds *args++ = regs->si; 158c3c9897cSLinus Torvalds case 2: 159c3c9897cSLinus Torvalds if (!n--) break; 160c3c9897cSLinus Torvalds *args++ = regs->dx; 161c3c9897cSLinus Torvalds case 3: 162c3c9897cSLinus Torvalds if (!n--) break; 163c3c9897cSLinus Torvalds *args++ = regs->r10; 164c3c9897cSLinus Torvalds case 4: 165c3c9897cSLinus Torvalds if (!n--) break; 166c3c9897cSLinus Torvalds *args++ = regs->r8; 167c3c9897cSLinus Torvalds case 5: 168c3c9897cSLinus Torvalds if (!n--) break; 169c3c9897cSLinus Torvalds *args++ = regs->r9; 170c3c9897cSLinus Torvalds case 6: 171bb898558SAl Viro if (!n--) break; 172bb898558SAl Viro default: 173bb898558SAl Viro BUG(); 174bb898558SAl Viro break; 175bb898558SAl Viro } 176bb898558SAl Viro } 177bb898558SAl Viro 178bb898558SAl Viro static inline void syscall_set_arguments(struct task_struct *task, 179bb898558SAl Viro struct pt_regs *regs, 180bb898558SAl Viro unsigned int i, unsigned int n, 181bb898558SAl Viro const unsigned long *args) 182bb898558SAl Viro { 183bb898558SAl Viro # ifdef CONFIG_IA32_EMULATION 18437a8f7c3SAndy Lutomirski if (task->thread_info.status & TS_COMPAT) 185c3c9897cSLinus Torvalds switch (i) { 186c3c9897cSLinus Torvalds case 0: 187bb898558SAl Viro if (!n--) break; 188bb898558SAl Viro regs->bx = *args++; 189c3c9897cSLinus Torvalds case 1: 190c3c9897cSLinus Torvalds if (!n--) break; 191c3c9897cSLinus Torvalds regs->cx = *args++; 192c3c9897cSLinus Torvalds case 2: 193c3c9897cSLinus Torvalds if (!n--) break; 194c3c9897cSLinus Torvalds regs->dx = *args++; 195c3c9897cSLinus Torvalds case 3: 196c3c9897cSLinus Torvalds if (!n--) break; 197c3c9897cSLinus Torvalds regs->si = *args++; 198c3c9897cSLinus Torvalds case 4: 199c3c9897cSLinus Torvalds if (!n--) break; 200c3c9897cSLinus Torvalds regs->di = *args++; 201c3c9897cSLinus Torvalds case 5: 202c3c9897cSLinus Torvalds if (!n--) break; 203c3c9897cSLinus Torvalds regs->bp = *args++; 204c3c9897cSLinus Torvalds case 6: 205bb898558SAl Viro if (!n--) break; 206bb898558SAl Viro default: 207bb898558SAl Viro BUG(); 208c3c9897cSLinus Torvalds break; 209bb898558SAl Viro } 210bb898558SAl Viro else 211bb898558SAl Viro # endif 212c3c9897cSLinus Torvalds switch (i) { 213c3c9897cSLinus Torvalds case 0: 214bb898558SAl Viro if (!n--) break; 215bb898558SAl Viro regs->di = *args++; 216c3c9897cSLinus Torvalds case 1: 217c3c9897cSLinus Torvalds if (!n--) break; 218c3c9897cSLinus Torvalds regs->si = *args++; 219c3c9897cSLinus Torvalds case 2: 220c3c9897cSLinus Torvalds if (!n--) break; 221c3c9897cSLinus Torvalds regs->dx = *args++; 222c3c9897cSLinus Torvalds case 3: 223c3c9897cSLinus Torvalds if (!n--) break; 224c3c9897cSLinus Torvalds regs->r10 = *args++; 225c3c9897cSLinus Torvalds case 4: 226c3c9897cSLinus Torvalds if (!n--) break; 227c3c9897cSLinus Torvalds regs->r8 = *args++; 228c3c9897cSLinus Torvalds case 5: 229c3c9897cSLinus Torvalds if (!n--) break; 230c3c9897cSLinus Torvalds regs->r9 = *args++; 231c3c9897cSLinus Torvalds case 6: 232bb898558SAl Viro if (!n--) break; 233bb898558SAl Viro default: 234bb898558SAl Viro BUG(); 235c3c9897cSLinus Torvalds break; 236bb898558SAl Viro } 237bb898558SAl Viro } 238bb898558SAl Viro 239*16add411SDmitry V. Levin static inline int syscall_get_arch(struct task_struct *task) 240b7456536SWill Drewry { 241b9d989c7SAndy Lutomirski /* x32 tasks should be considered AUDIT_ARCH_X86_64. */ 242*16add411SDmitry V. Levin return (IS_ENABLED(CONFIG_IA32_EMULATION) && 243*16add411SDmitry V. Levin task->thread_info.status & TS_COMPAT) 244*16add411SDmitry V. Levin ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64; 245b7456536SWill Drewry } 246bb898558SAl Viro #endif /* CONFIG_X86_32 */ 247bb898558SAl Viro 2485e1b0075SH. Peter Anvin #endif /* _ASM_X86_SYSCALL_H */ 249