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 23typedef void (*sys_call_ptr_t)(void); 24extern 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 */ 31static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) 32{ 33 return regs->orig_ax; 34} 35 36static inline void syscall_rollback(struct task_struct *task, 37 struct pt_regs *regs) 38{ 39 regs->ax = regs->orig_ax; 40} 41 42static 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 61static inline long syscall_get_return_value(struct task_struct *task, 62 struct pt_regs *regs) 63{ 64 return regs->ax; 65} 66 67static 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 76static 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 85static 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 94static inline int syscall_get_arch(void) 95{ 96 return AUDIT_ARCH_I386; 97} 98 99#else /* CONFIG_X86_64 */ 100 101static 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 162static 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 223static 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