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 */ 20typedef long (*sys_call_ptr_t)(const struct pt_regs *); 21extern 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 */ 27extern long ia32_sys_call(const struct pt_regs *, unsigned int nr); 28extern long x32_sys_call(const struct pt_regs *, unsigned int nr); 29extern 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 */ 36static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) 37{ 38 return regs->orig_ax; 39} 40 41static inline void syscall_rollback(struct task_struct *task, 42 struct pt_regs *regs) 43{ 44 regs->ax = regs->orig_ax; 45} 46 47static 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 66static inline long syscall_get_return_value(struct task_struct *task, 67 struct pt_regs *regs) 68{ 69 return regs->ax; 70} 71 72static 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 81static 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 88static inline int syscall_get_arch(struct task_struct *task) 89{ 90 return AUDIT_ARCH_I386; 91} 92 93#else /* CONFIG_X86_64 */ 94 95static 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 119static 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 127bool do_syscall_64(struct pt_regs *regs, int nr); 128void do_int80_emulation(struct pt_regs *regs); 129 130#endif /* CONFIG_X86_32 */ 131 132void do_int80_syscall_32(struct pt_regs *regs); 133bool do_fast_syscall_32(struct pt_regs *regs); 134bool do_SYSENTER_32(struct pt_regs *regs); 135 136#endif /* _ASM_X86_SYSCALL_H */ 137