This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC][PATCH] ARM: vDSO support


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]