Skip to content

Commit a0636d4

Browse files
H. Peter Anvinhansendc
authored andcommitted
x86/vdso: Abstract out vdso system call internals
Abstract out the calling of true system calls from the vdso into macros. It has been a very long time since gcc did not allow %ebx or %ebp in inline asm in 32-bit PIC mode; remove the corresponding hacks. Remove the use of memory output constraints in gettimeofday.h in favor of "memory" clobbers. The resulting code is identical for the current use cases, as the system call is usually a terminal fallback anyway, and it merely complicates the macroization. This patch adds only a handful of more lines of code than it removes, and in fact could be made substantially smaller by removing the macros for the argument counts that aren't currently used, however, it seems better to be general from the start. [ v3: remove stray comment from prototyping; remove VDSO_SYSCALL6() since it would require special handling on 32 bits and is currently unused. (Uros Biszjak) Indent nested preprocessor directives. ] Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com> Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Acked-by: Uros Bizjak <ubizjak@gmail.com> Link: https://patch.msgid.link/20251216212606.1325678-9-hpa@zytor.com
1 parent 8717b02 commit a0636d4

2 files changed

Lines changed: 111 additions & 100 deletions

File tree

arch/x86/include/asm/vdso/gettimeofday.h

Lines changed: 8 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <asm/msr.h>
1919
#include <asm/pvclock.h>
2020
#include <clocksource/hyperv_timer.h>
21+
#include <asm/vdso/sys_call.h>
2122

2223
#define VDSO_HAS_TIME 1
2324

@@ -53,130 +54,37 @@ extern struct ms_hyperv_tsc_page hvclock_page
5354
__attribute__((visibility("hidden")));
5455
#endif
5556

56-
#ifndef BUILD_VDSO32
57-
5857
static __always_inline
5958
long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
6059
{
61-
long ret;
62-
63-
asm ("syscall" : "=a" (ret), "=m" (*_ts) :
64-
"0" (__NR_clock_gettime), "D" (_clkid), "S" (_ts) :
65-
"rcx", "r11");
66-
67-
return ret;
60+
return VDSO_SYSCALL2(clock_gettime,64,_clkid,_ts);
6861
}
6962

7063
static __always_inline
7164
long gettimeofday_fallback(struct __kernel_old_timeval *_tv,
7265
struct timezone *_tz)
7366
{
74-
long ret;
75-
76-
asm("syscall" : "=a" (ret) :
77-
"0" (__NR_gettimeofday), "D" (_tv), "S" (_tz) : "memory");
78-
79-
return ret;
67+
return VDSO_SYSCALL2(gettimeofday,,_tv,_tz);
8068
}
8169

8270
static __always_inline
8371
long clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
8472
{
85-
long ret;
86-
87-
asm ("syscall" : "=a" (ret), "=m" (*_ts) :
88-
"0" (__NR_clock_getres), "D" (_clkid), "S" (_ts) :
89-
"rcx", "r11");
90-
91-
return ret;
73+
return VDSO_SYSCALL2(clock_getres,_time64,_clkid,_ts);
9274
}
9375

94-
#else
95-
96-
static __always_inline
97-
long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
98-
{
99-
long ret;
100-
101-
asm (
102-
"mov %%ebx, %%edx \n"
103-
"mov %[clock], %%ebx \n"
104-
"call __kernel_vsyscall \n"
105-
"mov %%edx, %%ebx \n"
106-
: "=a" (ret), "=m" (*_ts)
107-
: "0" (__NR_clock_gettime64), [clock] "g" (_clkid), "c" (_ts)
108-
: "edx");
109-
110-
return ret;
111-
}
76+
#ifndef CONFIG_X86_64
11277

11378
static __always_inline
11479
long clock_gettime32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
11580
{
116-
long ret;
117-
118-
asm (
119-
"mov %%ebx, %%edx \n"
120-
"mov %[clock], %%ebx \n"
121-
"call __kernel_vsyscall \n"
122-
"mov %%edx, %%ebx \n"
123-
: "=a" (ret), "=m" (*_ts)
124-
: "0" (__NR_clock_gettime), [clock] "g" (_clkid), "c" (_ts)
125-
: "edx");
126-
127-
return ret;
128-
}
129-
130-
static __always_inline
131-
long gettimeofday_fallback(struct __kernel_old_timeval *_tv,
132-
struct timezone *_tz)
133-
{
134-
long ret;
135-
136-
asm(
137-
"mov %%ebx, %%edx \n"
138-
"mov %2, %%ebx \n"
139-
"call __kernel_vsyscall \n"
140-
"mov %%edx, %%ebx \n"
141-
: "=a" (ret)
142-
: "0" (__NR_gettimeofday), "g" (_tv), "c" (_tz)
143-
: "memory", "edx");
144-
145-
return ret;
81+
return VDSO_SYSCALL2(clock_gettime,,_clkid,_ts);
14682
}
14783

14884
static __always_inline long
149-
clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
150-
{
151-
long ret;
152-
153-
asm (
154-
"mov %%ebx, %%edx \n"
155-
"mov %[clock], %%ebx \n"
156-
"call __kernel_vsyscall \n"
157-
"mov %%edx, %%ebx \n"
158-
: "=a" (ret), "=m" (*_ts)
159-
: "0" (__NR_clock_getres_time64), [clock] "g" (_clkid), "c" (_ts)
160-
: "edx");
161-
162-
return ret;
163-
}
164-
165-
static __always_inline
166-
long clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
85+
clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
16786
{
168-
long ret;
169-
170-
asm (
171-
"mov %%ebx, %%edx \n"
172-
"mov %[clock], %%ebx \n"
173-
"call __kernel_vsyscall \n"
174-
"mov %%edx, %%ebx \n"
175-
: "=a" (ret), "=m" (*_ts)
176-
: "0" (__NR_clock_getres), [clock] "g" (_clkid), "c" (_ts)
177-
: "edx");
178-
179-
return ret;
87+
return VDSO_SYSCALL2(clock_getres,,_clkid,_ts);
18088
}
18189

18290
#endif
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Macros for issuing an inline system call from the vDSO.
4+
*/
5+
6+
#ifndef X86_ASM_VDSO_SYS_CALL_H
7+
#define X86_ASM_VDSO_SYS_CALL_H
8+
9+
#include <linux/compiler.h>
10+
#include <asm/cpufeatures.h>
11+
#include <asm/alternative.h>
12+
13+
#ifdef CONFIG_X86_64
14+
# define __sys_instr "syscall"
15+
# define __sys_clobber "rcx", "r11", "memory"
16+
# define __sys_nr(x,y) __NR_ ## x
17+
# define __sys_reg1 "rdi"
18+
# define __sys_reg2 "rsi"
19+
# define __sys_reg3 "rdx"
20+
# define __sys_reg4 "r10"
21+
# define __sys_reg5 "r8"
22+
#else
23+
# define __sys_instr "call __kernel_vsyscall"
24+
# define __sys_clobber "memory"
25+
# define __sys_nr(x,y) __NR_ ## x ## y
26+
# define __sys_reg1 "ebx"
27+
# define __sys_reg2 "ecx"
28+
# define __sys_reg3 "edx"
29+
# define __sys_reg4 "esi"
30+
# define __sys_reg5 "edi"
31+
#endif
32+
33+
/*
34+
* Example usage:
35+
*
36+
* result = VDSO_SYSCALL3(foo,64,x,y,z);
37+
*
38+
* ... calls foo(x,y,z) on 64 bits, and foo64(x,y,z) on 32 bits.
39+
*
40+
* VDSO_SYSCALL6() is currently missing, because it would require
41+
* special handling for %ebp on 32 bits when the vdso is compiled with
42+
* frame pointers enabled (the default on 32 bits.) Add it as a special
43+
* case when and if it becomes necessary.
44+
*/
45+
#define _VDSO_SYSCALL(name,suf32,...) \
46+
({ \
47+
long _sys_num_ret = __sys_nr(name,suf32); \
48+
asm_inline volatile( \
49+
__sys_instr \
50+
: "+a" (_sys_num_ret) \
51+
: __VA_ARGS__ \
52+
: __sys_clobber); \
53+
_sys_num_ret; \
54+
})
55+
56+
#define VDSO_SYSCALL0(name,suf32) \
57+
_VDSO_SYSCALL(name,suf32)
58+
#define VDSO_SYSCALL1(name,suf32,a1) \
59+
({ \
60+
register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \
61+
_VDSO_SYSCALL(name,suf32, \
62+
"r" (_sys_arg1)); \
63+
})
64+
#define VDSO_SYSCALL2(name,suf32,a1,a2) \
65+
({ \
66+
register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \
67+
register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \
68+
_VDSO_SYSCALL(name,suf32, \
69+
"r" (_sys_arg1), "r" (_sys_arg2)); \
70+
})
71+
#define VDSO_SYSCALL3(name,suf32,a1,a2,a3) \
72+
({ \
73+
register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \
74+
register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \
75+
register long _sys_arg3 asm(__sys_reg3) = (long)(a3); \
76+
_VDSO_SYSCALL(name,suf32, \
77+
"r" (_sys_arg1), "r" (_sys_arg2), \
78+
"r" (_sys_arg3)); \
79+
})
80+
#define VDSO_SYSCALL4(name,suf32,a1,a2,a3,a4) \
81+
({ \
82+
register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \
83+
register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \
84+
register long _sys_arg3 asm(__sys_reg3) = (long)(a3); \
85+
register long _sys_arg4 asm(__sys_reg4) = (long)(a4); \
86+
_VDSO_SYSCALL(name,suf32, \
87+
"r" (_sys_arg1), "r" (_sys_arg2), \
88+
"r" (_sys_arg3), "r" (_sys_arg4)); \
89+
})
90+
#define VDSO_SYSCALL5(name,suf32,a1,a2,a3,a4,a5) \
91+
({ \
92+
register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \
93+
register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \
94+
register long _sys_arg3 asm(__sys_reg3) = (long)(a3); \
95+
register long _sys_arg4 asm(__sys_reg4) = (long)(a4); \
96+
register long _sys_arg5 asm(__sys_reg5) = (long)(a5); \
97+
_VDSO_SYSCALL(name,suf32, \
98+
"r" (_sys_arg1), "r" (_sys_arg2), \
99+
"r" (_sys_arg3), "r" (_sys_arg4), \
100+
"r" (_sys_arg5)); \
101+
})
102+
103+
#endif /* X86_VDSO_SYS_CALL_H */

0 commit comments

Comments
 (0)