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 memcpy(args, ®s->bx, 6 * sizeof(args[0])); 86 } 87 88 static inline int syscall_get_arch(struct task_struct *task) 89 { 90 return AUDIT_ARCH_I386; 91 } 92 93 #else /* CONFIG_X86_64 */ 94 95 static inline void syscall_get_arguments(struct task_struct *task, 96 struct pt_regs *regs, 97 unsigned long *args) 98 { 99 # ifdef CONFIG_IA32_EMULATION 100 if (task->thread_info.status & TS_COMPAT) { 101 *args++ = regs->bx; 102 *args++ = regs->cx; 103 *args++ = regs->dx; 104 *args++ = regs->si; 105 *args++ = regs->di; 106 *args = regs->bp; 107 } else 108 # endif 109 { 110 *args++ = regs->di; 111 *args++ = regs->si; 112 *args++ = regs->dx; 113 *args++ = regs->r10; 114 *args++ = regs->r8; 115 *args = regs->r9; 116 } 117 } 118 119 static inline int syscall_get_arch(struct task_struct *task) 120 { 121 /* x32 tasks should be considered AUDIT_ARCH_X86_64. */ 122 return (IS_ENABLED(CONFIG_IA32_EMULATION) && 123 task->thread_info.status & TS_COMPAT) 124 ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64; 125 } 126 127 void do_syscall_64(struct pt_regs *regs, int nr); 128 void do_int80_emulation(struct pt_regs *regs); 129 130 #endif /* CONFIG_X86_32 */ 131 132 void do_int80_syscall_32(struct pt_regs *regs); 133 long do_fast_syscall_32(struct pt_regs *regs); 134 long do_SYSENTER_32(struct pt_regs *regs); 135 136 #endif /* _ASM_X86_SYSCALL_H */ 137