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/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 297236 : static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) 40 : { 41 297236 : return regs->orig_ax; 42 : } 43 : 44 0 : static inline void syscall_rollback(struct task_struct *task, 45 : struct pt_regs *regs) 46 : { 47 0 : regs->ax = regs->orig_ax; 48 : } 49 : 50 1284 : static inline long syscall_get_error(struct task_struct *task, 51 : struct pt_regs *regs) 52 : { 53 1284 : 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 1284 : 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 0 : error = (long) (int) error; 65 : #endif 66 1284 : return IS_ERR_VALUE(error) ? error : 0; 67 : } 68 : 69 0 : static inline long syscall_get_return_value(struct task_struct *task, 70 : struct pt_regs *regs) 71 : { 72 0 : 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 0 : 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 0 : if (task->thread_info.status & TS_COMPAT) { 113 0 : *args++ = regs->bx; 114 0 : *args++ = regs->cx; 115 0 : *args++ = regs->dx; 116 0 : *args++ = regs->si; 117 0 : *args++ = regs->di; 118 0 : *args = regs->bp; 119 : } else 120 : # endif 121 : { 122 0 : *args++ = regs->di; 123 0 : *args++ = regs->si; 124 0 : *args++ = regs->dx; 125 0 : *args++ = regs->r10; 126 0 : *args++ = regs->r8; 127 0 : *args = regs->r9; 128 : } 129 0 : } 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 0 : static inline int syscall_get_arch(struct task_struct *task) 156 : { 157 : /* x32 tasks should be considered AUDIT_ARCH_X86_64. */ 158 0 : return (IS_ENABLED(CONFIG_IA32_EMULATION) && 159 0 : task->thread_info.status & TS_COMPAT) 160 0 : ? 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 */