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