The generic vDSO provides a lot common functionality shared between different architectures. SPARC is the last architecture not using it, preventing some necessary code cleanup.
Make use of the generic infrastructure.
Signed-off-by: Thomas Weißschuh thomas.weissschuh@linutronix.de --- arch/sparc/Kconfig | 4 + arch/sparc/include/asm/clocksource.h | 5 - arch/sparc/include/asm/vdso/clocksource.h | 10 ++ arch/sparc/include/asm/vdso/gettimeofday.h | 58 ++++++++-- arch/sparc/include/asm/vdso/vsyscall.h | 10 ++ arch/sparc/include/asm/vvar.h | 75 ------------- arch/sparc/kernel/Makefile | 1 - arch/sparc/kernel/time_64.c | 7 +- arch/sparc/kernel/vdso.c | 69 ------------ arch/sparc/vdso/Makefile | 6 +- arch/sparc/vdso/vclock_gettime.c | 169 ++++------------------------- arch/sparc/vdso/vdso-layout.lds.S | 7 +- arch/sparc/vdso/vma.c | 70 +++--------- 13 files changed, 120 insertions(+), 371 deletions(-)
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 742d1ad7fb9483b11d6d5aac607bf24815b7a237..b6994e8f9ec57abc4e8d0c1e620b7ea90a522705 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -110,6 +110,10 @@ config SPARC64 select NEED_PER_CPU_EMBED_FIRST_CHUNK select NEED_PER_CPU_PAGE_FIRST_CHUNK select ARCH_HAS_CRC32 + select HAVE_GENERIC_VDSO + select GENERIC_TIME_VSYSCALL + select GENERIC_GETTIMEOFDAY + select GENERIC_VDSO_DATA_STORE
config ARCH_PROC_KCORE_TEXT def_bool y diff --git a/arch/sparc/include/asm/clocksource.h b/arch/sparc/include/asm/clocksource.h index 81c59fdeb02e814ffac81397611ee63d684d64b1..68303ad26eb26e99180bb71789f1d6fafe4a2225 100644 --- a/arch/sparc/include/asm/clocksource.h +++ b/arch/sparc/include/asm/clocksource.h @@ -5,9 +5,4 @@ #ifndef _ASM_SPARC_CLOCKSOURCE_H #define _ASM_SPARC_CLOCKSOURCE_H
-/* VDSO clocksources */ -#define VCLOCK_NONE 0 /* Nothing userspace can do. */ -#define VCLOCK_TICK 1 /* Use %tick. */ -#define VCLOCK_STICK 2 /* Use %stick. */ - #endif /* _ASM_SPARC_CLOCKSOURCE_H */ diff --git a/arch/sparc/include/asm/vdso/clocksource.h b/arch/sparc/include/asm/vdso/clocksource.h new file mode 100644 index 0000000000000000000000000000000000000000..007aa8ceaf522ebc11b05dd46dfcdf72a328822f --- /dev/null +++ b/arch/sparc/include/asm/vdso/clocksource.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_VDSO_CLOCKSOURCE_H +#define __ASM_VDSO_CLOCKSOURCE_H + +/* VDSO clocksources */ +#define VDSO_ARCH_CLOCKMODES \ + VDSO_CLOCKMODE_TICK, \ + VDSO_CLOCKMODE_STICK + +#endif /* __ASM_VDSO_CLOCKSOURCE_H */ diff --git a/arch/sparc/include/asm/vdso/gettimeofday.h b/arch/sparc/include/asm/vdso/gettimeofday.h index 429dc080568f59145cc0bc696060adeb60ac177a..a35875fba45470ba961a7df3ae52bc17d2a4a4a0 100644 --- a/arch/sparc/include/asm/vdso/gettimeofday.h +++ b/arch/sparc/include/asm/vdso/gettimeofday.h @@ -9,15 +9,14 @@ #include <uapi/linux/time.h> #include <uapi/linux/unistd.h>
+#include <vdso/align.h> +#include <vdso/clocksource.h> +#include <vdso/datapage.h> +#include <vdso/page.h> + #include <linux/types.h> -#include <asm/vvar.h>
#ifdef CONFIG_SPARC64 -static __always_inline u64 vdso_shift_ns(u64 val, u32 amt) -{ - return val >> amt; -} - static __always_inline u64 vread_tick(void) { u64 ret; @@ -48,6 +47,7 @@ static __always_inline u64 vdso_shift_ns(u64 val, u32 amt) : "g1"); return ret; } +#define vdso_shift_ns vdso_shift_ns
static __always_inline u64 vread_tick(void) { @@ -70,9 +70,9 @@ static __always_inline u64 vread_tick_stick(void) } #endif
-static __always_inline u64 __arch_get_hw_counter(struct vvar_data *vvar) +static __always_inline u64 __arch_get_hw_counter(s32 clock_mode, const struct vdso_time_data *vd) { - if (likely(vvar->vclock_mode == VCLOCK_STICK)) + if (likely(clock_mode == VDSO_CLOCKMODE_STICK)) return vread_tick_stick(); else return vread_tick(); @@ -102,7 +102,20 @@ static __always_inline u64 __arch_get_hw_counter(struct vvar_data *vvar) "cc", "memory"
static __always_inline -long clock_gettime_fallback(clockid_t clock, struct __kernel_old_timespec *ts) +long clock_gettime_fallback(clockid_t clock, struct __kernel_timespec *ts) +{ + register long num __asm__("g1") = __NR_clock_gettime; + register long o0 __asm__("o0") = clock; + register long o1 __asm__("o1") = (long) ts; + + __asm__ __volatile__(SYSCALL_STRING : "=r" (o0) : "r" (num), + "0" (o0), "r" (o1) : SYSCALL_CLOBBERS); + return o0; +} + +#ifndef CONFIG_SPARC64 +static __always_inline +long clock_gettime32_fallback(clockid_t clock, struct old_timespec32 *ts) { register long num __asm__("g1") = __NR_clock_gettime; register long o0 __asm__("o0") = clock; @@ -112,6 +125,7 @@ long clock_gettime_fallback(clockid_t clock, struct __kernel_old_timespec *ts) "0" (o0), "r" (o1) : SYSCALL_CLOBBERS); return o0; } +#endif
static __always_inline long gettimeofday_fallback(struct __kernel_old_timeval *tv, struct timezone *tz) @@ -125,4 +139,30 @@ long gettimeofday_fallback(struct __kernel_old_timeval *tv, struct timezone *tz) return o0; }
+static __always_inline const struct vdso_time_data *__arch_get_vdso_u_time_data(void) +{ + unsigned long ret; + + /* + * SPARC does not support native PC-relative code relocations. + * Calculate the address manually, works for 32 and 64 bit code. + */ + __asm__ __volatile__( + "1:\n" + "call 3f\n" // Jump over the embedded data and set up %o7 + "nop\n" // Delay slot + "2:\n" + ".word vdso_u_time_data - .\n" // Embedded offset to external symbol + "3:\n" + "add %%o7, 2b - 1b, %%o7\n" // Point %o7 to the embedded offset + "ldsw [%%o7], %0\n" // Load the offset + "add %0, %%o7, %0\n" // Calculate the absolute address + : "=r" (ret) + : + : "o7"); + + return (const struct vdso_time_data *)ret; +} +#define __arch_get_vdso_u_time_data __arch_get_vdso_u_time_data + #endif /* _ASM_SPARC_VDSO_GETTIMEOFDAY_H */ diff --git a/arch/sparc/include/asm/vdso/vsyscall.h b/arch/sparc/include/asm/vdso/vsyscall.h new file mode 100644 index 0000000000000000000000000000000000000000..8bfe703fedc56f9334773b26b5e1ecec42781378 --- /dev/null +++ b/arch/sparc/include/asm/vdso/vsyscall.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_SPARC_VDSO_VSYSCALL_H +#define _ASM_SPARC_VDSO_VSYSCALL_H + +#define __VDSO_PAGES 4 + +#include <asm-generic/vdso/vsyscall.h> + +#endif /* _ASM_SPARC_VDSO_VSYSCALL_H */ diff --git a/arch/sparc/include/asm/vvar.h b/arch/sparc/include/asm/vvar.h deleted file mode 100644 index 6eaf5cfcaae1319808e63884d624899895d9b6a5..0000000000000000000000000000000000000000 --- a/arch/sparc/include/asm/vvar.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. - */ - -#ifndef _ASM_SPARC_VVAR_DATA_H -#define _ASM_SPARC_VVAR_DATA_H - -#include <asm/clocksource.h> -#include <asm/processor.h> -#include <asm/barrier.h> -#include <linux/time.h> -#include <linux/types.h> - -struct vvar_data { - unsigned int seq; - - int vclock_mode; - struct { /* extract of a clocksource struct */ - u64 cycle_last; - u64 mask; - int mult; - int shift; - } clock; - /* open coded 'struct timespec' */ - u64 wall_time_sec; - u64 wall_time_snsec; - u64 monotonic_time_snsec; - u64 monotonic_time_sec; - u64 monotonic_time_coarse_sec; - u64 monotonic_time_coarse_nsec; - u64 wall_time_coarse_sec; - u64 wall_time_coarse_nsec; - - int tz_minuteswest; - int tz_dsttime; -}; - -extern struct vvar_data *vvar_data; -extern int vdso_fix_stick; - -static inline unsigned int vvar_read_begin(const struct vvar_data *s) -{ - unsigned int ret; - -repeat: - ret = READ_ONCE(s->seq); - if (unlikely(ret & 1)) { - cpu_relax(); - goto repeat; - } - smp_rmb(); /* Finish all reads before we return seq */ - return ret; -} - -static inline int vvar_read_retry(const struct vvar_data *s, - unsigned int start) -{ - smp_rmb(); /* Finish all reads before checking the value of seq */ - return unlikely(s->seq != start); -} - -static inline void vvar_write_begin(struct vvar_data *s) -{ - ++s->seq; - smp_wmb(); /* Makes sure that increment of seq is reflected */ -} - -static inline void vvar_write_end(struct vvar_data *s) -{ - smp_wmb(); /* Makes the value of seq current before we increment */ - ++s->seq; -} - - -#endif /* _ASM_SPARC_VVAR_DATA_H */ diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 36f2727e1445d0ea6e1c1a9ed716e04338a0c9a6..7a063cd4b6d3600e8e77efad5d69ac1d9fad2f75 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -43,7 +43,6 @@ obj-$(CONFIG_SPARC32) += systbls_32.o obj-y += time_$(BITS).o obj-$(CONFIG_SPARC32) += windows.o obj-y += cpu.o -obj-$(CONFIG_SPARC64) += vdso.o obj-$(CONFIG_SPARC32) += devices.o obj-y += ptrace_$(BITS).o obj-y += unaligned_$(BITS).o diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index 0077286b1f67ffc6b63c78709fbd66aaa3f3bedc..87b267043ccd21b9397e316b017f0ae3ab8585c6 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -48,7 +48,6 @@ #include <linux/uaccess.h> #include <asm/irq_regs.h> #include <asm/cacheflush.h> -#include <asm/clocksource.h>
#include "entry.h" #include "kernel.h" @@ -839,14 +838,14 @@ void __init time_init_early(void) if (tlb_type == spitfire) { if (is_hummingbird()) { init_tick_ops(&hbtick_operations); - clocksource_tick.vdso_clock_mode = VCLOCK_NONE; + clocksource_tick.vdso_clock_mode = VDSO_CLOCKMODE_NONE; } else { init_tick_ops(&tick_operations); - clocksource_tick.vdso_clock_mode = VCLOCK_TICK; + clocksource_tick.vdso_clock_mode = VDSO_CLOCKMODE_TICK; } } else { init_tick_ops(&stick_operations); - clocksource_tick.vdso_clock_mode = VCLOCK_STICK; + clocksource_tick.vdso_clock_mode = VDSO_CLOCKMODE_STICK; } }
diff --git a/arch/sparc/kernel/vdso.c b/arch/sparc/kernel/vdso.c deleted file mode 100644 index a79937998a13b9142cc887dcaf6488571f9557eb..0000000000000000000000000000000000000000 --- a/arch/sparc/kernel/vdso.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2001 Andrea Arcangeli andrea@suse.de SuSE - * Copyright 2003 Andi Kleen, SuSE Labs. - * - * Thanks to hpa@transmeta.com for some useful hint. - * Special thanks to Ingo Molnar for his early experience with - * a different vsyscall implementation for Linux/IA32 and for the name. - */ - -#include <linux/time.h> -#include <linux/timekeeper_internal.h> - -#include <asm/vvar.h> - -void update_vsyscall_tz(void) -{ - if (unlikely(vvar_data == NULL)) - return; - - vvar_data->tz_minuteswest = sys_tz.tz_minuteswest; - vvar_data->tz_dsttime = sys_tz.tz_dsttime; -} - -void update_vsyscall(struct timekeeper *tk) -{ - struct vvar_data *vdata = vvar_data; - - if (unlikely(vdata == NULL)) - return; - - vvar_write_begin(vdata); - vdata->vclock_mode = tk->tkr_mono.clock->vdso_clock_mode; - vdata->clock.cycle_last = tk->tkr_mono.cycle_last; - vdata->clock.mask = tk->tkr_mono.mask; - vdata->clock.mult = tk->tkr_mono.mult; - vdata->clock.shift = tk->tkr_mono.shift; - - vdata->wall_time_sec = tk->xtime_sec; - vdata->wall_time_snsec = tk->tkr_mono.xtime_nsec; - - vdata->monotonic_time_sec = tk->xtime_sec + - tk->wall_to_monotonic.tv_sec; - vdata->monotonic_time_snsec = tk->tkr_mono.xtime_nsec + - (tk->wall_to_monotonic.tv_nsec << - tk->tkr_mono.shift); - - while (vdata->monotonic_time_snsec >= - (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) { - vdata->monotonic_time_snsec -= - ((u64)NSEC_PER_SEC) << tk->tkr_mono.shift; - vdata->monotonic_time_sec++; - } - - vdata->wall_time_coarse_sec = tk->xtime_sec; - vdata->wall_time_coarse_nsec = - (long)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift); - - vdata->monotonic_time_coarse_sec = - vdata->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec; - vdata->monotonic_time_coarse_nsec = - vdata->wall_time_coarse_nsec + tk->wall_to_monotonic.tv_nsec; - - while (vdata->monotonic_time_coarse_nsec >= NSEC_PER_SEC) { - vdata->monotonic_time_coarse_nsec -= NSEC_PER_SEC; - vdata->monotonic_time_coarse_sec++; - } - - vvar_write_end(vdata); -} diff --git a/arch/sparc/vdso/Makefile b/arch/sparc/vdso/Makefile index e8315c6acb743137089d8e77d3539db63979e959..95b5d6b29a713293c1622c9a51aa2d6fa9f9fff6 100644 --- a/arch/sparc/vdso/Makefile +++ b/arch/sparc/vdso/Makefile @@ -3,6 +3,9 @@ # Building vDSO images for sparc. #
+# Include the generic Makefile to check the built vDSO: +include $(srctree)/lib/vdso/Makefile.include + # files to link into the vdso vobjs-y := vdso-note.o vclock_gettime.o
@@ -101,6 +104,7 @@ $(obj)/vdso32.so.dbg: FORCE \ quiet_cmd_vdso = VDSO $@ cmd_vdso = $(LD) -nostdlib -o $@ \ $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \ - -T $(filter %.lds,$^) $(filter %.o,$^) + -T $(filter %.lds,$^) $(filter %.o,$^); \ + $(cmd_vdso_check)
VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic --no-undefined -z noexecstack diff --git a/arch/sparc/vdso/vclock_gettime.c b/arch/sparc/vdso/vclock_gettime.c index e768c0b84b3420deab2f74335892d40a5b515ee7..093a7ff4dafce1cf0af5af4c303bef86e159858a 100644 --- a/arch/sparc/vdso/vclock_gettime.c +++ b/arch/sparc/vdso/vclock_gettime.c @@ -12,169 +12,40 @@ * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. */
-#include <linux/kernel.h> -#include <linux/string.h> -#include <asm/io.h> -#include <asm/timex.h> -#include <asm/clocksource.h> -#include <asm/vdso/gettimeofday.h> -#include <asm/vvar.h> +#include <linux/compiler.h> +#include <linux/types.h>
-/* - * Compute the vvar page's address in the process address space, and return it - * as a pointer to the vvar_data. - */ -notrace static __always_inline struct vvar_data *get_vvar_data(void) -{ - unsigned long ret; +#include <vdso/gettime.h>
- /* - * vdso data page is the first vDSO page so grab the PC - * and move up a page to get to the data page. - */ - __asm__("rd %%pc, %0" : "=r" (ret)); - ret &= ~(8192 - 1); - ret -= 8192; +#include <asm/vdso/gettimeofday.h>
- return (struct vvar_data *) ret; -} +#include "../../../../lib/vdso/gettimeofday.c"
-notrace static __always_inline u64 vgetsns(struct vvar_data *vvar) +int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) { - u64 v; - u64 cycles = __arch_get_hw_counter(vvar); - - v = (cycles - vvar->clock.cycle_last) & vvar->clock.mask; - return v * vvar->clock.mult; + return __cvdso_gettimeofday(tv, tz); }
-notrace static __always_inline int do_realtime(struct vvar_data *vvar, - struct __kernel_old_timespec *ts) -{ - unsigned long seq; - u64 ns; - - do { - seq = vvar_read_begin(vvar); - ts->tv_sec = vvar->wall_time_sec; - ns = vvar->wall_time_snsec; - ns += vgetsns(vvar); - ns = vdso_shift_ns(ns, vvar->clock.shift); - } while (unlikely(vvar_read_retry(vvar, seq))); - - ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); - ts->tv_nsec = ns; +int gettimeofday(struct __kernel_old_timeval *, struct timezone *) + __weak __alias(__vdso_gettimeofday);
- return 0; -} - -notrace static __always_inline int do_monotonic(struct vvar_data *vvar, - struct __kernel_old_timespec *ts) +#if defined(CONFIG_SPARC64) +int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) { - unsigned long seq; - u64 ns; - - do { - seq = vvar_read_begin(vvar); - ts->tv_sec = vvar->monotonic_time_sec; - ns = vvar->monotonic_time_snsec; - ns += vgetsns(vvar); - ns = vdso_shift_ns(ns, vvar->clock.shift); - } while (unlikely(vvar_read_retry(vvar, seq))); - - ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); - ts->tv_nsec = ns; - - return 0; -} - -notrace static int do_realtime_coarse(struct vvar_data *vvar, - struct __kernel_old_timespec *ts) -{ - unsigned long seq; - - do { - seq = vvar_read_begin(vvar); - ts->tv_sec = vvar->wall_time_coarse_sec; - ts->tv_nsec = vvar->wall_time_coarse_nsec; - } while (unlikely(vvar_read_retry(vvar, seq))); - return 0; + return __cvdso_clock_gettime(clock, ts); }
-notrace static int do_monotonic_coarse(struct vvar_data *vvar, - struct __kernel_old_timespec *ts) -{ - unsigned long seq; - - do { - seq = vvar_read_begin(vvar); - ts->tv_sec = vvar->monotonic_time_coarse_sec; - ts->tv_nsec = vvar->monotonic_time_coarse_nsec; - } while (unlikely(vvar_read_retry(vvar, seq))); +int clock_gettime(clockid_t, struct __kernel_timespec *) + __weak __alias(__vdso_clock_gettime);
- return 0; -} +#else
-notrace int -__vdso_clock_gettime(clockid_t clock, struct __kernel_old_timespec *ts) +int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) { - struct vvar_data *vvd = get_vvar_data(); - - switch (clock) { - case CLOCK_REALTIME: - if (unlikely(vvd->vclock_mode == VCLOCK_NONE)) - break; - return do_realtime(vvd, ts); - case CLOCK_MONOTONIC: - if (unlikely(vvd->vclock_mode == VCLOCK_NONE)) - break; - return do_monotonic(vvd, ts); - case CLOCK_REALTIME_COARSE: - return do_realtime_coarse(vvd, ts); - case CLOCK_MONOTONIC_COARSE: - return do_monotonic_coarse(vvd, ts); - } - /* - * Unknown clock ID ? Fall back to the syscall. - */ - return clock_gettime_fallback(clock, ts); + return __cvdso_clock_gettime32(clock, ts); } -int -clock_gettime(clockid_t, struct __kernel_old_timespec *) - __attribute__((weak, alias("__vdso_clock_gettime")));
-notrace int -__vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) -{ - struct vvar_data *vvd = get_vvar_data(); +int clock_gettime(clockid_t, struct old_timespec32 *) + __weak __alias(__vdso_clock_gettime);
- if (likely(vvd->vclock_mode != VCLOCK_NONE)) { - if (likely(tv != NULL)) { - union tstv_t { - struct __kernel_old_timespec ts; - struct __kernel_old_timeval tv; - } *tstv = (union tstv_t *) tv; - do_realtime(vvd, &tstv->ts); - /* - * Assign before dividing to ensure that the division is - * done in the type of tv_usec, not tv_nsec. - * - * There cannot be > 1 billion usec in a second: - * do_realtime() has already distributed such overflow - * into tv_sec. So we can assign it to an int safely. - */ - tstv->tv.tv_usec = tstv->ts.tv_nsec; - tstv->tv.tv_usec /= 1000; - } - if (unlikely(tz != NULL)) { - /* Avoid memcpy. Some old compilers fail to inline it */ - tz->tz_minuteswest = vvd->tz_minuteswest; - tz->tz_dsttime = vvd->tz_dsttime; - } - return 0; - } - return gettimeofday_fallback(tv, tz); -} -int -gettimeofday(struct __kernel_old_timeval *, struct timezone *) - __attribute__((weak, alias("__vdso_gettimeofday"))); +#endif diff --git a/arch/sparc/vdso/vdso-layout.lds.S b/arch/sparc/vdso/vdso-layout.lds.S index 9e0804789d11696948f11be367480b530a1f18d9..180e5d0ee07170a5dec88016a304a44f87eb8d88 100644 --- a/arch/sparc/vdso/vdso-layout.lds.S +++ b/arch/sparc/vdso/vdso-layout.lds.S @@ -4,6 +4,10 @@ * This script controls its layout. */
+#include <vdso/datapage.h> +#include <vdso/page.h> +#include <asm/vdso/vsyscall.h> + SECTIONS { /* @@ -13,8 +17,7 @@ SECTIONS * segment. Page size is 8192 for both 64-bit and 32-bit vdso binaries */
- vvar_start = . -8192; - vvar_data = vvar_start; + VDSO_VVAR_SYMS
. = SIZEOF_HEADERS;
diff --git a/arch/sparc/vdso/vma.c b/arch/sparc/vdso/vma.c index 582d84e2e5ba8932f39948bb0ca2678fc8f06a10..38a664d697829b8203f0c7cd9e6d7cc8bed4796f 100644 --- a/arch/sparc/vdso/vma.c +++ b/arch/sparc/vdso/vma.c @@ -16,17 +16,16 @@ #include <linux/linkage.h> #include <linux/random.h> #include <linux/elf.h> +#include <linux/vdso_datastore.h> #include <asm/cacheflush.h> #include <asm/spitfire.h> #include <asm/vdso.h> -#include <asm/vvar.h> #include <asm/page.h>
-unsigned int __read_mostly vdso_enabled = 1; +#include <vdso/datapage.h> +#include <asm/vdso/vsyscall.h>
-static struct vm_special_mapping vvar_mapping = { - .name = "[vvar]" -}; +unsigned int __read_mostly vdso_enabled = 1;
#ifdef CONFIG_SPARC64 static struct vm_special_mapping vdso_mapping64 = { @@ -40,10 +39,8 @@ static struct vm_special_mapping vdso_mapping32 = { }; #endif
-struct vvar_data *vvar_data; - /* - * Allocate pages for the vdso and vvar, and copy in the vdso text from the + * Allocate pages for the vdso and copy in the vdso text from the * kernel image. */ static int __init init_vdso_image(const struct vdso_image *image, @@ -51,9 +48,8 @@ static int __init init_vdso_image(const struct vdso_image *image, bool elf64) { int cnpages = (image->size) / PAGE_SIZE; - struct page *dp, **dpp = NULL; struct page *cp, **cpp = NULL; - int i, dnpages = 0; + int i;
/* * First, the vdso text. This is initialied data, an integral number of @@ -76,31 +72,6 @@ static int __init init_vdso_image(const struct vdso_image *image, copy_page(page_address(cp), image->data + i * PAGE_SIZE); }
- /* - * Now the vvar page. This is uninitialized data. - */ - - if (vvar_data == NULL) { - dnpages = (sizeof(struct vvar_data) / PAGE_SIZE) + 1; - if (WARN_ON(dnpages != 1)) - goto oom; - dpp = kcalloc(dnpages, sizeof(struct page *), GFP_KERNEL); - vvar_mapping.pages = dpp; - - if (!dpp) - goto oom; - - dp = alloc_page(GFP_KERNEL); - if (!dp) - goto oom; - - dpp[0] = dp; - vvar_data = page_address(dp); - memset(vvar_data, 0, PAGE_SIZE); - - vvar_data->seq = 0; - } - return 0; oom: if (cpp != NULL) { @@ -112,15 +83,6 @@ static int __init init_vdso_image(const struct vdso_image *image, vdso_mapping->pages = NULL; }
- if (dpp != NULL) { - for (i = 0; i < dnpages; i++) { - if (dpp[i] != NULL) - __free_page(dpp[i]); - } - kfree(dpp); - vvar_mapping.pages = NULL; - } - pr_warn("Cannot allocate vdso\n"); vdso_enabled = 0; return -ENOMEM; @@ -155,9 +117,12 @@ static unsigned long vdso_addr(unsigned long start, unsigned int len) return start + (offset << PAGE_SHIFT); }
+static_assert(VDSO_NR_PAGES == __VDSO_PAGES); + static int map_vdso(const struct vdso_image *image, struct vm_special_mapping *vdso_mapping) { + const size_t area_size = image->size + VDSO_NR_PAGES * PAGE_SIZE; struct mm_struct *mm = current->mm; struct vm_area_struct *vma; unsigned long text_start, addr = 0; @@ -170,23 +135,20 @@ static int map_vdso(const struct vdso_image *image, * region is free. */ if (current->flags & PF_RANDOMIZE) { - addr = get_unmapped_area(NULL, 0, - image->size - image->sym_vvar_start, - 0, 0); + addr = get_unmapped_area(NULL, 0, area_size, 0, 0); if (IS_ERR_VALUE(addr)) { ret = addr; goto up_fail; } - addr = vdso_addr(addr, image->size - image->sym_vvar_start); + addr = vdso_addr(addr, area_size); } - addr = get_unmapped_area(NULL, addr, - image->size - image->sym_vvar_start, 0, 0); + addr = get_unmapped_area(NULL, addr, area_size, 0, 0); if (IS_ERR_VALUE(addr)) { ret = addr; goto up_fail; }
- text_start = addr - image->sym_vvar_start; + text_start = addr + VDSO_NR_PAGES * PAGE_SIZE; current->mm->context.vdso = (void __user *)text_start;
/* @@ -204,11 +166,7 @@ static int map_vdso(const struct vdso_image *image, goto up_fail; }
- vma = _install_special_mapping(mm, - addr, - -image->sym_vvar_start, - VM_READ|VM_MAYREAD, - &vvar_mapping); + vma = vdso_install_vvar_mapping(mm, addr);
if (IS_ERR(vma)) { ret = PTR_ERR(vma);