root/arch/x86/include/asm/vdso/sys_call.h
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Macros for issuing an inline system call from the vDSO.
 */

#ifndef X86_ASM_VDSO_SYS_CALL_H
#define X86_ASM_VDSO_SYS_CALL_H

#include <linux/compiler.h>
#include <asm/cpufeatures.h>
#include <asm/alternative.h>

#ifdef CONFIG_X86_64
# define __sys_instr    "syscall"
# define __sys_clobber  "rcx", "r11", "memory"
# define __sys_nr(x,y)  __NR_ ## x
# define __sys_reg1     "rdi"
# define __sys_reg2     "rsi"
# define __sys_reg3     "rdx"
# define __sys_reg4     "r10"
# define __sys_reg5     "r8"
#else
# define __sys_instr    ALTERNATIVE("ds;ds;ds;int $0x80",               \
                                    "call __kernel_vsyscall",           \
                                    X86_FEATURE_SYSFAST32)
# define __sys_clobber  "memory"
# define __sys_nr(x,y)  __NR_ ## x ## y
# define __sys_reg1     "ebx"
# define __sys_reg2     "ecx"
# define __sys_reg3     "edx"
# define __sys_reg4     "esi"
# define __sys_reg5     "edi"
#endif

/*
 * Example usage:
 *
 * result = VDSO_SYSCALL3(foo,64,x,y,z);
 *
 * ... calls foo(x,y,z) on 64 bits, and foo64(x,y,z) on 32 bits.
 *
 * VDSO_SYSCALL6() is currently missing, because it would require
 * special handling for %ebp on 32 bits when the vdso is compiled with
 * frame pointers enabled (the default on 32 bits.) Add it as a special
 * case when and if it becomes necessary.
 */
#define _VDSO_SYSCALL(name,suf32,...)                                   \
        ({                                                              \
                long _sys_num_ret = __sys_nr(name,suf32);               \
                asm_inline volatile(                                    \
                        __sys_instr                                     \
                        : "+a" (_sys_num_ret)                           \
                        : __VA_ARGS__                                   \
                        : __sys_clobber);                               \
                _sys_num_ret;                                           \
        })

#define VDSO_SYSCALL0(name,suf32)                                       \
        _VDSO_SYSCALL(name,suf32)
#define VDSO_SYSCALL1(name,suf32,a1)                                    \
        ({                                                              \
                register long _sys_arg1 asm(__sys_reg1) = (long)(a1);   \
                _VDSO_SYSCALL(name,suf32,                               \
                              "r" (_sys_arg1));                         \
        })
#define VDSO_SYSCALL2(name,suf32,a1,a2)                         \
        ({                                                              \
                register long _sys_arg1 asm(__sys_reg1) = (long)(a1);   \
                register long _sys_arg2 asm(__sys_reg2) = (long)(a2);   \
                _VDSO_SYSCALL(name,suf32,                               \
                              "r" (_sys_arg1), "r" (_sys_arg2));        \
        })
#define VDSO_SYSCALL3(name,suf32,a1,a2,a3)                              \
        ({                                                              \
                register long _sys_arg1 asm(__sys_reg1) = (long)(a1);   \
                register long _sys_arg2 asm(__sys_reg2) = (long)(a2);   \
                register long _sys_arg3 asm(__sys_reg3) = (long)(a3);   \
                _VDSO_SYSCALL(name,suf32,                               \
                              "r" (_sys_arg1), "r" (_sys_arg2),         \
                              "r" (_sys_arg3));                         \
        })
#define VDSO_SYSCALL4(name,suf32,a1,a2,a3,a4)                           \
        ({                                                              \
                register long _sys_arg1 asm(__sys_reg1) = (long)(a1);   \
                register long _sys_arg2 asm(__sys_reg2) = (long)(a2);   \
                register long _sys_arg3 asm(__sys_reg3) = (long)(a3);   \
                register long _sys_arg4 asm(__sys_reg4) = (long)(a4);   \
                _VDSO_SYSCALL(name,suf32,                               \
                              "r" (_sys_arg1), "r" (_sys_arg2),         \
                              "r" (_sys_arg3), "r" (_sys_arg4));        \
        })
#define VDSO_SYSCALL5(name,suf32,a1,a2,a3,a4,a5)                        \
        ({                                                              \
                register long _sys_arg1 asm(__sys_reg1) = (long)(a1);   \
                register long _sys_arg2 asm(__sys_reg2) = (long)(a2);   \
                register long _sys_arg3 asm(__sys_reg3) = (long)(a3);   \
                register long _sys_arg4 asm(__sys_reg4) = (long)(a4);   \
                register long _sys_arg5 asm(__sys_reg5) = (long)(a5);   \
                _VDSO_SYSCALL(name,suf32,                               \
                              "r" (_sys_arg1), "r" (_sys_arg2),         \
                              "r" (_sys_arg3), "r" (_sys_arg4),         \
                              "r" (_sys_arg5));                         \
        })

#endif /* X86_VDSO_SYS_CALL_H */