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 #endif 25 26 #if defined(CONFIG_IA32_EMULATION) 27 extern const sys_call_ptr_t ia32_sys_call_table[]; 28 #endif 29 30 #ifdef CONFIG_X86_X32_ABI 31 extern const sys_call_ptr_t x32_sys_call_table[]; 32 #endif 33 34 /* 35 * Only the low 32 bits of orig_ax are meaningful, so we return int. 36 * This importantly ignores the high bits on 64-bit, so comparisons 37 * sign-extend the low 32 bits. 38 */ 39 static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) 40 { 41 return regs->orig_ax; 42 } 43 44 static inline void syscall_rollback(struct task_struct *task, 45 struct pt_regs *regs) 46 { 47 regs->ax = regs->orig_ax; 48 } 49 50 static inline long syscall_get_error(struct task_struct *task, 51 struct pt_regs *regs) 52 { 53 unsigned long error = regs->ax; 54 #ifdef CONFIG_IA32_EMULATION 55 /* 56 * TS_COMPAT is set for 32-bit syscall entries and then 57 * remains set until we return to user mode. 58 */ 59 if (task->thread_info.status & (TS_COMPAT|TS_I386_REGS_POKED)) 60 /* 61 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO 62 * and will match correctly in comparisons. 63 */ 64 error = (long) (int) error; 65 #endif 66 return IS_ERR_VALUE(error) ? error : 0; 67 } 68 69 static inline long syscall_get_return_value(struct task_struct *task, 70 struct pt_regs *regs) 71 { 72 return regs->ax; 73 } 74 75 static inline void syscall_set_return_value(struct task_struct *task, 76 struct pt_regs *regs, 77 int error, long val) 78 { 79 regs->ax = (long) error ?: val; 80 } 81 82 #ifdef CONFIG_X86_32 83 84 static inline void syscall_get_arguments(struct task_struct *task, 85 struct pt_regs *regs, 86 unsigned long *args) 87 { 88 memcpy(args, ®s->bx, 6 * sizeof(args[0])); 89 } 90 91 static inline void syscall_set_arguments(struct task_struct *task, 92 struct pt_regs *regs, 93 unsigned int i, unsigned int n, 94 const unsigned long *args) 95 { 96 BUG_ON(i + n > 6); 97 memcpy(®s->bx + i, args, n * sizeof(args[0])); 98 } 99 100 static inline int syscall_get_arch(struct task_struct *task) 101 { 102 return AUDIT_ARCH_I386; 103 } 104 105 #else /* CONFIG_X86_64 */ 106 107 static inline void syscall_get_arguments(struct task_struct *task, 108 struct pt_regs *regs, 109 unsigned long *args) 110 { 111 # ifdef CONFIG_IA32_EMULATION 112 if (task->thread_info.status & TS_COMPAT) { 113 *args++ = regs->bx; 114 *args++ = regs->cx; 115 *args++ = regs->dx; 116 *args++ = regs->si; 117 *args++ = regs->di; 118 *args = regs->bp; 119 } else 120 # endif 121 { 122 *args++ = regs->di; 123 *args++ = regs->si; 124 *args++ = regs->dx; 125 *args++ = regs->r10; 126 *args++ = regs->r8; 127 *args = regs->r9; 128 } 129 } 130 131 static inline void syscall_set_arguments(struct task_struct *task, 132 struct pt_regs *regs, 133 const unsigned long *args) 134 { 135 # ifdef CONFIG_IA32_EMULATION 136 if (task->thread_info.status & TS_COMPAT) { 137 regs->bx = *args++; 138 regs->cx = *args++; 139 regs->dx = *args++; 140 regs->si = *args++; 141 regs->di = *args++; 142 regs->bp = *args; 143 } else 144 # endif 145 { 146 regs->di = *args++; 147 regs->si = *args++; 148 regs->dx = *args++; 149 regs->r10 = *args++; 150 regs->r8 = *args++; 151 regs->r9 = *args; 152 } 153 } 154 155 static inline int syscall_get_arch(struct task_struct *task) 156 { 157 /* x32 tasks should be considered AUDIT_ARCH_X86_64. */ 158 return (IS_ENABLED(CONFIG_IA32_EMULATION) && 159 task->thread_info.status & TS_COMPAT) 160 ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64; 161 } 162 163 void do_syscall_64(unsigned long nr, struct pt_regs *regs); 164 void do_int80_syscall_32(struct pt_regs *regs); 165 long do_fast_syscall_32(struct pt_regs *regs); 166 167 #endif /* CONFIG_X86_32 */ 168 169 #endif /* _ASM_X86_SYSCALL_H */ 170