Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

sparc64: vdso: Switch to the generic vDSO library

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>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Tested-by: Andreas Larsson <andreas@gaisler.com>
Reviewed-by: Andreas Larsson <andreas@gaisler.com>
Acked-by: Andreas Larsson <andreas@gaisler.com>
Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-10-d8eb3b0e1410@linutronix.de

authored by

Thomas Weißschuh and committed by
Thomas Gleixner
7c5fc16c e13e3059

+123 -380
+2 -1
arch/sparc/Kconfig
··· 104 104 select ARCH_USE_QUEUED_RWLOCKS 105 105 select ARCH_USE_QUEUED_SPINLOCKS 106 106 select GENERIC_TIME_VSYSCALL 107 - select ARCH_CLOCKSOURCE_DATA 108 107 select ARCH_HAS_PTE_SPECIAL 109 108 select PCI_DOMAINS if PCI 110 109 select ARCH_HAS_GIGANTIC_PAGE ··· 114 115 select ARCH_SUPPORTS_SCHED_SMT if SMP 115 116 select ARCH_SUPPORTS_SCHED_MC if SMP 116 117 select ARCH_HAS_LAZY_MMU_MODE 118 + select HAVE_GENERIC_VDSO 119 + select GENERIC_GETTIMEOFDAY 117 120 118 121 config ARCH_PROC_KCORE_TEXT 119 122 def_bool y
-9
arch/sparc/include/asm/clocksource.h
··· 5 5 #ifndef _ASM_SPARC_CLOCKSOURCE_H 6 6 #define _ASM_SPARC_CLOCKSOURCE_H 7 7 8 - /* VDSO clocksources */ 9 - #define VCLOCK_NONE 0 /* Nothing userspace can do. */ 10 - #define VCLOCK_TICK 1 /* Use %tick. */ 11 - #define VCLOCK_STICK 2 /* Use %stick. */ 12 - 13 - struct arch_clocksource_data { 14 - int vclock_mode; 15 - }; 16 - 17 8 #endif /* _ASM_SPARC_CLOCKSOURCE_H */
+10
arch/sparc/include/asm/vdso/clocksource.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __ASM_VDSO_CLOCKSOURCE_H 3 + #define __ASM_VDSO_CLOCKSOURCE_H 4 + 5 + /* VDSO clocksources */ 6 + #define VDSO_ARCH_CLOCKMODES \ 7 + VDSO_CLOCKMODE_TICK, \ 8 + VDSO_CLOCKMODE_STICK 9 + 10 + #endif /* __ASM_VDSO_CLOCKSOURCE_H */
+49 -9
arch/sparc/include/asm/vdso/gettimeofday.h
··· 9 9 #include <uapi/linux/time.h> 10 10 #include <uapi/linux/unistd.h> 11 11 12 + #include <vdso/align.h> 13 + #include <vdso/clocksource.h> 14 + #include <vdso/datapage.h> 15 + #include <vdso/page.h> 16 + 12 17 #include <linux/types.h> 13 - #include <asm/vvar.h> 14 18 15 19 #ifdef CONFIG_SPARC64 16 - static __always_inline u64 vdso_shift_ns(u64 val, u32 amt) 17 - { 18 - return val >> amt; 19 - } 20 - 21 20 static __always_inline u64 vread_tick(void) 22 21 { 23 22 u64 ret; ··· 47 48 : "g1"); 48 49 return ret; 49 50 } 51 + #define vdso_shift_ns vdso_shift_ns 50 52 51 53 static __always_inline u64 vread_tick(void) 52 54 { ··· 70 70 } 71 71 #endif 72 72 73 - static __always_inline u64 __arch_get_hw_counter(struct vvar_data *vvar) 73 + static __always_inline u64 __arch_get_hw_counter(s32 clock_mode, const struct vdso_time_data *vd) 74 74 { 75 - if (likely(vvar->vclock_mode == VCLOCK_STICK)) 75 + if (likely(clock_mode == VDSO_CLOCKMODE_STICK)) 76 76 return vread_tick_stick(); 77 77 else 78 78 return vread_tick(); ··· 102 102 "cc", "memory" 103 103 104 104 static __always_inline 105 - long clock_gettime_fallback(clockid_t clock, struct __kernel_old_timespec *ts) 105 + long clock_gettime_fallback(clockid_t clock, struct __kernel_timespec *ts) 106 106 { 107 107 register long num __asm__("g1") = __NR_clock_gettime; 108 108 register long o0 __asm__("o0") = clock; ··· 112 112 "0" (o0), "r" (o1) : SYSCALL_CLOBBERS); 113 113 return o0; 114 114 } 115 + 116 + #ifndef CONFIG_SPARC64 117 + static __always_inline 118 + long clock_gettime32_fallback(clockid_t clock, struct old_timespec32 *ts) 119 + { 120 + register long num __asm__("g1") = __NR_clock_gettime; 121 + register long o0 __asm__("o0") = clock; 122 + register long o1 __asm__("o1") = (long) ts; 123 + 124 + __asm__ __volatile__(SYSCALL_STRING : "=r" (o0) : "r" (num), 125 + "0" (o0), "r" (o1) : SYSCALL_CLOBBERS); 126 + return o0; 127 + } 128 + #endif 115 129 116 130 static __always_inline 117 131 long gettimeofday_fallback(struct __kernel_old_timeval *tv, struct timezone *tz) ··· 138 124 "0" (o0), "r" (o1) : SYSCALL_CLOBBERS); 139 125 return o0; 140 126 } 127 + 128 + static __always_inline const struct vdso_time_data *__arch_get_vdso_u_time_data(void) 129 + { 130 + unsigned long ret; 131 + 132 + /* 133 + * SPARC does not support native PC-relative code relocations. 134 + * Calculate the address manually, works for 32 and 64 bit code. 135 + */ 136 + __asm__ __volatile__( 137 + "1:\n" 138 + "call 3f\n" // Jump over the embedded data and set up %o7 139 + "nop\n" // Delay slot 140 + "2:\n" 141 + ".word vdso_u_time_data - .\n" // Embedded offset to external symbol 142 + "3:\n" 143 + "add %%o7, 2b - 1b, %%o7\n" // Point %o7 to the embedded offset 144 + "ldsw [%%o7], %0\n" // Load the offset 145 + "add %0, %%o7, %0\n" // Calculate the absolute address 146 + : "=r" (ret) 147 + : 148 + : "o7"); 149 + 150 + return (const struct vdso_time_data *)ret; 151 + } 152 + #define __arch_get_vdso_u_time_data __arch_get_vdso_u_time_data 141 153 142 154 #endif /* _ASM_SPARC_VDSO_GETTIMEOFDAY_H */
+10
arch/sparc/include/asm/vdso/vsyscall.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef _ASM_SPARC_VDSO_VSYSCALL_H 4 + #define _ASM_SPARC_VDSO_VSYSCALL_H 5 + 6 + #define __VDSO_PAGES 4 7 + 8 + #include <asm-generic/vdso/vsyscall.h> 9 + 10 + #endif /* _ASM_SPARC_VDSO_VSYSCALL_H */
-75
arch/sparc/include/asm/vvar.h
··· 1 - /* 2 - * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. 3 - */ 4 - 5 - #ifndef _ASM_SPARC_VVAR_DATA_H 6 - #define _ASM_SPARC_VVAR_DATA_H 7 - 8 - #include <asm/clocksource.h> 9 - #include <asm/processor.h> 10 - #include <asm/barrier.h> 11 - #include <linux/time.h> 12 - #include <linux/types.h> 13 - 14 - struct vvar_data { 15 - unsigned int seq; 16 - 17 - int vclock_mode; 18 - struct { /* extract of a clocksource struct */ 19 - u64 cycle_last; 20 - u64 mask; 21 - int mult; 22 - int shift; 23 - } clock; 24 - /* open coded 'struct timespec' */ 25 - u64 wall_time_sec; 26 - u64 wall_time_snsec; 27 - u64 monotonic_time_snsec; 28 - u64 monotonic_time_sec; 29 - u64 monotonic_time_coarse_sec; 30 - u64 monotonic_time_coarse_nsec; 31 - u64 wall_time_coarse_sec; 32 - u64 wall_time_coarse_nsec; 33 - 34 - int tz_minuteswest; 35 - int tz_dsttime; 36 - }; 37 - 38 - extern struct vvar_data *vvar_data; 39 - extern int vdso_fix_stick; 40 - 41 - static inline unsigned int vvar_read_begin(const struct vvar_data *s) 42 - { 43 - unsigned int ret; 44 - 45 - repeat: 46 - ret = READ_ONCE(s->seq); 47 - if (unlikely(ret & 1)) { 48 - cpu_relax(); 49 - goto repeat; 50 - } 51 - smp_rmb(); /* Finish all reads before we return seq */ 52 - return ret; 53 - } 54 - 55 - static inline int vvar_read_retry(const struct vvar_data *s, 56 - unsigned int start) 57 - { 58 - smp_rmb(); /* Finish all reads before checking the value of seq */ 59 - return unlikely(s->seq != start); 60 - } 61 - 62 - static inline void vvar_write_begin(struct vvar_data *s) 63 - { 64 - ++s->seq; 65 - smp_wmb(); /* Makes sure that increment of seq is reflected */ 66 - } 67 - 68 - static inline void vvar_write_end(struct vvar_data *s) 69 - { 70 - smp_wmb(); /* Makes the value of seq current before we increment */ 71 - ++s->seq; 72 - } 73 - 74 - 75 - #endif /* _ASM_SPARC_VVAR_DATA_H */
-1
arch/sparc/kernel/Makefile
··· 41 41 obj-y += time_$(BITS).o 42 42 obj-$(CONFIG_SPARC32) += windows.o 43 43 obj-y += cpu.o 44 - obj-$(CONFIG_SPARC64) += vdso.o 45 44 obj-$(CONFIG_SPARC32) += devices.o 46 45 obj-y += ptrace_$(BITS).o 47 46 obj-y += unaligned_$(BITS).o
+3 -3
arch/sparc/kernel/time_64.c
··· 838 838 if (tlb_type == spitfire) { 839 839 if (is_hummingbird()) { 840 840 init_tick_ops(&hbtick_operations); 841 - clocksource_tick.archdata.vclock_mode = VCLOCK_NONE; 841 + clocksource_tick.vdso_clock_mode = VDSO_CLOCKMODE_NONE; 842 842 } else { 843 843 init_tick_ops(&tick_operations); 844 - clocksource_tick.archdata.vclock_mode = VCLOCK_TICK; 844 + clocksource_tick.vdso_clock_mode = VDSO_CLOCKMODE_TICK; 845 845 } 846 846 } else { 847 847 init_tick_ops(&stick_operations); 848 - clocksource_tick.archdata.vclock_mode = VCLOCK_STICK; 848 + clocksource_tick.vdso_clock_mode = VDSO_CLOCKMODE_STICK; 849 849 } 850 850 } 851 851
-69
arch/sparc/kernel/vdso.c
··· 1 - /* 2 - * Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE 3 - * Copyright 2003 Andi Kleen, SuSE Labs. 4 - * 5 - * Thanks to hpa@transmeta.com for some useful hint. 6 - * Special thanks to Ingo Molnar for his early experience with 7 - * a different vsyscall implementation for Linux/IA32 and for the name. 8 - */ 9 - 10 - #include <linux/time.h> 11 - #include <linux/timekeeper_internal.h> 12 - 13 - #include <asm/vvar.h> 14 - 15 - void update_vsyscall_tz(void) 16 - { 17 - if (unlikely(vvar_data == NULL)) 18 - return; 19 - 20 - vvar_data->tz_minuteswest = sys_tz.tz_minuteswest; 21 - vvar_data->tz_dsttime = sys_tz.tz_dsttime; 22 - } 23 - 24 - void update_vsyscall(struct timekeeper *tk) 25 - { 26 - struct vvar_data *vdata = vvar_data; 27 - 28 - if (unlikely(vdata == NULL)) 29 - return; 30 - 31 - vvar_write_begin(vdata); 32 - vdata->vclock_mode = tk->tkr_mono.clock->archdata.vclock_mode; 33 - vdata->clock.cycle_last = tk->tkr_mono.cycle_last; 34 - vdata->clock.mask = tk->tkr_mono.mask; 35 - vdata->clock.mult = tk->tkr_mono.mult; 36 - vdata->clock.shift = tk->tkr_mono.shift; 37 - 38 - vdata->wall_time_sec = tk->xtime_sec; 39 - vdata->wall_time_snsec = tk->tkr_mono.xtime_nsec; 40 - 41 - vdata->monotonic_time_sec = tk->xtime_sec + 42 - tk->wall_to_monotonic.tv_sec; 43 - vdata->monotonic_time_snsec = tk->tkr_mono.xtime_nsec + 44 - (tk->wall_to_monotonic.tv_nsec << 45 - tk->tkr_mono.shift); 46 - 47 - while (vdata->monotonic_time_snsec >= 48 - (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) { 49 - vdata->monotonic_time_snsec -= 50 - ((u64)NSEC_PER_SEC) << tk->tkr_mono.shift; 51 - vdata->monotonic_time_sec++; 52 - } 53 - 54 - vdata->wall_time_coarse_sec = tk->xtime_sec; 55 - vdata->wall_time_coarse_nsec = 56 - (long)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift); 57 - 58 - vdata->monotonic_time_coarse_sec = 59 - vdata->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec; 60 - vdata->monotonic_time_coarse_nsec = 61 - vdata->wall_time_coarse_nsec + tk->wall_to_monotonic.tv_nsec; 62 - 63 - while (vdata->monotonic_time_coarse_nsec >= NSEC_PER_SEC) { 64 - vdata->monotonic_time_coarse_nsec -= NSEC_PER_SEC; 65 - vdata->monotonic_time_coarse_sec++; 66 - } 67 - 68 - vvar_write_end(vdata); 69 - }
+5 -1
arch/sparc/vdso/Makefile
··· 3 3 # Building vDSO images for sparc. 4 4 # 5 5 6 + # Include the generic Makefile to check the built vDSO: 7 + include $(srctree)/lib/vdso/Makefile.include 8 + 6 9 # files to link into the vdso 7 10 vobjs-y := vdso-note.o vclock_gettime.o 8 11 ··· 108 105 quiet_cmd_vdso = VDSO $@ 109 106 cmd_vdso = $(LD) -nostdlib -o $@ \ 110 107 $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \ 111 - -T $(filter %.lds,$^) $(filter %.o,$^) 108 + -T $(filter %.lds,$^) $(filter %.o,$^); \ 109 + $(cmd_vdso_check) 112 110 113 111 VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic --no-undefined -z noexecstack
+25 -154
arch/sparc/vdso/vclock_gettime.c
··· 12 12 * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. 13 13 */ 14 14 15 - #include <linux/kernel.h> 16 - #include <linux/string.h> 17 - #include <asm/io.h> 18 - #include <asm/timex.h> 19 - #include <asm/clocksource.h> 15 + #include <linux/compiler.h> 16 + #include <linux/types.h> 17 + 18 + #include <vdso/gettime.h> 19 + 20 20 #include <asm/vdso/gettimeofday.h> 21 - #include <asm/vvar.h> 22 21 23 - /* 24 - * Compute the vvar page's address in the process address space, and return it 25 - * as a pointer to the vvar_data. 26 - */ 27 - notrace static __always_inline struct vvar_data *get_vvar_data(void) 22 + #include "../../../../lib/vdso/gettimeofday.c" 23 + 24 + int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) 28 25 { 29 - unsigned long ret; 30 - 31 - /* 32 - * vdso data page is the first vDSO page so grab the PC 33 - * and move up a page to get to the data page. 34 - */ 35 - __asm__("rd %%pc, %0" : "=r" (ret)); 36 - ret &= ~(8192 - 1); 37 - ret -= 8192; 38 - 39 - return (struct vvar_data *) ret; 26 + return __cvdso_gettimeofday(tv, tz); 40 27 } 41 28 42 - notrace static __always_inline u64 vgetsns(struct vvar_data *vvar) 43 - { 44 - u64 v; 45 - u64 cycles = __arch_get_hw_counter(vvar); 29 + int gettimeofday(struct __kernel_old_timeval *, struct timezone *) 30 + __weak __alias(__vdso_gettimeofday); 46 31 47 - v = (cycles - vvar->clock.cycle_last) & vvar->clock.mask; 48 - return v * vvar->clock.mult; 32 + #if defined(CONFIG_SPARC64) 33 + int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) 34 + { 35 + return __cvdso_clock_gettime(clock, ts); 49 36 } 50 37 51 - notrace static __always_inline int do_realtime(struct vvar_data *vvar, 52 - struct __kernel_old_timespec *ts) 38 + int clock_gettime(clockid_t, struct __kernel_timespec *) 39 + __weak __alias(__vdso_clock_gettime); 40 + 41 + #else 42 + 43 + int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) 53 44 { 54 - unsigned long seq; 55 - u64 ns; 56 - 57 - do { 58 - seq = vvar_read_begin(vvar); 59 - ts->tv_sec = vvar->wall_time_sec; 60 - ns = vvar->wall_time_snsec; 61 - ns += vgetsns(vvar); 62 - ns = vdso_shift_ns(ns, vvar->clock.shift); 63 - } while (unlikely(vvar_read_retry(vvar, seq))); 64 - 65 - ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); 66 - ts->tv_nsec = ns; 67 - 68 - return 0; 45 + return __cvdso_clock_gettime32(clock, ts); 69 46 } 70 47 71 - notrace static __always_inline int do_monotonic(struct vvar_data *vvar, 72 - struct __kernel_old_timespec *ts) 73 - { 74 - unsigned long seq; 75 - u64 ns; 48 + int clock_gettime(clockid_t, struct old_timespec32 *) 49 + __weak __alias(__vdso_clock_gettime); 76 50 77 - do { 78 - seq = vvar_read_begin(vvar); 79 - ts->tv_sec = vvar->monotonic_time_sec; 80 - ns = vvar->monotonic_time_snsec; 81 - ns += vgetsns(vvar); 82 - ns = vdso_shift_ns(ns, vvar->clock.shift); 83 - } while (unlikely(vvar_read_retry(vvar, seq))); 84 - 85 - ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); 86 - ts->tv_nsec = ns; 87 - 88 - return 0; 89 - } 90 - 91 - notrace static int do_realtime_coarse(struct vvar_data *vvar, 92 - struct __kernel_old_timespec *ts) 93 - { 94 - unsigned long seq; 95 - 96 - do { 97 - seq = vvar_read_begin(vvar); 98 - ts->tv_sec = vvar->wall_time_coarse_sec; 99 - ts->tv_nsec = vvar->wall_time_coarse_nsec; 100 - } while (unlikely(vvar_read_retry(vvar, seq))); 101 - return 0; 102 - } 103 - 104 - notrace static int do_monotonic_coarse(struct vvar_data *vvar, 105 - struct __kernel_old_timespec *ts) 106 - { 107 - unsigned long seq; 108 - 109 - do { 110 - seq = vvar_read_begin(vvar); 111 - ts->tv_sec = vvar->monotonic_time_coarse_sec; 112 - ts->tv_nsec = vvar->monotonic_time_coarse_nsec; 113 - } while (unlikely(vvar_read_retry(vvar, seq))); 114 - 115 - return 0; 116 - } 117 - 118 - notrace int 119 - __vdso_clock_gettime(clockid_t clock, struct __kernel_old_timespec *ts) 120 - { 121 - struct vvar_data *vvd = get_vvar_data(); 122 - 123 - switch (clock) { 124 - case CLOCK_REALTIME: 125 - if (unlikely(vvd->vclock_mode == VCLOCK_NONE)) 126 - break; 127 - return do_realtime(vvd, ts); 128 - case CLOCK_MONOTONIC: 129 - if (unlikely(vvd->vclock_mode == VCLOCK_NONE)) 130 - break; 131 - return do_monotonic(vvd, ts); 132 - case CLOCK_REALTIME_COARSE: 133 - return do_realtime_coarse(vvd, ts); 134 - case CLOCK_MONOTONIC_COARSE: 135 - return do_monotonic_coarse(vvd, ts); 136 - } 137 - /* 138 - * Unknown clock ID ? Fall back to the syscall. 139 - */ 140 - return clock_gettime_fallback(clock, ts); 141 - } 142 - int 143 - clock_gettime(clockid_t, struct __kernel_old_timespec *) 144 - __attribute__((weak, alias("__vdso_clock_gettime"))); 145 - 146 - notrace int 147 - __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) 148 - { 149 - struct vvar_data *vvd = get_vvar_data(); 150 - 151 - if (likely(vvd->vclock_mode != VCLOCK_NONE)) { 152 - if (likely(tv != NULL)) { 153 - union tstv_t { 154 - struct __kernel_old_timespec ts; 155 - struct __kernel_old_timeval tv; 156 - } *tstv = (union tstv_t *) tv; 157 - do_realtime(vvd, &tstv->ts); 158 - /* 159 - * Assign before dividing to ensure that the division is 160 - * done in the type of tv_usec, not tv_nsec. 161 - * 162 - * There cannot be > 1 billion usec in a second: 163 - * do_realtime() has already distributed such overflow 164 - * into tv_sec. So we can assign it to an int safely. 165 - */ 166 - tstv->tv.tv_usec = tstv->ts.tv_nsec; 167 - tstv->tv.tv_usec /= 1000; 168 - } 169 - if (unlikely(tz != NULL)) { 170 - /* Avoid memcpy. Some old compilers fail to inline it */ 171 - tz->tz_minuteswest = vvd->tz_minuteswest; 172 - tz->tz_dsttime = vvd->tz_dsttime; 173 - } 174 - return 0; 175 - } 176 - return gettimeofday_fallback(tv, tz); 177 - } 178 - int 179 - gettimeofday(struct __kernel_old_timeval *, struct timezone *) 180 - __attribute__((weak, alias("__vdso_gettimeofday"))); 51 + #endif
+5 -2
arch/sparc/vdso/vdso-layout.lds.S
··· 4 4 * This script controls its layout. 5 5 */ 6 6 7 + #include <vdso/datapage.h> 8 + #include <vdso/page.h> 9 + #include <asm/vdso/vsyscall.h> 10 + 7 11 SECTIONS 8 12 { 9 13 /* ··· 17 13 * segment. Page size is 8192 for both 64-bit and 32-bit vdso binaries 18 14 */ 19 15 20 - vvar_start = . -8192; 21 - vvar_data = vvar_start; 16 + VDSO_VVAR_SYMS 22 17 23 18 . = SIZEOF_HEADERS; 24 19
+14 -56
arch/sparc/vdso/vma.c
··· 16 16 #include <linux/linkage.h> 17 17 #include <linux/random.h> 18 18 #include <linux/elf.h> 19 + #include <linux/vdso_datastore.h> 19 20 #include <asm/cacheflush.h> 20 21 #include <asm/spitfire.h> 21 22 #include <asm/vdso.h> 22 - #include <asm/vvar.h> 23 23 #include <asm/page.h> 24 24 25 - unsigned int __read_mostly vdso_enabled = 1; 25 + #include <vdso/datapage.h> 26 + #include <asm/vdso/vsyscall.h> 26 27 27 - static struct vm_special_mapping vvar_mapping = { 28 - .name = "[vvar]" 29 - }; 28 + unsigned int __read_mostly vdso_enabled = 1; 30 29 31 30 #ifdef CONFIG_SPARC64 32 31 static struct vm_special_mapping vdso_mapping64 = { ··· 39 40 }; 40 41 #endif 41 42 42 - struct vvar_data *vvar_data; 43 - 44 43 /* 45 - * Allocate pages for the vdso and vvar, and copy in the vdso text from the 44 + * Allocate pages for the vdso and copy in the vdso text from the 46 45 * kernel image. 47 46 */ 48 47 static int __init init_vdso_image(const struct vdso_image *image, ··· 48 51 bool elf64) 49 52 { 50 53 int cnpages = (image->size) / PAGE_SIZE; 51 - struct page *dp, **dpp = NULL; 52 54 struct page *cp, **cpp = NULL; 53 - int i, dnpages = 0; 55 + int i; 54 56 55 57 /* 56 58 * First, the vdso text. This is initialied data, an integral number of ··· 72 76 copy_page(page_address(cp), image->data + i * PAGE_SIZE); 73 77 } 74 78 75 - /* 76 - * Now the vvar page. This is uninitialized data. 77 - */ 78 - 79 - if (vvar_data == NULL) { 80 - dnpages = (sizeof(struct vvar_data) / PAGE_SIZE) + 1; 81 - if (WARN_ON(dnpages != 1)) 82 - goto oom; 83 - dpp = kzalloc_objs(struct page *, dnpages); 84 - vvar_mapping.pages = dpp; 85 - 86 - if (!dpp) 87 - goto oom; 88 - 89 - dp = alloc_page(GFP_KERNEL); 90 - if (!dp) 91 - goto oom; 92 - 93 - dpp[0] = dp; 94 - vvar_data = page_address(dp); 95 - memset(vvar_data, 0, PAGE_SIZE); 96 - 97 - vvar_data->seq = 0; 98 - } 99 - 100 79 return 0; 101 80 oom: 102 81 if (cpp != NULL) { ··· 81 110 } 82 111 kfree(cpp); 83 112 vdso_mapping->pages = NULL; 84 - } 85 - 86 - if (dpp != NULL) { 87 - for (i = 0; i < dnpages; i++) { 88 - if (dpp[i] != NULL) 89 - __free_page(dpp[i]); 90 - } 91 - kfree(dpp); 92 - vvar_mapping.pages = NULL; 93 113 } 94 114 95 115 pr_warn("Cannot allocate vdso\n"); ··· 117 155 return start + (offset << PAGE_SHIFT); 118 156 } 119 157 158 + static_assert(VDSO_NR_PAGES == __VDSO_PAGES); 159 + 120 160 static int map_vdso(const struct vdso_image *image, 121 161 struct vm_special_mapping *vdso_mapping) 122 162 { 163 + const size_t area_size = image->size + VDSO_NR_PAGES * PAGE_SIZE; 123 164 struct mm_struct *mm = current->mm; 124 165 struct vm_area_struct *vma; 125 166 unsigned long text_start, addr = 0; ··· 135 170 * region is free. 136 171 */ 137 172 if (current->flags & PF_RANDOMIZE) { 138 - addr = get_unmapped_area(NULL, 0, 139 - image->size - image->sym_vvar_start, 140 - 0, 0); 173 + addr = get_unmapped_area(NULL, 0, area_size, 0, 0); 141 174 if (IS_ERR_VALUE(addr)) { 142 175 ret = addr; 143 176 goto up_fail; 144 177 } 145 - addr = vdso_addr(addr, image->size - image->sym_vvar_start); 178 + addr = vdso_addr(addr, area_size); 146 179 } 147 - addr = get_unmapped_area(NULL, addr, 148 - image->size - image->sym_vvar_start, 0, 0); 180 + addr = get_unmapped_area(NULL, addr, area_size, 0, 0); 149 181 if (IS_ERR_VALUE(addr)) { 150 182 ret = addr; 151 183 goto up_fail; 152 184 } 153 185 154 - text_start = addr - image->sym_vvar_start; 186 + text_start = addr + VDSO_NR_PAGES * PAGE_SIZE; 155 187 current->mm->context.vdso = (void __user *)text_start; 156 188 157 189 /* ··· 166 204 goto up_fail; 167 205 } 168 206 169 - vma = _install_special_mapping(mm, 170 - addr, 171 - -image->sym_vvar_start, 172 - VM_READ|VM_MAYREAD, 173 - &vvar_mapping); 207 + vma = vdso_install_vvar_mapping(mm, addr); 174 208 175 209 if (IS_ERR(vma)) { 176 210 ret = PTR_ERR(vma);