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