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 /* This is used purely for kernel/trace/trace_syscalls.c */ 20 typedef long (*sys_call_ptr_t)(const struct pt_regs *); 21 extern const sys_call_ptr_t sys_call_table[]; 22 23 /* 24 * These may not exist, but still put the prototypes in so we 25 * can use IS_ENABLED(). 26 */ 27 extern long ia32_sys_call(const struct pt_regs *, unsigned int nr); 28 extern long x32_sys_call(const struct pt_regs *, unsigned int nr); 29 extern long x64_sys_call(const struct pt_regs *, unsigned int nr); 30 31 /* 32 * Only the low 32 bits of orig_ax are meaningful, so we return int. 33 * This importantly ignores the high bits on 64-bit, so comparisons 34 * sign-extend the low 32 bits. 35 */ 36 static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) 37 { 38 return regs->orig_ax; 39 } 40 41 static inline void syscall_rollback(struct task_struct *task, 42 struct pt_regs *regs) 43 { 44 regs->ax = regs->orig_ax; 45 } 46 47 static inline long syscall_get_error(struct task_struct *task, 48 struct pt_regs *regs) 49 { 50 unsigned long error = regs->ax; 51 #ifdef CONFIG_IA32_EMULATION 52 /* 53 * TS_COMPAT is set for 32-bit syscall entries and then 54 * remains set until we return to user mode. 55 */ 56 if (task->thread_info.status & (TS_COMPAT|TS_I386_REGS_POKED)) 57 /* 58 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO 59 * and will match correctly in comparisons. 60 */ 61 error = (long) (int) error; 62 #endif 63 return IS_ERR_VALUE(error) ? error : 0; 64 } 65 66 static inline long syscall_get_return_value(struct task_struct *task, 67 struct pt_regs *regs) 68 { 69 return regs->ax; 70 } 71 72 static inline void syscall_set_return_value(struct task_struct *task, 73 struct pt_regs *regs, 74 int error, long val) 75 { 76 regs->ax = (long) error ?: val; 77 } 78 79 #ifdef CONFIG_X86_32 80 81 static inline void syscall_get_arguments(struct task_struct *task, 82 struct pt_regs *regs, 83 unsigned long *args) 84 { 85 args[0] = regs->bx; 86 args[1] = regs->cx; 87 args[2] = regs->dx; 88 args[3] = regs->si; 89 args[4] = regs->di; 90 args[5] = regs->bp; 91 } 92 93 static inline int syscall_get_arch(struct task_struct *task) 94 { 95 return AUDIT_ARCH_I386; 96 } 97 98 #else /* CONFIG_X86_64 */ 99 100 static inline void syscall_get_arguments(struct task_struct *task, 101 struct pt_regs *regs, 102 unsigned long *args) 103 { 104 # ifdef CONFIG_IA32_EMULATION 105 if (task->thread_info.status & TS_COMPAT) { 106 *args++ = regs->bx; 107 *args++ = regs->cx; 108 *args++ = regs->dx; 109 *args++ = regs->si; 110 *args++ = regs->di; 111 *args = regs->bp; 112 } else 113 # endif 114 { 115 *args++ = regs->di; 116 *args++ = regs->si; 117 *args++ = regs->dx; 118 *args++ = regs->r10; 119 *args++ = regs->r8; 120 *args = regs->r9; 121 } 122 } 123 124 static inline int syscall_get_arch(struct task_struct *task) 125 { 126 /* x32 tasks should be considered AUDIT_ARCH_X86_64. */ 127 return (IS_ENABLED(CONFIG_IA32_EMULATION) && 128 task->thread_info.status & TS_COMPAT) 129 ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64; 130 } 131 132 void do_syscall_64(struct pt_regs *regs, int nr); 133 void do_int80_emulation(struct pt_regs *regs); 134 135 #endif /* CONFIG_X86_32 */ 136 137 void do_int80_syscall_32(struct pt_regs *regs); 138 long do_fast_syscall_32(struct pt_regs *regs); 139 long do_SYSENTER_32(struct pt_regs *regs); 140 141 #endif /* _ASM_X86_SYSCALL_H */ 142