[RFC] MIPS: Add VDSO support
diff mbox

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

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 mbox

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.  */