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 <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(struct task_struct *task, 95 struct pt_regs *regs) 96 { 97 return AUDIT_ARCH_I386; 98 } 99 100 #else /* CONFIG_X86_64 */ 101 102 static inline void syscall_get_arguments(struct task_struct *task, 103 struct pt_regs *regs, 104 unsigned int i, unsigned int n, 105 unsigned long *args) 106 { 107 # ifdef CONFIG_IA32_EMULATION 108 if (task_thread_info(task)->status & TS_COMPAT) 109 switch (i) { 110 case 0: 111 if (!n--) break; 112 *args++ = regs->bx; 113 case 1: 114 if (!n--) break; 115 *args++ = regs->cx; 116 case 2: 117 if (!n--) break; 118 *args++ = regs->dx; 119 case 3: 120 if (!n--) break; 121 *args++ = regs->si; 122 case 4: 123 if (!n--) break; 124 *args++ = regs->di; 125 case 5: 126 if (!n--) break; 127 *args++ = regs->bp; 128 case 6: 129 if (!n--) break; 130 default: 131 BUG(); 132 break; 133 } 134 else 135 # endif 136 switch (i) { 137 case 0: 138 if (!n--) break; 139 *args++ = regs->di; 140 case 1: 141 if (!n--) break; 142 *args++ = regs->si; 143 case 2: 144 if (!n--) break; 145 *args++ = regs->dx; 146 case 3: 147 if (!n--) break; 148 *args++ = regs->r10; 149 case 4: 150 if (!n--) break; 151 *args++ = regs->r8; 152 case 5: 153 if (!n--) break; 154 *args++ = regs->r9; 155 case 6: 156 if (!n--) break; 157 default: 158 BUG(); 159 break; 160 } 161 } 162 163 static inline void syscall_set_arguments(struct task_struct *task, 164 struct pt_regs *regs, 165 unsigned int i, unsigned int n, 166 const unsigned long *args) 167 { 168 # ifdef CONFIG_IA32_EMULATION 169 if (task_thread_info(task)->status & TS_COMPAT) 170 switch (i) { 171 case 0: 172 if (!n--) break; 173 regs->bx = *args++; 174 case 1: 175 if (!n--) break; 176 regs->cx = *args++; 177 case 2: 178 if (!n--) break; 179 regs->dx = *args++; 180 case 3: 181 if (!n--) break; 182 regs->si = *args++; 183 case 4: 184 if (!n--) break; 185 regs->di = *args++; 186 case 5: 187 if (!n--) break; 188 regs->bp = *args++; 189 case 6: 190 if (!n--) break; 191 default: 192 BUG(); 193 break; 194 } 195 else 196 # endif 197 switch (i) { 198 case 0: 199 if (!n--) break; 200 regs->di = *args++; 201 case 1: 202 if (!n--) break; 203 regs->si = *args++; 204 case 2: 205 if (!n--) break; 206 regs->dx = *args++; 207 case 3: 208 if (!n--) break; 209 regs->r10 = *args++; 210 case 4: 211 if (!n--) break; 212 regs->r8 = *args++; 213 case 5: 214 if (!n--) break; 215 regs->r9 = *args++; 216 case 6: 217 if (!n--) break; 218 default: 219 BUG(); 220 break; 221 } 222 } 223 224 static inline int syscall_get_arch(struct task_struct *task, 225 struct pt_regs *regs) 226 { 227 #ifdef CONFIG_IA32_EMULATION 228 /* 229 * TS_COMPAT is set for 32-bit syscall entry and then 230 * remains set until we return to user mode. 231 * 232 * TIF_IA32 tasks should always have TS_COMPAT set at 233 * system call time. 234 * 235 * x32 tasks should be considered AUDIT_ARCH_X86_64. 236 */ 237 if (task_thread_info(task)->status & TS_COMPAT) 238 return AUDIT_ARCH_I386; 239 #endif 240 /* Both x32 and x86_64 are considered "64-bit". */ 241 return AUDIT_ARCH_X86_64; 242 } 243 #endif /* CONFIG_X86_32 */ 244 245 #endif /* _ASM_X86_SYSCALL_H */ 246