1 /* 2 * Access to user system call parameters and results 3 * 4 * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. 5 * 6 * This copyrighted material is made available to anyone wishing to use, 7 * modify, copy, or redistribute it subject to the terms and conditions 8 * of the GNU General Public License v.2. 9 * 10 * See asm-generic/syscall.h for descriptions of what we must do here. 11 */ 12 13 #ifndef _ASM_X86_SYSCALL_H 14 #define _ASM_X86_SYSCALL_H 15 16 #include <uapi/linux/audit.h> 17 #include <linux/sched.h> 18 #include <linux/err.h> 19 #include <asm/asm-offsets.h> /* For NR_syscalls */ 20 #include <asm/thread_info.h> /* for TS_COMPAT */ 21 #include <asm/unistd.h> 22 23 typedef asmlinkage long (*sys_call_ptr_t)(unsigned long, unsigned long, 24 unsigned long, unsigned long, 25 unsigned long, unsigned long); 26 extern const sys_call_ptr_t sys_call_table[]; 27 28 #if defined(CONFIG_X86_32) 29 #define ia32_sys_call_table sys_call_table 30 #define __NR_syscall_compat_max __NR_syscall_max 31 #define IA32_NR_syscalls NR_syscalls 32 #endif 33 34 #if defined(CONFIG_IA32_EMULATION) 35 extern const sys_call_ptr_t ia32_sys_call_table[]; 36 #endif 37 38 /* 39 * Only the low 32 bits of orig_ax are meaningful, so we return int. 40 * This importantly ignores the high bits on 64-bit, so comparisons 41 * sign-extend the low 32 bits. 42 */ 43 static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) 44 { 45 return regs->orig_ax; 46 } 47 48 static inline void syscall_rollback(struct task_struct *task, 49 struct pt_regs *regs) 50 { 51 regs->ax = regs->orig_ax; 52 } 53 54 static inline long syscall_get_error(struct task_struct *task, 55 struct pt_regs *regs) 56 { 57 unsigned long error = regs->ax; 58 #ifdef CONFIG_IA32_EMULATION 59 /* 60 * TS_COMPAT is set for 32-bit syscall entries and then 61 * remains set until we return to user mode. 62 */ 63 if (task->thread.status & (TS_COMPAT|TS_I386_REGS_POKED)) 64 /* 65 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO 66 * and will match correctly in comparisons. 67 */ 68 error = (long) (int) error; 69 #endif 70 return IS_ERR_VALUE(error) ? error : 0; 71 } 72 73 static inline long syscall_get_return_value(struct task_struct *task, 74 struct pt_regs *regs) 75 { 76 return regs->ax; 77 } 78 79 static inline void syscall_set_return_value(struct task_struct *task, 80 struct pt_regs *regs, 81 int error, long val) 82 { 83 regs->ax = (long) error ?: val; 84 } 85 86 #ifdef CONFIG_X86_32 87 88 static inline void syscall_get_arguments(struct task_struct *task, 89 struct pt_regs *regs, 90 unsigned int i, unsigned int n, 91 unsigned long *args) 92 { 93 BUG_ON(i + n > 6); 94 memcpy(args, ®s->bx + i, n * sizeof(args[0])); 95 } 96 97 static inline void syscall_set_arguments(struct task_struct *task, 98 struct pt_regs *regs, 99 unsigned int i, unsigned int n, 100 const unsigned long *args) 101 { 102 BUG_ON(i + n > 6); 103 memcpy(®s->bx + i, args, n * sizeof(args[0])); 104 } 105 106 static inline int syscall_get_arch(void) 107 { 108 return AUDIT_ARCH_I386; 109 } 110 111 #else /* CONFIG_X86_64 */ 112 113 static inline void syscall_get_arguments(struct task_struct *task, 114 struct pt_regs *regs, 115 unsigned int i, unsigned int n, 116 unsigned long *args) 117 { 118 # ifdef CONFIG_IA32_EMULATION 119 if (task->thread.status & TS_COMPAT) 120 switch (i) { 121 case 0: 122 if (!n--) break; 123 *args++ = regs->bx; 124 case 1: 125 if (!n--) break; 126 *args++ = regs->cx; 127 case 2: 128 if (!n--) break; 129 *args++ = regs->dx; 130 case 3: 131 if (!n--) break; 132 *args++ = regs->si; 133 case 4: 134 if (!n--) break; 135 *args++ = regs->di; 136 case 5: 137 if (!n--) break; 138 *args++ = regs->bp; 139 case 6: 140 if (!n--) break; 141 default: 142 BUG(); 143 break; 144 } 145 else 146 # endif 147 switch (i) { 148 case 0: 149 if (!n--) break; 150 *args++ = regs->di; 151 case 1: 152 if (!n--) break; 153 *args++ = regs->si; 154 case 2: 155 if (!n--) break; 156 *args++ = regs->dx; 157 case 3: 158 if (!n--) break; 159 *args++ = regs->r10; 160 case 4: 161 if (!n--) break; 162 *args++ = regs->r8; 163 case 5: 164 if (!n--) break; 165 *args++ = regs->r9; 166 case 6: 167 if (!n--) break; 168 default: 169 BUG(); 170 break; 171 } 172 } 173 174 static inline void syscall_set_arguments(struct task_struct *task, 175 struct pt_regs *regs, 176 unsigned int i, unsigned int n, 177 const unsigned long *args) 178 { 179 # ifdef CONFIG_IA32_EMULATION 180 if (task->thread.status & TS_COMPAT) 181 switch (i) { 182 case 0: 183 if (!n--) break; 184 regs->bx = *args++; 185 case 1: 186 if (!n--) break; 187 regs->cx = *args++; 188 case 2: 189 if (!n--) break; 190 regs->dx = *args++; 191 case 3: 192 if (!n--) break; 193 regs->si = *args++; 194 case 4: 195 if (!n--) break; 196 regs->di = *args++; 197 case 5: 198 if (!n--) break; 199 regs->bp = *args++; 200 case 6: 201 if (!n--) break; 202 default: 203 BUG(); 204 break; 205 } 206 else 207 # endif 208 switch (i) { 209 case 0: 210 if (!n--) break; 211 regs->di = *args++; 212 case 1: 213 if (!n--) break; 214 regs->si = *args++; 215 case 2: 216 if (!n--) break; 217 regs->dx = *args++; 218 case 3: 219 if (!n--) break; 220 regs->r10 = *args++; 221 case 4: 222 if (!n--) break; 223 regs->r8 = *args++; 224 case 5: 225 if (!n--) break; 226 regs->r9 = *args++; 227 case 6: 228 if (!n--) break; 229 default: 230 BUG(); 231 break; 232 } 233 } 234 235 static inline int syscall_get_arch(void) 236 { 237 /* x32 tasks should be considered AUDIT_ARCH_X86_64. */ 238 return in_ia32_syscall() ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64; 239 } 240 #endif /* CONFIG_X86_32 */ 241 242 #endif /* _ASM_X86_SYSCALL_H */ 243