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