1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Access to user system call parameters and results 4 * 5 * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. 6 * 7 * See asm-generic/syscall.h for descriptions of what we must do here. 8 */ 9 10 #ifndef _ASM_X86_SYSCALL_H 11 #define _ASM_X86_SYSCALL_H 12 13 #include <uapi/linux/audit.h> 14 #include <linux/sched.h> 15 #include <linux/err.h> 16 #include <asm/thread_info.h> /* for TS_COMPAT */ 17 #include <asm/unistd.h> 18 19 typedef long (*sys_call_ptr_t)(const struct pt_regs *); 20 extern const sys_call_ptr_t sys_call_table[]; 21 22 #if defined(CONFIG_X86_32) 23 #define ia32_sys_call_table sys_call_table 24 #else 25 /* 26 * These may not exist, but still put the prototypes in so we 27 * can use IS_ENABLED(). 28 */ 29 extern const sys_call_ptr_t ia32_sys_call_table[]; 30 extern const sys_call_ptr_t x32_sys_call_table[]; 31 #endif 32 33 /* 34 * Only the low 32 bits of orig_ax are meaningful, so we return int. 35 * This importantly ignores the high bits on 64-bit, so comparisons 36 * sign-extend the low 32 bits. 37 */ 38 static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) 39 { 40 return regs->orig_ax; 41 } 42 43 static inline void syscall_rollback(struct task_struct *task, 44 struct pt_regs *regs) 45 { 46 regs->ax = regs->orig_ax; 47 } 48 49 static inline long syscall_get_error(struct task_struct *task, 50 struct pt_regs *regs) 51 { 52 unsigned long error = regs->ax; 53 #ifdef CONFIG_IA32_EMULATION 54 /* 55 * TS_COMPAT is set for 32-bit syscall entries and then 56 * remains set until we return to user mode. 57 */ 58 if (task->thread_info.status & (TS_COMPAT|TS_I386_REGS_POKED)) 59 /* 60 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO 61 * and will match correctly in comparisons. 62 */ 63 error = (long) (int) error; 64 #endif 65 return IS_ERR_VALUE(error) ? error : 0; 66 } 67 68 static inline long syscall_get_return_value(struct task_struct *task, 69 struct pt_regs *regs) 70 { 71 return regs->ax; 72 } 73 74 static inline void syscall_set_return_value(struct task_struct *task, 75 struct pt_regs *regs, 76 int error, long val) 77 { 78 regs->ax = (long) error ?: val; 79 } 80 81 #ifdef CONFIG_X86_32 82 83 static inline void syscall_get_arguments(struct task_struct *task, 84 struct pt_regs *regs, 85 unsigned long *args) 86 { 87 memcpy(args, ®s->bx, 6 * sizeof(args[0])); 88 } 89 90 static inline void syscall_set_arguments(struct task_struct *task, 91 struct pt_regs *regs, 92 unsigned int i, unsigned int n, 93 const unsigned long *args) 94 { 95 BUG_ON(i + n > 6); 96 memcpy(®s->bx + i, args, n * sizeof(args[0])); 97 } 98 99 static inline int syscall_get_arch(struct task_struct *task) 100 { 101 return AUDIT_ARCH_I386; 102 } 103 104 #else /* CONFIG_X86_64 */ 105 106 static inline void syscall_get_arguments(struct task_struct *task, 107 struct pt_regs *regs, 108 unsigned long *args) 109 { 110 # ifdef CONFIG_IA32_EMULATION 111 if (task->thread_info.status & TS_COMPAT) { 112 *args++ = regs->bx; 113 *args++ = regs->cx; 114 *args++ = regs->dx; 115 *args++ = regs->si; 116 *args++ = regs->di; 117 *args = regs->bp; 118 } else 119 # endif 120 { 121 *args++ = regs->di; 122 *args++ = regs->si; 123 *args++ = regs->dx; 124 *args++ = regs->r10; 125 *args++ = regs->r8; 126 *args = regs->r9; 127 } 128 } 129 130 static inline void syscall_set_arguments(struct task_struct *task, 131 struct pt_regs *regs, 132 const unsigned long *args) 133 { 134 # ifdef CONFIG_IA32_EMULATION 135 if (task->thread_info.status & TS_COMPAT) { 136 regs->bx = *args++; 137 regs->cx = *args++; 138 regs->dx = *args++; 139 regs->si = *args++; 140 regs->di = *args++; 141 regs->bp = *args; 142 } else 143 # endif 144 { 145 regs->di = *args++; 146 regs->si = *args++; 147 regs->dx = *args++; 148 regs->r10 = *args++; 149 regs->r8 = *args++; 150 regs->r9 = *args; 151 } 152 } 153 154 static inline int syscall_get_arch(struct task_struct *task) 155 { 156 /* x32 tasks should be considered AUDIT_ARCH_X86_64. */ 157 return (IS_ENABLED(CONFIG_IA32_EMULATION) && 158 task->thread_info.status & TS_COMPAT) 159 ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64; 160 } 161 162 void do_syscall_64(struct pt_regs *regs, int nr); 163 void do_int80_syscall_32(struct pt_regs *regs); 164 long do_fast_syscall_32(struct pt_regs *regs); 165 166 #endif /* CONFIG_X86_32 */ 167 168 #endif /* _ASM_X86_SYSCALL_H */ 169