diff options
-rw-r--r-- | ChangeLog | 28 | ||||
-rw-r--r-- | elf/rtld.c | 7 | ||||
-rw-r--r-- | sysdeps/powerpc/powerpc32/dl-start.S | 3 | ||||
-rw-r--r-- | sysdeps/powerpc/powerpc32/hp-timing.h | 82 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/clock_getres.c | 18 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/clock_gettime.c | 18 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/Makefile | 4 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/Versions | 7 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h | 36 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/dl-vdso.c | 59 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/dl-vdso.h | 27 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/get_clockfreq.c | 110 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/gettimeofday.c | 42 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/libc-start.c (renamed from sysdeps/powerpc/elf/libc-start.c) | 89 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h | 109 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h | 118 |
16 files changed, 659 insertions, 98 deletions
diff --git a/ChangeLog b/ChangeLog index 5201d34627..74d0a82e13 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2005-12-08 Steven Munroe <sjmunroe@us.ibm.com> + Tom Gall <tom_gall@vnet.ibm.com> + + * elf/rtld.c (dl_main): Initialize l_local_scope for sysinfo_map. + * sysdeps/powerpc/elf/libc-start.c: Move this... + * sysdeps/unix/sysv/linux/powerpc/libc-start.c: ...to here. + * sysdeps/powerpc/powerpc32/dl-start.S: Add _dl_main_dispatch label. + * sysdeps/powerpc/powerpc32/hp-timing.h: New file. + * sysdeps/unix/sysv/linux/powerpc/Versions: New file. + * sysdeps/unix/sysv/linux/clock_getres.c: If HAVE_CLOCK_GETRES_VSYSCALL + is not defined, redefine INTERNAL_VSYSCALL and INLINE_VSYSCALL to + INTERNAL_SYSCALL and INLINE_SYSCALL respectively. Otherwise include + <bits/libc-vdso.h>. Use INLINE_VSYSCALL and INTERNAL_SYSCALL instead + of the normal versions throughout the code. + * sysdeps/unix/sysv/linux/clock_gettime.c: Likewise if + HAVE_CLOCK_GETTIME_VSYSCALL is defined. + * sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h: New file. + * sysdeps/unix/sysv/linux/powerpc/dl-vdso.c: New file. + * sysdeps/unix/sysv/linux/powerpc/dl-vdso.h: New file. + * sysdeps/unix/sysv/linux/powerpc/get_clockfreq.c: Use vDSO. + * sysdeps/unix/sysv/linux/powerpc/gettimeofday.c: New file. + * sysdeps/unix/sysv/linux/powerpc/Makefile: Add dl-vdso to routines. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h: Define + INLINE_VSYSCALL, INTERNAL_VSYSCALL, INTERNAL_SYSCALL_NCS, + INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK, HAVE_CLOCK_GETRES_VSYSCALL, + and HAVE_CLOCK_GETTIME_VSYSCALL. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h: Likewise. + 2005-12-29 Ulrich Drepper <drepper@redhat.com> * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h [ASSEMBLER]: diff --git a/elf/rtld.c b/elf/rtld.c index 71bcf0ab71..76d129a0a0 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -1307,6 +1307,13 @@ ld.so does not support TLS, but program uses it!\n"); _dl_setup_hash (l); l->l_relocated = 1; + /* Initialize l_local_scope to contain just this map. This allows + the use of dl_lookup_symbol_x to resolve symbols within the vdso. + So we create a single entry list pointing to l_real as its only + element */ + l->l_local_scope[0]->r_nlist = 1; + l->l_local_scope[0]->r_list = &l->l_real; + /* Now that we have the info handy, use the DSO image's soname so this object can be looked up by name. Note that we do not set l_name here. That field gives the file name of the DSO, diff --git a/sysdeps/powerpc/powerpc32/dl-start.S b/sysdeps/powerpc/powerpc32/dl-start.S index e1f7f6e24a..7403a352fa 100644 --- a/sysdeps/powerpc/powerpc32/dl-start.S +++ b/sysdeps/powerpc/powerpc32/dl-start.S @@ -1,5 +1,5 @@ /* Machine-dependent ELF startup code. PowerPC version. - Copyright (C) 1995-2000, 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 1995-2000, 2002, 2004, 2005 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 @@ -98,6 +98,7 @@ ENTRY(_dl_start_user) Take the opportunity to clear LR, so anyone who accidentally returns from _start gets SEGV. Also clear the next few words of the stack. */ +ENTRY(_dl_main_dispatch) li r31,0 stw r31,0(r1) mtlr r31 diff --git a/sysdeps/powerpc/powerpc32/hp-timing.h b/sysdeps/powerpc/powerpc32/hp-timing.h new file mode 100644 index 0000000000..b62b0f2138 --- /dev/null +++ b/sysdeps/powerpc/powerpc32/hp-timing.h @@ -0,0 +1,82 @@ +/* High precision, low overhead timing functions. Linux/PPC32 version. + Copyright (C) 2005 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _HP_TIMING_H +#define _HP_TIMING_H 1 + + +/* There are no generic definitions for the times. We could write something + using the `gettimeofday' system call where available but the overhead of + the system call might be too high. + + In case a platform supports timers in the hardware the following macros + and types must be defined: + + - HP_TIMING_AVAIL: test for availability. + + - HP_TIMING_INLINE: this macro is non-zero if the functionality is not + implemented using function calls but instead uses some inlined code + which might simply consist of a few assembler instructions. We have to + know this since we might want to use the macros here in places where we + cannot make function calls. + + - hp_timing_t: This is the type for variables used to store the time + values. + + - HP_TIMING_ZERO: clear `hp_timing_t' object. + + - HP_TIMING_NOW: place timestamp for current time in variable given as + parameter. + + - HP_TIMING_DIFF_INIT: do whatever is necessary to be able to use the + HP_TIMING_DIFF macro. + + - HP_TIMING_DIFF: compute difference between two times and store it + in a third. Source and destination might overlap. + + - HP_TIMING_ACCUM: add time difference to another variable. This might + be a bit more complicated to implement for some platforms as the + operation should be thread-safe and 64bit arithmetic on 32bit platforms + is not. + + - HP_TIMING_ACCUM_NT: this is the variant for situations where we know + there are no threads involved. + + - HP_TIMING_PRINT: write decimal representation of the timing value into + the given string. This operation need not be inline even though + HP_TIMING_INLINE is specified. + +*/ + +/* Provide dummy definitions. */ +#define HP_TIMING_AVAIL (0) +#define HP_TIMING_INLINE (0) +typedef unsigned long long int hp_timing_t; +#define HP_TIMING_ZERO(Var) +#define HP_TIMING_NOW(var) +#define HP_TIMING_DIFF_INIT() +#define HP_TIMING_DIFF(Diff, Start, End) +#define HP_TIMING_ACCUM(Sum, Diff) +#define HP_TIMING_ACCUM_NT(Sum, Diff) +#define HP_TIMING_PRINT(Buf, Len, Val) + +/* Since this implementation is not available we tell the user about it. */ +#define HP_TIMING_NONAVAIL 1 + +#endif /* hp-timing.h */ diff --git a/sysdeps/unix/sysv/linux/clock_getres.c b/sysdeps/unix/sysv/linux/clock_getres.c index 2d0136dfeb..44dcccd150 100644 --- a/sysdeps/unix/sysv/linux/clock_getres.c +++ b/sysdeps/unix/sysv/linux/clock_getres.c @@ -1,5 +1,5 @@ /* clock_getres -- Get the resolution of a POSIX clockid_t. Linux version. - Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005 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 @@ -24,9 +24,17 @@ #include "kernel-features.h" +#ifndef HAVE_CLOCK_GETRES_VSYSCALL +# undef INTERNAL_VSYSCALL +# define INTERNAL_VSYSCALL INTERNAL_SYSCALL +# undef INLINE_VSYSCALL +# define INLINE_VSYSCALL INLINE_SYSCALL +#else +# include <bits/libc-vdso.h> +#endif #define SYSCALL_GETRES \ - retval = INLINE_SYSCALL (clock_getres, 2, clock_id, res); \ + retval = INLINE_VSYSCALL (clock_getres, 2, clock_id, res); \ break #ifdef __ASSUME_POSIX_TIMERS @@ -52,7 +60,7 @@ maybe_syscall_getres (clockid_t clock_id, struct timespec *res) if (!__libc_missing_posix_timers) { INTERNAL_SYSCALL_DECL (err); - int r = INTERNAL_SYSCALL (clock_getres, err, 2, clock_id, res); + int r = INTERNAL_VSYSCALL (clock_getres, err, 2, clock_id, res); if (!INTERNAL_SYSCALL_ERROR_P (r, err)) return 0; @@ -109,7 +117,7 @@ maybe_syscall_getres_cpu (clockid_t clock_id, struct timespec *res) if (!__libc_missing_posix_cpu_timers) { INTERNAL_SYSCALL_DECL (err); - int r = INTERNAL_SYSCALL (clock_getres, err, 2, clock_id, res); + int r = INTERNAL_VSYSCALL (clock_getres, err, 2, clock_id, res); if (!INTERNAL_SYSCALL_ERROR_P (r, err)) return 0; @@ -128,7 +136,7 @@ maybe_syscall_getres_cpu (clockid_t clock_id, struct timespec *res) { /* Check whether the kernel supports CPU clocks at all. If not, record it for the future. */ - r = INTERNAL_SYSCALL (clock_getres, err, 2, + r = INTERNAL_VSYSCALL (clock_getres, err, 2, MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED), NULL); if (INTERNAL_SYSCALL_ERROR_P (r, err)) diff --git a/sysdeps/unix/sysv/linux/clock_gettime.c b/sysdeps/unix/sysv/linux/clock_gettime.c index bd79642dd5..315d595edc 100644 --- a/sysdeps/unix/sysv/linux/clock_gettime.c +++ b/sysdeps/unix/sysv/linux/clock_gettime.c @@ -1,5 +1,5 @@ /* clock_gettime -- Get current time from a POSIX clockid_t. Linux version. - Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005 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 @@ -23,9 +23,17 @@ #include "kernel-posix-cpu-timers.h" #include "kernel-features.h" +#ifndef HAVE_CLOCK_GETTIME_VSYSCALL +# undef INTERNAL_VSYSCALL +# define INTERNAL_VSYSCALL INTERNAL_SYSCALL +# undef INLINE_VSYSCALL +# define INLINE_VSYSCALL INLINE_SYSCALL +#else +# include <bits/libc-vdso.h> +#endif #define SYSCALL_GETTIME \ - retval = INLINE_SYSCALL (clock_gettime, 2, clock_id, tp); \ + retval = INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp); \ break #ifdef __ASSUME_POSIX_TIMERS @@ -51,7 +59,7 @@ maybe_syscall_gettime (clockid_t clock_id, struct timespec *tp) if (!__libc_missing_posix_timers) { INTERNAL_SYSCALL_DECL (err); - int r = INTERNAL_SYSCALL (clock_gettime, err, 2, clock_id, tp); + int r = INTERNAL_VSYSCALL (clock_gettime, err, 2, clock_id, tp); if (!INTERNAL_SYSCALL_ERROR_P (r, err)) return 0; @@ -108,7 +116,7 @@ maybe_syscall_gettime_cpu (clockid_t clock_id, struct timespec *tp) if (!__libc_missing_posix_cpu_timers) { INTERNAL_SYSCALL_DECL (err); - int r = INTERNAL_SYSCALL (clock_gettime, err, 2, clock_id, tp); + int r = INTERNAL_VSYSCALL (clock_gettime, err, 2, clock_id, tp); if (!INTERNAL_SYSCALL_ERROR_P (r, err)) return 0; @@ -127,7 +135,7 @@ maybe_syscall_gettime_cpu (clockid_t clock_id, struct timespec *tp) { /* Check whether the kernel supports CPU clocks at all. If not, record it for the future. */ - r = INTERNAL_SYSCALL (clock_getres, err, 2, + r = INTERNAL_VSYSCALL (clock_getres, err, 2, MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED), NULL); if (INTERNAL_SYSCALL_ERROR_P (r, err)) diff --git a/sysdeps/unix/sysv/linux/powerpc/Makefile b/sysdeps/unix/sysv/linux/powerpc/Makefile index 55d2d0d273..ecd8057951 100644 --- a/sysdeps/unix/sysv/linux/powerpc/Makefile +++ b/sysdeps/unix/sysv/linux/powerpc/Makefile @@ -6,3 +6,7 @@ endif ifeq ($(subdir),stdlib) gen-as-const-headers += ucontext_i.sym endif + +ifeq ($(subdir),elf) +routines += dl-vdso +endif diff --git a/sysdeps/unix/sysv/linux/powerpc/Versions b/sysdeps/unix/sysv/linux/powerpc/Versions new file mode 100644 index 0000000000..1ef53b9e9c --- /dev/null +++ b/sysdeps/unix/sysv/linux/powerpc/Versions @@ -0,0 +1,7 @@ +libc { + GLIBC_PRIVATE { + __vdso_get_tbfreq; + __vdso_clock_gettime; + __vdso_clock_getres; + } +} diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h new file mode 100644 index 0000000000..f20a5a175c --- /dev/null +++ b/sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h @@ -0,0 +1,36 @@ +/* Resolve function pointers to VDSO functions. + Copyright (C) 2005 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +#ifndef _LIBC_VDSO_H +#define _LIBC_VDSO_H + +#ifdef SHARED + +extern void *__vdso_gettimeofday; + +extern void *__vdso_clock_gettime; + +extern void *__vdso_clock_getres; + +extern void *__vdso_get_tbfreq; + +#endif + +#endif /* _LIBC_VDSO_H */ diff --git a/sysdeps/unix/sysv/linux/powerpc/dl-vdso.c b/sysdeps/unix/sysv/linux/powerpc/dl-vdso.c new file mode 100644 index 0000000000..e1be097734 --- /dev/null +++ b/sysdeps/unix/sysv/linux/powerpc/dl-vdso.c @@ -0,0 +1,59 @@ +/* ELF symbol resolve functions for VDSO objects. + Copyright (C) 2005 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "config.h" +#include <dl-hash.h> +#include <ldsodefs.h> + + +void * +internal_function +_dl_vdso_vsym (const char *name, const char *version) +{ + struct link_map *map = GLRO (dl_sysinfo_map); + void *value = NULL; + + + if (map != NULL) + { + /* Use a WEAK REF so we don't error out if the symbol is not found. */ + ElfW (Sym) wsym; + memset (&wsym, 0, sizeof (ElfW (Sym))); + wsym.st_info = (unsigned char) ELFW (ST_INFO (STB_WEAK, STT_NOTYPE)); + + /* Compute hash value to the version string. */ + struct r_found_version vers; + vers.name = version; + vers.hidden = 1; + vers.hash = _dl_elf_hash (version); + /* We don't have a specific file where the symbol can be found. */ + vers.filename = NULL; + + /* Search the scope of the vdso map. */ + const ElfW (Sym) *ref = &wsym; + lookup_t result = GLRO (dl_lookup_symbol_x) (name, map, &ref, + map->l_local_scope, + &vers, 0, 0, NULL); + + if (ref != NULL) + value = DL_SYMBOL_ADDRESS (result, ref); + } + + return value; +} diff --git a/sysdeps/unix/sysv/linux/powerpc/dl-vdso.h b/sysdeps/unix/sysv/linux/powerpc/dl-vdso.h new file mode 100644 index 0000000000..a7dcb2e5ff --- /dev/null +++ b/sysdeps/unix/sysv/linux/powerpc/dl-vdso.h @@ -0,0 +1,27 @@ +/* ELF symbol resolve functions for VDSO objects. + Copyright (C) 2005 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _DL_VDSO_H +#define _DL_VDSO_H 1 + +/* Functions for resolving symbols in the VDSO link map. */ +extern void *_dl_vdso_vsym (const char *name, const char *version) + internal_function attribute_hidden; + +#endif /* dl-vdso.h */ diff --git a/sysdeps/unix/sysv/linux/powerpc/get_clockfreq.c b/sysdeps/unix/sysv/linux/powerpc/get_clockfreq.c index ddaff303c5..6d2e766aa4 100644 --- a/sysdeps/unix/sysv/linux/powerpc/get_clockfreq.c +++ b/sysdeps/unix/sysv/linux/powerpc/get_clockfreq.c @@ -22,14 +22,15 @@ #include <string.h> #include <unistd.h> #include <libc-internal.h> - +#include <sysdep.h> +#include <bits/libc-vdso.h> hp_timing_t __get_clockfreq (void) { /* We read the information from the /proc filesystem. /proc/cpuinfo contains at least one line like: - timebase : 33333333 + timebase : 33333333 We search for this line and convert the number into an integer. */ static hp_timing_t timebase_freq; hp_timing_t result = 0L; @@ -38,67 +39,78 @@ __get_clockfreq (void) if (timebase_freq != 0) return timebase_freq; - int fd = open ("/proc/cpuinfo", O_RDONLY); - if (__builtin_expect (fd != -1, 1)) + /* If we can use the vDSO to obtain the timebase even better. */ +#ifdef SHARED + INTERNAL_SYSCALL_DECL (err); + timebase_freq = INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK (get_tbfreq, err, 0); + if (INTERNAL_SYSCALL_ERROR_P (timebase_freq, err) + && INTERNAL_SYSCALL_ERRNO (timebase_freq, err) == ENOSYS) +#endif { - /* The timebase will be in the 1st 1024 bytes for systems with up - to 8 processors. If the first read returns less then 1024 - bytes read, we have the whole cpuinfo and can start the scan. - Otherwise we will have to read more to insure we have the - timebase value in the scan. */ - char buf[1024]; - ssize_t n; + int fd = open ("/proc/cpuinfo", O_RDONLY); - n = read (fd, buf, sizeof (buf)); - if (n == sizeof (buf)) + if (__builtin_expect (fd != -1, 1)) { - /* We are here because the 1st read returned exactly sizeof - (buf) bytes. This implies that we are not at EOF and may - not have read the timebase value yet. So we need to read - more bytes until we know we have EOF. We copy the lower - half of buf to the upper half and read sizeof (buf)/2 - bytes into the lower half of buf and repeat until we - reach EOF. We can assume that the timebase will be in - the last 512 bytes of cpuinfo, so two 512 byte half_bufs - will be sufficient to contain the timebase and will - handle the case where the timebase spans the half_buf - boundry. */ - const ssize_t half_buf = sizeof (buf) / 2; - while (n >= half_buf) + /* The timebase will be in the 1st 1024 bytes for systems with up + to 8 processors. If the first read returns less then 1024 + bytes read, we have the whole cpuinfo and can start the scan. + Otherwise we will have to read more to insure we have the + timebase value in the scan. */ + char buf[1024]; + ssize_t n; + + n = read (fd, buf, sizeof (buf)); + if (n == sizeof (buf)) { - memcpy (buf, buf + half_buf, half_buf); - n = read (fd, buf + half_buf, half_buf); + /* We are here because the 1st read returned exactly sizeof + (buf) bytes. This implies that we are not at EOF and may + not have read the timebase value yet. So we need to read + more bytes until we know we have EOF. We copy the lower + half of buf to the upper half and read sizeof (buf)/2 + bytes into the lower half of buf and repeat until we + reach EOF. We can assume that the timebase will be in + the last 512 bytes of cpuinfo, so two 512 byte half_bufs + will be sufficient to contain the timebase and will + handle the case where the timebase spans the half_buf + boundry. */ + const ssize_t half_buf = sizeof (buf) / 2; + while (n >= half_buf) + { + memcpy (buf, buf + half_buf, half_buf); + n = read (fd, buf + half_buf, half_buf); + } + if (n >= 0) + n += half_buf; } - if (n >= 0) - n += half_buf; - } - - if (__builtin_expect (n, 1) > 0) - { - char *mhz = memmem (buf, n, "timebase", 7); - if (__builtin_expect (mhz != NULL, 1)) + if (__builtin_expect (n, 1) > 0) { - char *endp = buf + n; - - /* Search for the beginning of the string. */ - while (mhz < endp && (*mhz < '0' || *mhz > '9') && *mhz != '\n') - ++mhz; + char *mhz = memmem (buf, n, "timebase", 7); - while (mhz < endp && *mhz != '\n') + if (__builtin_expect (mhz != NULL, 1)) { - if (*mhz >= '0' && *mhz <= '9') + char *endp = buf + n; + + /* Search for the beginning of the string. */ + while (mhz < endp && (*mhz < '0' || *mhz > '9') + && *mhz != '\n') + ++mhz; + + while (mhz < endp && *mhz != '\n') { - result *= 10; - result += *mhz - '0'; - } + if (*mhz >= '0' && *mhz <= '9') + { + result *= 10; + result += *mhz - '0'; + } - ++mhz; + ++mhz; + } } + timebase_freq = result; } - timebase_freq = result; + close (fd); } - close (fd); } return timebase_freq; diff --git a/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c new file mode 100644 index 0000000000..b381baa285 --- /dev/null +++ b/sysdeps/unix/sysv/linux/powerpc/gettimeofday.c @@ -0,0 +1,42 @@ +/* Copyright (C) 2005 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <bp-checks.h> +#include <stddef.h> +#include <sys/time.h> +#include <time.h> +#include <hp-timing.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, CHECK_1 (tv), CHECK_1 (tz)); +} + +INTDEF (__gettimeofday) +weak_alias (__gettimeofday, gettimeofday) diff --git a/sysdeps/powerpc/elf/libc-start.c b/sysdeps/unix/sysv/linux/powerpc/libc-start.c index 8a60af8d71..a8005c1163 100644 --- a/sysdeps/powerpc/elf/libc-start.c +++ b/sysdeps/unix/sysv/linux/powerpc/libc-start.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1998,2000-2004,2005 Free Software Foundation, Inc. +/* Copyright (C) 1998,2000,2001,2002,2003,2004,2005 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 @@ -24,33 +24,61 @@ extern int __cache_line_size; weak_extern (__cache_line_size) - /* The main work is done in the generic function. */ #define LIBC_START_MAIN generic_start_main #define LIBC_START_DISABLE_INLINE #define LIBC_START_MAIN_AUXVEC_ARG #define MAIN_AUXVEC_ARG +#define INIT_MAIN_ARGS #include <csu/libc-start.c> - struct startup_info -{ - void *__unbounded sda_base; - int (*main) (int, char **, char **, void *); - int (*init) (int, char **, char **, void *); - void (*fini) (void); -}; + { + void *__unbounded sda_base; + int (*main) (int, char **, char **, void *); + int (*init) (int, char **, char **, void *); + void (*fini) (void); + }; + + +#ifdef SHARED +# include <sys/time.h> +# include <dl-vdso.h> +# undef __gettimeofday +# undef __clock_gettime +# undef __clock_getres +# include <bits/libc-vdso.h> + +void *__vdso_gettimeofday; +void *__vdso_clock_gettime; +void *__vdso_clock_getres; +void *__vdso_get_tbfreq; +static inline void _libc_vdso_platform_setup (void) + { + __vdso_gettimeofday = _dl_vdso_vsym ("__kernel_gettimeofday", + "LINUX_2.6.15"); + + __vdso_clock_gettime = _dl_vdso_vsym ("__kernel_clock_gettime", + "LINUX_2.6.15"); + + __vdso_clock_getres = _dl_vdso_vsym ("__kernel_clock_getres", + "LINUX_2.6.15"); + + __vdso_get_tbfreq = _dl_vdso_vsym ("__kernel_vdso_get_tbfreq", + "LINUX_2.6.15"); + } +#endif int /* GKM FIXME: GCC: this should get __BP_ prefix by virtue of the BPs in the arglist of startup_info.main and startup_info.init. */ -BP_SYM (__libc_start_main) (int argc, char *__unbounded *__unbounded ubp_av, - char *__unbounded *__unbounded ubp_ev, - ElfW(auxv_t) *__unbounded auxvec, - void (*rtld_fini) (void), - struct startup_info *__unbounded stinfo, - char *__unbounded *__unbounded stack_on_entry) + BP_SYM (__libc_start_main) (int argc, char *__unbounded *__unbounded ubp_av, + char *__unbounded *__unbounded ubp_ev, + ElfW (auxv_t) * __unbounded auxvec, + void (*rtld_fini) (void), + struct startup_info *__unbounded stinfo, + char *__unbounded *__unbounded stack_on_entry) { #if __BOUNDED_POINTERS__ char **argv; @@ -60,13 +88,13 @@ BP_SYM (__libc_start_main) (int argc, char *__unbounded *__unbounded ubp_av, /* the PPC SVR4 ABI says that the top thing on the stack will be a NULL pointer, so if not we assume that we're being called - as a statically-linked program by Linux... */ + as a statically-linked program by Linux... */ if (*stack_on_entry != NULL) { - char *__unbounded *__unbounded temp; + char *__unbounded * __unbounded temp; /* ...in which case, we have argc as the top thing on the - stack, followed by argv (NULL-terminated), envp (likewise), - and the auxilary vector. */ + stack, followed by argv (NULL-terminated), envp (likewise), + and the auxilary vector. */ /* 32/64-bit agnostic load from stack */ argc = *(long int *__unbounded) stack_on_entry; ubp_av = stack_on_entry + 1; @@ -74,25 +102,28 @@ BP_SYM (__libc_start_main) (int argc, char *__unbounded *__unbounded ubp_av, #ifdef HAVE_AUX_VECTOR temp = ubp_ev; while (*temp != NULL) - ++temp; - auxvec = (ElfW(auxv_t) *)++temp; + ++temp; + auxvec = (ElfW (auxv_t) *)++ temp; #endif rtld_fini = NULL; } /* Initialize the __cache_line_size variable from the aux vector. */ - for (ElfW(auxv_t) *av = auxvec; av->a_type != AT_NULL; ++av) + for (ElfW (auxv_t) * av = auxvec; av->a_type != AT_NULL; ++av) switch (av->a_type) { case AT_DCACHEBSIZE: - { - int *cls = & __cache_line_size; - if (cls != NULL) - *cls = av->a_un.a_val; - } - break; + { + int *cls = &__cache_line_size; + if (cls != NULL) + *cls = av->a_un.a_val; + } + break; } - +#ifdef SHARED + /* Resolve and initialize function pointers for VDSO functions. */ + _libc_vdso_platform_setup (); +#endif return generic_start_main (stinfo->main, argc, ubp_av, auxvec, stinfo->init, stinfo->fini, rtld_fini, stack_on_entry); diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h index cf49d0a527..0d231912ba 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h @@ -55,6 +55,109 @@ # include <errno.h> +# ifdef SHARED +# define INLINE_VSYSCALL(name, nr, args...) \ + ({ \ + __label__ out; \ + __label__ iserr; \ + INTERNAL_SYSCALL_DECL (sc_err); \ + long int sc_ret; \ + \ + 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 int 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 + +# define INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK(name, err, nr, args...) \ + ({ \ + long int sc_ret = ENOSYS; \ + \ + if (__vdso_##name != NULL) \ + sc_ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, err, nr, ##args); \ + else \ + err = 1 << 28; \ + sc_ret; \ + }) + +/* List of system calls which are supported as vsyscalls. */ +# define HAVE_CLOCK_GETRES_VSYSCALL 1 +# define HAVE_CLOCK_GETTIME_VSYSCALL 1 + +/* Define a macro which expands inline into the wrapper code for a VDSO + call. This use is for internal calls that do not need to handle errors + normally. It will never touch errno. + On powerpc a system call basically clobbers the same registers like a + function call, with the exception of LR (which is needed for the + "sc; bnslr+" sequence) and CR (where only CR0.SO is clobbered to signal + an error return status). */ +# define INTERNAL_VSYSCALL_NCS(funcptr, err, nr, args...) \ + ({ \ + register void *r0 __asm__ ("r0"); \ + register long int r3 __asm__ ("r3"); \ + register long int r4 __asm__ ("r4"); \ + register long int r5 __asm__ ("r5"); \ + register long int r6 __asm__ ("r6"); \ + register long int r7 __asm__ ("r7"); \ + register long int r8 __asm__ ("r8"); \ + register long int r9 __asm__ ("r9"); \ + register long int r10 __asm__ ("r10"); \ + register long int r11 __asm__ ("r11"); \ + register long int r12 __asm__ ("r12"); \ + LOADARGS_##nr (funcptr, args); \ + __asm__ __volatile__ \ + ("mtctr %0\n\t" \ + "bctrl\n\t" \ + "mfcr %0" \ + : "=&r" (r0), \ + "=&r" (r3), "=&r" (r4), "=&r" (r5), "=&r" (r6), "=&r" (r7), \ + "=&r" (r8), "=&r" (r9), "=&r" (r10), "=&r" (r11), "=&r" (r12) \ + : ASM_INPUT_##nr \ + : "cr0", "ctr", "lr", "memory"); \ + err = (long int) r0; \ + (int) r3; \ + }) + # undef INLINE_SYSCALL # define INLINE_SYSCALL(name, nr, args...) \ ({ \ @@ -93,7 +196,7 @@ register long int r10 __asm__ ("r10"); \ register long int r11 __asm__ ("r11"); \ register long int r12 __asm__ ("r12"); \ - LOADARGS_##nr(name, args); \ + LOADARGS_##nr(name, args); \ __asm__ __volatile__ \ ("sc \n\t" \ "mfcr %0" \ @@ -115,11 +218,11 @@ # undef INTERNAL_SYSCALL_ERRNO # define INTERNAL_SYSCALL_ERRNO(val, err) (val) -# define LOADARGS_0(name, dummy) \ +# define LOADARGS_0(name, dummy) \ r0 = name # define LOADARGS_1(name, __arg1) \ long int arg1 = (long int) (__arg1); \ - LOADARGS_0(name, 0); \ + LOADARGS_0(name, 0); \ extern void __illegally_sized_syscall_arg1 (void); \ if (__builtin_classify_type (__arg1) != 5 && sizeof (__arg1) > 4) \ __illegally_sized_syscall_arg1 (); \ diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h index 3ece017563..e0b4cb3eed 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h @@ -62,12 +62,118 @@ #ifdef __ASSEMBLER__ /* This seems to always be the case on PPC. */ -#define ALIGNARG(log2) log2 +# define ALIGNARG(log2) log2 /* For ELF we need the `.type' directive to make shared libs work right. */ -#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg; -#define ASM_SIZE_DIRECTIVE(name) .size name,.-name +# define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg; +# define ASM_SIZE_DIRECTIVE(name) .size name,.-name -#endif /* __ASSEMBLER__ */ +#endif /* __ASSEMBLER__ */ + +/* This version is for kernels that implement system calls that + behave like function calls as far as register saving. + It falls back to the syscall in the case that the vDSO doesn't + exist or fails for ENOSYS */ +#ifdef SHARED +# define INLINE_VSYSCALL(name, nr, args...) \ + ({ \ + __label__ out; \ + __label__ iserr; \ + INTERNAL_SYSCALL_DECL (sc_err); \ + long int sc_ret; \ + \ + 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 int 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 + +/* This version is for internal uses when there is no desire + to set errno */ +#define INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK(name, err, nr, args...) \ + ({ \ + long int sc_ret = ENOSYS; \ + \ + if (__vdso_##name != NULL) \ + sc_ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, err, nr, ##args); \ + else \ + err = 1 << 28; \ + sc_ret; \ + }) + +/* List of system calls which are supported as vsyscalls. */ +#define HAVE_CLOCK_GETRES_VSYSCALL 1 +#define HAVE_CLOCK_GETTIME_VSYSCALL 1 + +/* Define a macro which expands inline into the wrapper code for a system + call. This use is for internal calls that do not need to handle errors + normally. It will never touch errno. This returns just what the kernel + gave back in the non-error (CR0.SO cleared) case, otherwise (CR0.SO set) + the negation of the return value in the kernel gets reverted. */ + +#define INTERNAL_VSYSCALL_NCS(funcptr, err, nr, args...) \ + ({ \ + register void *r0 __asm__ ("r0"); \ + register long int r3 __asm__ ("r3"); \ + register long int r4 __asm__ ("r4"); \ + register long int r5 __asm__ ("r5"); \ + register long int r6 __asm__ ("r6"); \ + register long int r7 __asm__ ("r7"); \ + register long int r8 __asm__ ("r8"); \ + LOADARGS_##nr (funcptr, args); \ + __asm__ __volatile__ \ + ("mtctr %0\n\t" \ + "bctrl\n\t" \ + "mfcr %0\n\t" \ + "0:" \ + : "=&r" (r0), \ + "=&r" (r3), "=&r" (r4), "=&r" (r5), \ + "=&r" (r6), "=&r" (r7), "=&r" (r8) \ + : ASM_INPUT_##nr \ + : "r9", "r10", "r11", "r12", \ + "cr0", "ctr", "lr", "memory"); \ + err = (long int) r0; \ + (int) r3; \ + }) #undef INLINE_SYSCALL @@ -101,7 +207,7 @@ register long int r6 __asm__ ("r6"); \ register long int r7 __asm__ ("r7"); \ register long int r8 __asm__ ("r8"); \ - LOADARGS_##nr(name, args); \ + LOADARGS_##nr (name, ##args); \ __asm__ __volatile__ \ ("sc\n\t" \ "mfcr %0\n\t" \ @@ -116,7 +222,7 @@ (int) r3; \ }) #define INTERNAL_SYSCALL(name, err, nr, args...) \ - INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, ##args) + INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, args) #undef INTERNAL_SYSCALL_DECL #define INTERNAL_SYSCALL_DECL(err) long int err |