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