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