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 extern const unsigned long sys_call_table[]; 24 25 /* 26 * Only the low 32 bits of orig_ax are meaningful, so we return int. 27 * This importantly ignores the high bits on 64-bit, so comparisons 28 * sign-extend the low 32 bits. 29 */ 30 static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) 31 { 32 return regs->orig_ax; 33 } 34 35 static inline void syscall_rollback(struct task_struct *task, 36 struct pt_regs *regs) 37 { 38 regs->ax = regs->orig_ax; 39 } 40 41 static inline long syscall_get_error(struct task_struct *task, 42 struct pt_regs *regs) 43 { 44 unsigned long error = regs->ax; 45 #ifdef CONFIG_IA32_EMULATION 46 /* 47 * TS_COMPAT is set for 32-bit syscall entries and then 48 * remains set until we return to user mode. 49 */ 50 if (task_thread_info(task)->status & TS_COMPAT) 51 /* 52 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO 53 * and will match correctly in comparisons. 54 */ 55 error = (long) (int) error; 56 #endif 57 return IS_ERR_VALUE(error) ? error : 0; 58 } 59 60 static inline long syscall_get_return_value(struct task_struct *task, 61 struct pt_regs *regs) 62 { 63 return regs->ax; 64 } 65 66 static inline void syscall_set_return_value(struct task_struct *task, 67 struct pt_regs *regs, 68 int error, long val) 69 { 70 regs->ax = (long) error ?: val; 71 } 72 73 #ifdef CONFIG_X86_32 74 75 static inline void syscall_get_arguments(struct task_struct *task, 76 struct pt_regs *regs, 77 unsigned int i, unsigned int n, 78 unsigned long *args) 79 { 80 BUG_ON(i + n > 6); 81 memcpy(args, ®s->bx + i, n * sizeof(args[0])); 82 } 83 84 static inline void syscall_set_arguments(struct task_struct *task, 85 struct pt_regs *regs, 86 unsigned int i, unsigned int n, 87 const unsigned long *args) 88 { 89 BUG_ON(i + n > 6); 90 memcpy(®s->bx + i, args, n * sizeof(args[0])); 91 } 92 93 static inline int syscall_get_arch(struct task_struct *task, 94 struct pt_regs *regs) 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(struct task_struct *task, 224 struct pt_regs *regs) 225 { 226 #ifdef CONFIG_IA32_EMULATION 227 /* 228 * TS_COMPAT is set for 32-bit syscall entry and then 229 * remains set until we return to user mode. 230 * 231 * TIF_IA32 tasks should always have TS_COMPAT set at 232 * system call time. 233 * 234 * x32 tasks should be considered AUDIT_ARCH_X86_64. 235 */ 236 if (task_thread_info(task)->status & TS_COMPAT) 237 return AUDIT_ARCH_I386; 238 #endif 239 /* Both x32 and x86_64 are considered "64-bit". */ 240 return AUDIT_ARCH_X86_64; 241 } 242 #endif /* CONFIG_X86_32 */ 243 244 #endif /* _ASM_X86_SYSCALL_H */ 245