This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[RFC][PATCH] ARM: vDSO support
- From: Nathan Lynch <nathan_lynch at mentor dot com>
- To: libc-alpha at sourceware dot org
- Date: Tue, 25 Feb 2014 18:06:56 -0600
- Subject: [RFC][PATCH] ARM: vDSO support
- Authentication-results: sourceware.org; auth=none
Future versions (beginning with 3.15 or 3.16) of Linux on 32-bit ARM
are expected to provide fast user-space implementations of the
following system calls:
- gettimeofday
- clock_gettime
- clock_getres
This patch adds support for the ARM vDSO to glibc. The changes are
mostly copied from the aarch64 code, with necessary adjustments to
_libc_vdso_platform_setup and INTERNAL_VSYSCALL_NCS (which has
__thumb2__ and non-__thumb2__ versions).
Tested on OMAP5 (Cortex-A15) with the relevant kernel patch, the latest
posted version of which may be found here:
http://lists.infradead.org/pipermail/linux-arm-kernel/2014-February/230971.html
I have run 'make check' using cross-test-ssh.sh to run the tests on
the target, and no new failures were reported.
Changelog:
2014-02-25 Nathan Lynch <nathan_lynch@mentor.com>
* sysdeps/unix/sysv/linux/arm/Makefile (sysdep_routines):
Include dl-vdso.
* sysdeps/unix/sysv/linux/arm/Versions: Add __vdso_clock_gettime
and __vdso_clock_getres.
* sysdeps/unix/sysv/linux/arm/bits/libc-vdso.h: New file.
* sysdeps/unix/sysv/linux/arm/gettimeofday.c: New file.
* sysdeps/unix/sysv/linux/arm/init-first.c: New file.
* sysdeps/unix/sysv/linux/arm/sysdep.h: Define
INTERNAL_VSYSCALL_NCS, INTERNAL_VSYSCALL, INLINE_VSYSCALL.
---
sysdeps/unix/sysv/linux/arm/Makefile | 1 +
sysdeps/unix/sysv/linux/arm/Versions | 4 ++
sysdeps/unix/sysv/linux/arm/bits/libc-vdso.h | 31 +++++++++++
sysdeps/unix/sysv/linux/arm/gettimeofday.c | 38 +++++++++++++
sysdeps/unix/sysv/linux/arm/init-first.c | 43 ++++++++++++++
sysdeps/unix/sysv/linux/arm/sysdep.h | 83 ++++++++++++++++++++++++++++
6 files changed, 200 insertions(+)
create mode 100644 sysdeps/unix/sysv/linux/arm/bits/libc-vdso.h
create mode 100644 sysdeps/unix/sysv/linux/arm/gettimeofday.c
create mode 100644 sysdeps/unix/sysv/linux/arm/init-first.c
diff --git a/sysdeps/unix/sysv/linux/arm/Makefile b/sysdeps/unix/sysv/linux/arm/Makefile
index aa7526a25872..469812142eb6 100644
--- a/sysdeps/unix/sysv/linux/arm/Makefile
+++ b/sysdeps/unix/sysv/linux/arm/Makefile
@@ -10,6 +10,7 @@ shared-only-routines += libc-aeabi_read_tp
endif
ifeq ($(subdir),elf)
+sysdep_routines += dl-vdso
sysdep-rtld-routines += aeabi_read_tp libc-do-syscall
endif
diff --git a/sysdeps/unix/sysv/linux/arm/Versions b/sysdeps/unix/sysv/linux/arm/Versions
index 1d9e96464040..8a94ebfd58fc 100644
--- a/sysdeps/unix/sysv/linux/arm/Versions
+++ b/sysdeps/unix/sysv/linux/arm/Versions
@@ -37,4 +37,8 @@ libc {
GLIBC_2.11 {
fallocate64;
}
+ GLIBC_PRIVATE {
+ __vdso_clock_gettime;
+ __vdso_clock_getres;
+ }
}
diff --git a/sysdeps/unix/sysv/linux/arm/bits/libc-vdso.h b/sysdeps/unix/sysv/linux/arm/bits/libc-vdso.h
new file mode 100644
index 000000000000..8c5fcf2b2de3
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/arm/bits/libc-vdso.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2009-2014 Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _LIBC_VDSO_H
+#define _LIBC_VDSO_H
+
+#ifdef SHARED
+
+extern void (*__vdso_gettimeofday) (struct timeval *, void *)
+ attribute_hidden;
+extern void (*__vdso_clock_gettime) (clockid_t, struct timespec *);
+extern void (*__vdso_clock_getres) (clockid_t, struct timespec *);
+
+#endif
+
+#endif /* _LIBC_VDSO_H */
diff --git a/sysdeps/unix/sysv/linux/arm/gettimeofday.c b/sysdeps/unix/sysv/linux/arm/gettimeofday.c
new file mode 100644
index 000000000000..267cfae30761
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/arm/gettimeofday.c
@@ -0,0 +1,38 @@
+/* Copyright (C) 2005-2014 Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <sys/time.h>
+
+#undef __gettimeofday
+
+#include <bits/libc-vdso.h>
+
+/* Get the current time of day and timezone information,
+ putting it into *tv and *tz. If tz is null, *tz is not filled.
+ Returns 0 on success, -1 on errors. */
+int
+__gettimeofday (tv, tz)
+ struct timeval *tv;
+ struct timezone *tz;
+{
+ return INLINE_VSYSCALL (gettimeofday, 2, tv, tz);
+}
+libc_hidden_def (__gettimeofday)
+weak_alias (__gettimeofday, gettimeofday)
+libc_hidden_weak (gettimeofday)
diff --git a/sysdeps/unix/sysv/linux/arm/init-first.c b/sysdeps/unix/sysv/linux/arm/init-first.c
new file mode 100644
index 000000000000..854270f71b18
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/arm/init-first.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 2007-2014 Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef SHARED
+# include <dl-vdso.h>
+# undef __gettimeofday
+# undef __clock_gettime
+# undef __clock_getres
+# include <bits/libc-vdso.h>
+
+void (*__vdso_gettimeofday) (struct timeval *, void *) attribute_hidden;
+void (*__vdso_clock_gettime) (clockid_t, struct timespec *);
+void (*__vdso_clock_getres) (clockid_t, struct timespec *);
+
+static inline void
+_libc_vdso_platform_setup (void)
+{
+ PREPARE_VERSION (linux315, "LINUX_3.15", 182939509);
+
+ __vdso_gettimeofday = _dl_vdso_vsym ("__kernel_gettimeofday", &linux315);
+ __vdso_clock_gettime = _dl_vdso_vsym ("__kernel_clock_gettime", &linux315);
+ __vdso_clock_getres = _dl_vdso_vsym ("__kernel_clock_getres", &linux315);
+}
+
+# define VDSO_SETUP _libc_vdso_platform_setup
+#endif
+
+#include <csu/init-first.c>
diff --git a/sysdeps/unix/sysv/linux/arm/sysdep.h b/sysdeps/unix/sysv/linux/arm/sysdep.h
index 700c1cec7ece..313f810b7152 100644
--- a/sysdeps/unix/sysv/linux/arm/sysdep.h
+++ b/sysdeps/unix/sysv/linux/arm/sysdep.h
@@ -317,6 +317,89 @@ __local_syscall_error: \
#else /* not __ASSEMBLER__ */
+# ifdef SHARED
+# define INLINE_VSYSCALL(name, nr, args...) \
+ ({ \
+ __label__ out; \
+ __label__ iserr; \
+ long sc_ret; \
+ INTERNAL_SYSCALL_DECL (sc_err); \
+ \
+ if (__vdso_##name != NULL) \
+ { \
+ sc_ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, sc_err, nr, ##args); \
+ if (!INTERNAL_SYSCALL_ERROR_P (sc_ret, sc_err)) \
+ goto out; \
+ if (INTERNAL_SYSCALL_ERRNO (sc_ret, sc_err) != ENOSYS) \
+ goto iserr; \
+ } \
+ \
+ sc_ret = INTERNAL_SYSCALL (name, sc_err, nr, ##args); \
+ if (INTERNAL_SYSCALL_ERROR_P (sc_ret, sc_err)) \
+ { \
+ iserr: \
+ __set_errno (INTERNAL_SYSCALL_ERRNO (sc_ret, sc_err)); \
+ sc_ret = -1L; \
+ } \
+ out: \
+ sc_ret; \
+ })
+# else
+# define INLINE_VSYSCALL(name, nr, args...) \
+ INLINE_SYSCALL (name, nr, ##args)
+# endif
+
+# ifdef SHARED
+# define INTERNAL_VSYSCALL(name, err, nr, args...) \
+ ({ \
+ __label__ out; \
+ long v_ret; \
+ \
+ if (__vdso_##name != NULL) \
+ { \
+ v_ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, err, nr, ##args); \
+ if (!INTERNAL_SYSCALL_ERROR_P (v_ret, err) \
+ || INTERNAL_SYSCALL_ERRNO (v_ret, err) != ENOSYS) \
+ goto out; \
+ } \
+ v_ret = INTERNAL_SYSCALL (name, err, nr, ##args); \
+ out: \
+ v_ret; \
+ })
+# else
+# define INTERNAL_VSYSCALL(name, err, nr, args...) \
+ INTERNAL_SYSCALL (name, err, nr, ##args)
+# endif
+
+/* List of system calls which are supported as vsyscalls. */
+# define HAVE_CLOCK_GETRES_VSYSCALL 1
+# define HAVE_CLOCK_GETTIME_VSYSCALL 1
+
+# ifdef __thumb2__
+# define INTERNAL_VSYSCALL_NCS(funcptr, err, nr, args...) \
+ ({ \
+ register int _a1 asm ("r0"); \
+ LOAD_ARGS_##nr (args) \
+ asm volatile ("blx %1" \
+ : "=r" (_a1) \
+ : "r" (funcptr) ASM_ARGS_##nr \
+ : "memory", "lr"); \
+ _a1; \
+ })
+# else
+# define INTERNAL_VSYSCALL_NCS(funcptr, err, nr, args...) \
+ ({ \
+ register int _a1 asm ("r0"); \
+ LOAD_ARGS_##nr (args) \
+ asm volatile ("mov lr, pc\n\t" \
+ "mov pc, %1\n\t" \
+ : "=r" (_a1) \
+ : "r" (funcptr) ASM_ARGS_##nr \
+ : "memory", "lr"); \
+ _a1; \
+ })
+# endif
+
/* Define a macro which expands into the inline wrapper code for a system
call. */
#undef INLINE_SYSCALL
--
1.8.3.1