[RFC] MIPS: Add VDSO support

Message ID 1459350611-6100-1-git-send-email-Zubair.Kakakhel@imgtec.com
State Superseded
Headers

Commit Message

Zubair Lutfullah Kakakhel March 30, 2016, 3:10 p.m. UTC
  From: Alex Smith <alex.smith@imgtec.com>

This patch adds support for using the implementations of gettimeofday()
and clock_gettime() provided by the kernel in the VDSO. The VDSO will
always provide clock_gettime() as CLOCK_{REALTIME,MONOTONIC}_COARSE can
be implemented regardless of platform. CLOCK_{REALTIME,MONOTONIC}, along
with gettimeofday(), are only implemented on platforms which make use of
either the CP0 count or GIC as their clocksource. On other platforms,
the VDSO does not provide the __vdso_gettimeofday symbol, as it is
never useful.

The VDSO functions return ENOSYS when they encounter an unsupported
request, in which case glibc should fall back to the standard syscall.

	* sysdeps/unix/sysv/linux/mips/Makefile (sysdep_routines):
	Include dl-vdso.
	* sysdeps/unix/sysv/linux/mips/Versions: Add
	__vdso_clock_gettime.
	* sysdeps/unix/sysv/linux/mips/init-first.c: New file.
	* sysdeps/unix/sysv/linux/mips/libc-vdso.h: New file.
	* sysdeps/unix/sysv/linux/mips/mips32/sysdep.h:
	(INTERNAL_VSYSCALL_CALL): Define to be compatible with MIPS
	definitions of INTERNAL_SYSCALL_{ERROR_P,ERRNO}.
	(HAVE_CLOCK_GETTIME_VSYSCALL): Define.
	(HAVE_GETTIMEOFDAY_VSYSCALL): Define.
	* sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h: Likewise.

---
Hi,

The kernel patches for vdso support are already upstream.

I'm picking up this patch to upstream vdso support for MIPS in glibc.

Rebased this patch on glibc-2.23

Tested with upstream kernel 4.5 and QEMU emulating Malta.

 ./vdsotest gettimeofday bench
gettimeofday: syscall: 1021 nsec/call
gettimeofday:    libc: 262 nsec/call
gettimeofday:    vdso: 174 nsec/call

Regards,
ZubairLK

---
 sysdeps/unix/sysv/linux/mips/Makefile            |  2 ++
 sysdeps/unix/sysv/linux/mips/Versions            |  4 +++
 sysdeps/unix/sysv/linux/mips/init-first.c        | 44 ++++++++++++++++++++++++
 sysdeps/unix/sysv/linux/mips/libc-vdso.h         | 33 ++++++++++++++++++
 sysdeps/unix/sysv/linux/mips/mips32/sysdep.h     | 16 +++++++++
 sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h | 17 +++++++++
 sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h | 17 +++++++++
 7 files changed, 133 insertions(+)
 create mode 100644 sysdeps/unix/sysv/linux/mips/init-first.c
 create mode 100644 sysdeps/unix/sysv/linux/mips/libc-vdso.h
  

Comments

Mike Frysinger March 30, 2016, 8:02 p.m. UTC | #1
On 30 Mar 2016 16:10, Zubair Lutfullah Kakakhel wrote:
> The kernel patches for vdso support are already upstream.

can you make sure the vdso(7) man page is updated then ?
-mike
  
Zubair Lutfullah Kakakhel April 6, 2016, 10:20 a.m. UTC | #2
Hi,

On 30/03/16 21:02, Mike Frysinger wrote:
> On 30 Mar 2016 16:10, Zubair Lutfullah Kakakhel wrote:
>> The kernel patches for vdso support are already upstream.
>
> can you make sure the vdso(7) man page is updated then ?
> -mike
>

Thanks.

I've sent a patch for man-pages.

http://thread.gmane.org/gmane.linux.man/10349

Regards,
ZubairLK
  
Zubair Lutfullah Kakakhel April 8, 2016, 11:56 a.m. UTC | #3
+ Joseph.

Apologies. I forgot to cc you initially.

Regards,
ZubairLK

On 30/03/16 16:10, Zubair Lutfullah Kakakhel wrote:
> From: Alex Smith <alex.smith@imgtec.com>
>
> This patch adds support for using the implementations of gettimeofday()
> and clock_gettime() provided by the kernel in the VDSO. The VDSO will
> always provide clock_gettime() as CLOCK_{REALTIME,MONOTONIC}_COARSE can
> be implemented regardless of platform. CLOCK_{REALTIME,MONOTONIC}, along
> with gettimeofday(), are only implemented on platforms which make use of
> either the CP0 count or GIC as their clocksource. On other platforms,
> the VDSO does not provide the __vdso_gettimeofday symbol, as it is
> never useful.
>
> The VDSO functions return ENOSYS when they encounter an unsupported
> request, in which case glibc should fall back to the standard syscall.
>
> 	* sysdeps/unix/sysv/linux/mips/Makefile (sysdep_routines):
> 	Include dl-vdso.
> 	* sysdeps/unix/sysv/linux/mips/Versions: Add
> 	__vdso_clock_gettime.
> 	* sysdeps/unix/sysv/linux/mips/init-first.c: New file.
> 	* sysdeps/unix/sysv/linux/mips/libc-vdso.h: New file.
> 	* sysdeps/unix/sysv/linux/mips/mips32/sysdep.h:
> 	(INTERNAL_VSYSCALL_CALL): Define to be compatible with MIPS
> 	definitions of INTERNAL_SYSCALL_{ERROR_P,ERRNO}.
> 	(HAVE_CLOCK_GETTIME_VSYSCALL): Define.
> 	(HAVE_GETTIMEOFDAY_VSYSCALL): Define.
> 	* sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h: Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h: Likewise.
>
> ---
> Hi,
>
> The kernel patches for vdso support are already upstream.
>
> I'm picking up this patch to upstream vdso support for MIPS in glibc.
>
> Rebased this patch on glibc-2.23
>
> Tested with upstream kernel 4.5 and QEMU emulating Malta.
>
>   ./vdsotest gettimeofday bench
> gettimeofday: syscall: 1021 nsec/call
> gettimeofday:    libc: 262 nsec/call
> gettimeofday:    vdso: 174 nsec/call
>
> Regards,
> ZubairLK
>
> ---
>   sysdeps/unix/sysv/linux/mips/Makefile            |  2 ++
>   sysdeps/unix/sysv/linux/mips/Versions            |  4 +++
>   sysdeps/unix/sysv/linux/mips/init-first.c        | 44 ++++++++++++++++++++++++
>   sysdeps/unix/sysv/linux/mips/libc-vdso.h         | 33 ++++++++++++++++++
>   sysdeps/unix/sysv/linux/mips/mips32/sysdep.h     | 16 +++++++++
>   sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h | 17 +++++++++
>   sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h | 17 +++++++++
>   7 files changed, 133 insertions(+)
>   create mode 100644 sysdeps/unix/sysv/linux/mips/init-first.c
>   create mode 100644 sysdeps/unix/sysv/linux/mips/libc-vdso.h
>
> diff --git a/sysdeps/unix/sysv/linux/mips/Makefile b/sysdeps/unix/sysv/linux/mips/Makefile
> index 8127025..c6729c1 100644
> --- a/sysdeps/unix/sysv/linux/mips/Makefile
> +++ b/sysdeps/unix/sysv/linux/mips/Makefile
> @@ -96,6 +96,8 @@ ifeq ($(subdir),elf)
>   ifeq ($(build-shared),yes)
>   # This is needed for DSO loading from static binaries.
>   sysdep-dl-routines += dl-static
> +
> +sysdep_routines += dl-vdso
>   endif
>   endif
>
> diff --git a/sysdeps/unix/sysv/linux/mips/Versions b/sysdeps/unix/sysv/linux/mips/Versions
> index a56322a..453f276 100644
> --- a/sysdeps/unix/sysv/linux/mips/Versions
> +++ b/sysdeps/unix/sysv/linux/mips/Versions
> @@ -37,4 +37,8 @@ libc {
>     GLIBC_2.11 {
>       fallocate64;
>     }
> +  GLIBC_PRIVATE {
> +    # nptl/pthread_cond_timedwait.c uses INTERNAL_VSYSCALL(clock_gettime).
> +    __vdso_clock_gettime;
> +  }
>   }
> diff --git a/sysdeps/unix/sysv/linux/mips/init-first.c b/sysdeps/unix/sysv/linux/mips/init-first.c
> new file mode 100644
> index 0000000..46dba69
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/mips/init-first.c
> @@ -0,0 +1,44 @@
> +/* Initialization code run first thing by the ELF startup code.
> +   Copyright (C) 2015 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>
> +# include <libc-vdso.h>
> +
> +int (*VDSO_SYMBOL(gettimeofday)) (struct timeval *, void *) attribute_hidden;
> +int (*VDSO_SYMBOL(clock_gettime)) (clockid_t, struct timespec *);
> +
> +static inline void
> +_libc_vdso_platform_setup (void)
> +{
> +  PREPARE_VERSION_KNOWN (linux26, LINUX_2_6);
> +
> +  void *p = _dl_vdso_vsym ("__vdso_gettimeofday", &linux26);
> +  PTR_MANGLE (p);
> +  VDSO_SYMBOL (gettimeofday) = p;
> +
> +  p = _dl_vdso_vsym ("__vdso_clock_gettime", &linux26);
> +  PTR_MANGLE (p);
> +  VDSO_SYMBOL (clock_gettime) = p;
> +}
> +
> +# define VDSO_SETUP _libc_vdso_platform_setup
> +#endif
> +
> +#include <csu/init-first.c>
> diff --git a/sysdeps/unix/sysv/linux/mips/libc-vdso.h b/sysdeps/unix/sysv/linux/mips/libc-vdso.h
> new file mode 100644
> index 0000000..1580de8
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/mips/libc-vdso.h
> @@ -0,0 +1,33 @@
> +/* VDSO function pointer declarations.
> +   Copyright (C) 2015 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
> +
> +# include <sysdep-vdso.h>
> +
> +extern int (*VDSO_SYMBOL(gettimeofday)) (struct timeval *, void *)
> +   attribute_hidden;
> +extern int (*VDSO_SYMBOL(clock_gettime)) (clockid_t, struct timespec *);
> +
> +#endif
> +
> +#endif /* _LIBC_VDSO_H */
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h b/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
> index 2160df7..2335409 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
> @@ -371,6 +371,22 @@
>   #define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \
>   	"$14", "$15", "$24", "$25", "hi", "lo", "memory"
>
> +/* Standard MIPS syscalls have an error flag, and return a positive errno
> +   when the error flag is set. Emulate this behaviour for vsyscalls so that
> +   the INTERNAL_SYSCALL_{ERROR_P,ERRNO} macros work correctly.  */
> +#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...)		\
> +  ({									\
> +    long _ret = funcptr (args);						\
> +    err = ((unsigned long) (_ret) >= (unsigned long) -4095L);		\
> +    if (err)								\
> +      _ret = -_ret;							\
> +    _ret;								\
> +  })
> +
> +/* List of system calls which are supported as vsyscalls.  */
> +#define HAVE_CLOCK_GETTIME_VSYSCALL	1
> +#define HAVE_GETTIMEOFDAY_VSYSCALL	1
> +
>   #endif /* __ASSEMBLER__ */
>
>   /* Pointer mangling is not yet supported for MIPS.  */
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h b/sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h
> index 466dcde..661b3dc 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h
> @@ -295,6 +295,23 @@
>
>   #define __SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", "$13", \
>   	"$14", "$15", "$24", "$25", "hi", "lo", "memory"
> +
> +/* Standard MIPS syscalls have an error flag, and return a positive errno
> +   when the error flag is set. Emulate this behaviour for vsyscalls so that
> +   the INTERNAL_SYSCALL_{ERROR_P,ERRNO} macros work correctly.  */
> +#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...)		\
> +  ({									\
> +    long _ret = funcptr (args);						\
> +    err = ((unsigned long) (_ret) >= (unsigned long) -4095L);		\
> +    if (err)								\
> +      _ret = -_ret;							\
> +    _ret;								\
> +  })
> +
> +/* List of system calls which are supported as vsyscalls.  */
> +#define HAVE_CLOCK_GETTIME_VSYSCALL	1
> +#define HAVE_GETTIMEOFDAY_VSYSCALL	1
> +
>   #endif /* __ASSEMBLER__ */
>
>   /* Pointer mangling is not yet supported for MIPS.  */
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h b/sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h
> index db8b237..476eca3 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h
> @@ -291,6 +291,23 @@
>
>   #define __SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", "$13", \
>   	"$14", "$15", "$24", "$25", "hi", "lo", "memory"
> +
> +/* Standard MIPS syscalls have an error flag, and return a positive errno
> +   when the error flag is set. Emulate this behaviour for vsyscalls so that
> +   the INTERNAL_SYSCALL_{ERROR_P,ERRNO} macros work correctly.  */
> +#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...)		\
> +  ({									\
> +    long _ret = funcptr (args);						\
> +    err = ((unsigned long) (_ret) >= (unsigned long) -4095L);		\
> +    if (err)								\
> +      _ret = -_ret;							\
> +    _ret;								\
> +  })
> +
> +/* List of system calls which are supported as vsyscalls.  */
> +#define HAVE_CLOCK_GETTIME_VSYSCALL	1
> +#define HAVE_GETTIMEOFDAY_VSYSCALL	1
> +
>   #endif /* __ASSEMBLER__ */
>
>   /* Pointer mangling is not yet supported for MIPS.  */
>
  
Joseph Myers April 8, 2016, 2:10 p.m. UTC | #4
On Wed, 30 Mar 2016, Zubair Lutfullah Kakakhel wrote:

> +/* Initialization code run first thing by the ELF startup code.
> +   Copyright (C) 2015 Free Software Foundation, Inc.

Copyright notices for all new files should include 2016.  OK with that 
fixed for all affected files in this patch.
  

Patch

diff --git a/sysdeps/unix/sysv/linux/mips/Makefile b/sysdeps/unix/sysv/linux/mips/Makefile
index 8127025..c6729c1 100644
--- a/sysdeps/unix/sysv/linux/mips/Makefile
+++ b/sysdeps/unix/sysv/linux/mips/Makefile
@@ -96,6 +96,8 @@  ifeq ($(subdir),elf)
 ifeq ($(build-shared),yes)
 # This is needed for DSO loading from static binaries.
 sysdep-dl-routines += dl-static
+
+sysdep_routines += dl-vdso
 endif
 endif
 
diff --git a/sysdeps/unix/sysv/linux/mips/Versions b/sysdeps/unix/sysv/linux/mips/Versions
index a56322a..453f276 100644
--- a/sysdeps/unix/sysv/linux/mips/Versions
+++ b/sysdeps/unix/sysv/linux/mips/Versions
@@ -37,4 +37,8 @@  libc {
   GLIBC_2.11 {
     fallocate64;
   }
+  GLIBC_PRIVATE {
+    # nptl/pthread_cond_timedwait.c uses INTERNAL_VSYSCALL(clock_gettime).
+    __vdso_clock_gettime;
+  }
 }
diff --git a/sysdeps/unix/sysv/linux/mips/init-first.c b/sysdeps/unix/sysv/linux/mips/init-first.c
new file mode 100644
index 0000000..46dba69
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/mips/init-first.c
@@ -0,0 +1,44 @@ 
+/* Initialization code run first thing by the ELF startup code.
+   Copyright (C) 2015 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>
+# include <libc-vdso.h>
+
+int (*VDSO_SYMBOL(gettimeofday)) (struct timeval *, void *) attribute_hidden;
+int (*VDSO_SYMBOL(clock_gettime)) (clockid_t, struct timespec *);
+
+static inline void
+_libc_vdso_platform_setup (void)
+{
+  PREPARE_VERSION_KNOWN (linux26, LINUX_2_6);
+
+  void *p = _dl_vdso_vsym ("__vdso_gettimeofday", &linux26);
+  PTR_MANGLE (p);
+  VDSO_SYMBOL (gettimeofday) = p;
+
+  p = _dl_vdso_vsym ("__vdso_clock_gettime", &linux26);
+  PTR_MANGLE (p);
+  VDSO_SYMBOL (clock_gettime) = p;
+}
+
+# define VDSO_SETUP _libc_vdso_platform_setup
+#endif
+
+#include <csu/init-first.c>
diff --git a/sysdeps/unix/sysv/linux/mips/libc-vdso.h b/sysdeps/unix/sysv/linux/mips/libc-vdso.h
new file mode 100644
index 0000000..1580de8
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/mips/libc-vdso.h
@@ -0,0 +1,33 @@ 
+/* VDSO function pointer declarations.
+   Copyright (C) 2015 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
+
+# include <sysdep-vdso.h>
+
+extern int (*VDSO_SYMBOL(gettimeofday)) (struct timeval *, void *)
+   attribute_hidden;
+extern int (*VDSO_SYMBOL(clock_gettime)) (clockid_t, struct timespec *);
+
+#endif
+
+#endif /* _LIBC_VDSO_H */
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h b/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
index 2160df7..2335409 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
@@ -371,6 +371,22 @@ 
 #define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \
 	"$14", "$15", "$24", "$25", "hi", "lo", "memory"
 
+/* Standard MIPS syscalls have an error flag, and return a positive errno
+   when the error flag is set. Emulate this behaviour for vsyscalls so that
+   the INTERNAL_SYSCALL_{ERROR_P,ERRNO} macros work correctly.  */
+#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...)		\
+  ({									\
+    long _ret = funcptr (args);						\
+    err = ((unsigned long) (_ret) >= (unsigned long) -4095L);		\
+    if (err)								\
+      _ret = -_ret;							\
+    _ret;								\
+  })
+
+/* List of system calls which are supported as vsyscalls.  */
+#define HAVE_CLOCK_GETTIME_VSYSCALL	1
+#define HAVE_GETTIMEOFDAY_VSYSCALL	1
+
 #endif /* __ASSEMBLER__ */
 
 /* Pointer mangling is not yet supported for MIPS.  */
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h b/sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h
index 466dcde..661b3dc 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h
@@ -295,6 +295,23 @@ 
 
 #define __SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", "$13", \
 	"$14", "$15", "$24", "$25", "hi", "lo", "memory"
+
+/* Standard MIPS syscalls have an error flag, and return a positive errno
+   when the error flag is set. Emulate this behaviour for vsyscalls so that
+   the INTERNAL_SYSCALL_{ERROR_P,ERRNO} macros work correctly.  */
+#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...)		\
+  ({									\
+    long _ret = funcptr (args);						\
+    err = ((unsigned long) (_ret) >= (unsigned long) -4095L);		\
+    if (err)								\
+      _ret = -_ret;							\
+    _ret;								\
+  })
+
+/* List of system calls which are supported as vsyscalls.  */
+#define HAVE_CLOCK_GETTIME_VSYSCALL	1
+#define HAVE_GETTIMEOFDAY_VSYSCALL	1
+
 #endif /* __ASSEMBLER__ */
 
 /* Pointer mangling is not yet supported for MIPS.  */
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h b/sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h
index db8b237..476eca3 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h
@@ -291,6 +291,23 @@ 
 
 #define __SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", "$13", \
 	"$14", "$15", "$24", "$25", "hi", "lo", "memory"
+
+/* Standard MIPS syscalls have an error flag, and return a positive errno
+   when the error flag is set. Emulate this behaviour for vsyscalls so that
+   the INTERNAL_SYSCALL_{ERROR_P,ERRNO} macros work correctly.  */
+#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...)		\
+  ({									\
+    long _ret = funcptr (args);						\
+    err = ((unsigned long) (_ret) >= (unsigned long) -4095L);		\
+    if (err)								\
+      _ret = -_ret;							\
+    _ret;								\
+  })
+
+/* List of system calls which are supported as vsyscalls.  */
+#define HAVE_CLOCK_GETTIME_VSYSCALL	1
+#define HAVE_GETTIMEOFDAY_VSYSCALL	1
+
 #endif /* __ASSEMBLER__ */
 
 /* Pointer mangling is not yet supported for MIPS.  */