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