aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-10-22 22:14:24 -0400
committerDavid S. Miller <davem@davemloft.net>2018-10-22 22:14:24 -0400
commit8dbc450f76dc8f3b47fe117cd0cde166e1f21b64 (patch)
tree8099283c91e9180860d9abd92a60278289cd096d
parent46b8306480fb424abd525acc1763da1c63a27d8a (diff)
parent19832d244954189c851d8492718607a14734679c (diff)
Merge branch 'sparc-vdso'
sparc: VDSO improvements I started out on these changes with the goal of improving perf annotations when the VDSO is in use. Due to lack of inlining the helper functions are typically hit when profiling instead of __vdso_gettimeoday() or __vdso_vclock_gettime(). The only symbols available by default are the dyanmic symbols, which therefore doesn't cover the helper functions. So the perf output looks terrible, because the symbols cannot be resolved and all show up as "Unknown". The sparc VDSO code forces no inlining because of the way the simplistic %tick register read code patching works. So fixing that was the first order of business. Tricks were taken from how x86 implements alternates. The crucial factor is that if you want to refer to locations (for the original and patch instruction(s)) you have to do so in a way that is resolvable at link time even for a shared object. So you have to do this by storing PC-relative values, and not in executable sections. Next, we sanitize the Makefile so that the cflags et al. make more sense. And LDFLAGS are applied actually to invocations of LD instead of CC. We also add some sanity checking, specifically in a post-link check that makes sure we don't have any unexpected unresolved symbols in the VDSO. This is essential because the dynamic linker cannot resolve symbols in the VDSO because it cannot write to it. Finally some very minor optimizations are preformed to the vclock_gettime.c code. One thing which is tricky with this code on sparc is that struct timeval and struct timespec are layed out differently on 64-bit. This is because, unlike other architectures, sparc defined suseconds_t as 'int' even on 64-bit. This is why we have all of the "union" tstv_t" business and the weird assignments in __vdso_gettimeofday(). Performance wise we do gain some cycle shere, specifically here are cycle counts for a user application calling gettimeofday(): no-VDSO VDSO-orig VDSO-new ================================================ 64-bit 853 cycles 112 cycles 125 cycles 32-bit 849 cycles 134 cycles 141 cycles These results are with current glibc sources. To get better we'd need to implement this in assembler, and I might just do that at some point. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/sparc/include/asm/thread_info_64.h4
-rw-r--r--arch/sparc/include/asm/vdso.h6
-rw-r--r--arch/sparc/kernel/time_64.c3
-rw-r--r--arch/sparc/vdso/Makefile33
-rw-r--r--arch/sparc/vdso/checkundef.sh10
-rw-r--r--arch/sparc/vdso/vclock_gettime.c102
-rw-r--r--arch/sparc/vdso/vdso-layout.lds.S7
-rw-r--r--arch/sparc/vdso/vdso2c.c6
-rw-r--r--arch/sparc/vdso/vdso2c.h18
-rw-r--r--arch/sparc/vdso/vma.c39
10 files changed, 121 insertions, 107 deletions
diff --git a/arch/sparc/include/asm/thread_info_64.h b/arch/sparc/include/asm/thread_info_64.h
index 7fb676360928..20255471e653 100644
--- a/arch/sparc/include/asm/thread_info_64.h
+++ b/arch/sparc/include/asm/thread_info_64.h
@@ -121,8 +121,12 @@ struct thread_info {
121} 121}
122 122
123/* how to get the thread information struct from C */ 123/* how to get the thread information struct from C */
124#ifndef BUILD_VDSO
124register struct thread_info *current_thread_info_reg asm("g6"); 125register struct thread_info *current_thread_info_reg asm("g6");
125#define current_thread_info() (current_thread_info_reg) 126#define current_thread_info() (current_thread_info_reg)
127#else
128extern struct thread_info *current_thread_info(void);
129#endif
126 130
127/* thread information allocation */ 131/* thread information allocation */
128#if PAGE_SHIFT == 13 132#if PAGE_SHIFT == 13
diff --git a/arch/sparc/include/asm/vdso.h b/arch/sparc/include/asm/vdso.h
index 93b628731a5e..56836eb01787 100644
--- a/arch/sparc/include/asm/vdso.h
+++ b/arch/sparc/include/asm/vdso.h
@@ -8,10 +8,10 @@
8struct vdso_image { 8struct vdso_image {
9 void *data; 9 void *data;
10 unsigned long size; /* Always a multiple of PAGE_SIZE */ 10 unsigned long size; /* Always a multiple of PAGE_SIZE */
11
12 unsigned long tick_patch, tick_patch_len;
13
11 long sym_vvar_start; /* Negative offset to the vvar area */ 14 long sym_vvar_start; /* Negative offset to the vvar area */
12 long sym_vread_tick; /* Start of vread_tick section */
13 long sym_vread_tick_patch_start; /* Start of tick read */
14 long sym_vread_tick_patch_end; /* End of tick read */
15}; 15};
16 16
17#ifdef CONFIG_SPARC64 17#ifdef CONFIG_SPARC64
diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c
index f0eba72aa1ad..5f356dc8e178 100644
--- a/arch/sparc/kernel/time_64.c
+++ b/arch/sparc/kernel/time_64.c
@@ -53,8 +53,6 @@
53 53
54DEFINE_SPINLOCK(rtc_lock); 54DEFINE_SPINLOCK(rtc_lock);
55 55
56unsigned int __read_mostly vdso_fix_stick;
57
58#ifdef CONFIG_SMP 56#ifdef CONFIG_SMP
59unsigned long profile_pc(struct pt_regs *regs) 57unsigned long profile_pc(struct pt_regs *regs)
60{ 58{
@@ -838,7 +836,6 @@ void __init time_init_early(void)
838 } else { 836 } else {
839 init_tick_ops(&tick_operations); 837 init_tick_ops(&tick_operations);
840 clocksource_tick.archdata.vclock_mode = VCLOCK_TICK; 838 clocksource_tick.archdata.vclock_mode = VCLOCK_TICK;
841 vdso_fix_stick = 1;
842 } 839 }
843 } else { 840 } else {
844 init_tick_ops(&stick_operations); 841 init_tick_ops(&stick_operations);
diff --git a/arch/sparc/vdso/Makefile b/arch/sparc/vdso/Makefile
index dc85570d8839..a6e18ca4cc18 100644
--- a/arch/sparc/vdso/Makefile
+++ b/arch/sparc/vdso/Makefile
@@ -33,10 +33,8 @@ targets += $(vdso_img_sodbg) $(vdso_img-y:%=vdso%.so)
33 33
34CPPFLAGS_vdso.lds += -P -C 34CPPFLAGS_vdso.lds += -P -C
35 35
36VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \ 36VDSO_LDFLAGS_vdso.lds = -m elf64_sparc -soname linux-vdso.so.1 --no-undefined \
37 -Wl,--no-undefined \ 37 -z max-page-size=8192 -z common-page-size=8192
38 -Wl,-z,max-page-size=8192 -Wl,-z,common-page-size=8192 \
39 $(DISABLE_LTO)
40 38
41$(obj)/vdso64.so.dbg: $(obj)/vdso.lds $(vobjs) FORCE 39$(obj)/vdso64.so.dbg: $(obj)/vdso.lds $(vobjs) FORCE
42 $(call if_changed,vdso) 40 $(call if_changed,vdso)
@@ -54,13 +52,14 @@ $(obj)/vdso-image-%.c: $(obj)/vdso%.so.dbg $(obj)/vdso%.so $(obj)/vdso2c FORCE
54# Don't omit frame pointers for ease of userspace debugging, but do 52# Don't omit frame pointers for ease of userspace debugging, but do
55# optimize sibling calls. 53# optimize sibling calls.
56# 54#
57CFL := $(PROFILING) -mcmodel=medlow -fPIC -O2 -fasynchronous-unwind-tables \ 55CFL := $(PROFILING) -mcmodel=medlow -fPIC -O2 -fasynchronous-unwind-tables -m64 \
58 -m64 -ffixed-g2 -ffixed-g3 -fcall-used-g4 -fcall-used-g5 -ffixed-g6 \ 56 $(filter -g%,$(KBUILD_CFLAGS)) $(call cc-option, -fno-stack-protector) \
59 -ffixed-g7 $(filter -g%,$(KBUILD_CFLAGS)) \ 57 -fno-omit-frame-pointer -foptimize-sibling-calls \
60 $(call cc-option, -fno-stack-protector) -fno-omit-frame-pointer \ 58 -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO
61 -foptimize-sibling-calls -DBUILD_VDSO
62 59
63$(vobjs): KBUILD_CFLAGS += $(CFL) 60SPARC_REG_CFLAGS = -ffixed-g4 -ffixed-g5 -fcall-used-g5 -fcall-used-g7
61
62$(vobjs): KBUILD_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS) $(SPARC_REG_CFLAGS),$(KBUILD_CFLAGS)) $(CFL)
64 63
65# 64#
66# vDSO code runs in userspace and -pg doesn't help with profiling anyway. 65# vDSO code runs in userspace and -pg doesn't help with profiling anyway.
@@ -73,7 +72,7 @@ $(obj)/%.so: $(obj)/%.so.dbg
73 $(call if_changed,objcopy) 72 $(call if_changed,objcopy)
74 73
75CPPFLAGS_vdso32.lds = $(CPPFLAGS_vdso.lds) 74CPPFLAGS_vdso32.lds = $(CPPFLAGS_vdso.lds)
76VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-m,elf32_sparc,-soname=linux-gate.so.1 75VDSO_LDFLAGS_vdso32.lds = -m elf32_sparc -soname linux-gate.so.1
77 76
78#This makes sure the $(obj) subdirectory exists even though vdso32/ 77#This makes sure the $(obj) subdirectory exists even though vdso32/
79#is not a kbuild sub-make subdirectory 78#is not a kbuild sub-make subdirectory
@@ -91,7 +90,8 @@ KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS))
91KBUILD_CFLAGS_32 := $(filter-out -mcmodel=medlow,$(KBUILD_CFLAGS_32)) 90KBUILD_CFLAGS_32 := $(filter-out -mcmodel=medlow,$(KBUILD_CFLAGS_32))
92KBUILD_CFLAGS_32 := $(filter-out -fno-pic,$(KBUILD_CFLAGS_32)) 91KBUILD_CFLAGS_32 := $(filter-out -fno-pic,$(KBUILD_CFLAGS_32))
93KBUILD_CFLAGS_32 := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS_32)) 92KBUILD_CFLAGS_32 := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS_32))
94KBUILD_CFLAGS_32 += -m32 -msoft-float -fpic -mno-app-regs -ffixed-g7 93KBUILD_CFLAGS_32 := $(filter-out $(SPARC_REG_CFLAGS),$(KBUILD_CFLAGS_32))
94KBUILD_CFLAGS_32 += -m32 -msoft-float -fpic
95KBUILD_CFLAGS_32 += $(call cc-option, -fno-stack-protector) 95KBUILD_CFLAGS_32 += $(call cc-option, -fno-stack-protector)
96KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls) 96KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls)
97KBUILD_CFLAGS_32 += -fno-omit-frame-pointer 97KBUILD_CFLAGS_32 += -fno-omit-frame-pointer
@@ -109,12 +109,13 @@ $(obj)/vdso32.so.dbg: FORCE \
109# The DSO images are built using a special linker script. 109# The DSO images are built using a special linker script.
110# 110#
111quiet_cmd_vdso = VDSO $@ 111quiet_cmd_vdso = VDSO $@
112 cmd_vdso = $(CC) -nostdlib -o $@ \ 112 cmd_vdso = $(LD) -nostdlib -o $@ \
113 $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \ 113 $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \
114 -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) 114 -T $(filter %.lds,$^) $(filter %.o,$^) && \
115 sh $(srctree)/$(src)/checkundef.sh '$(OBJDUMP)' '$@'
115 116
116VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \ 117VDSO_LDFLAGS = -shared $(call ld-option, --hash-style=both) \
117 $(call cc-ldoption, -Wl$(comma)--build-id) -Wl,-Bsymbolic 118 $(call ld-option, --build-id) -Bsymbolic
118GCOV_PROFILE := n 119GCOV_PROFILE := n
119 120
120# 121#
diff --git a/arch/sparc/vdso/checkundef.sh b/arch/sparc/vdso/checkundef.sh
new file mode 100644
index 000000000000..2d85876ffc32
--- /dev/null
+++ b/arch/sparc/vdso/checkundef.sh
@@ -0,0 +1,10 @@
1#!/bin/sh
2objdump="$1"
3file="$2"
4$objdump -t "$file" | grep '*UUND*' | grep -v '#scratch' > /dev/null 2>&1
5if [ $? -eq 1 ]; then
6 exit 0
7else
8 echo "$file: undefined symbols found" >&2
9 exit 1
10fi
diff --git a/arch/sparc/vdso/vclock_gettime.c b/arch/sparc/vdso/vclock_gettime.c
index 75dca9aab737..7b539ceebe13 100644
--- a/arch/sparc/vdso/vclock_gettime.c
+++ b/arch/sparc/vdso/vclock_gettime.c
@@ -12,11 +12,6 @@
12 * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. 12 * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
13 */ 13 */
14 14
15/* Disable profiling for userspace code: */
16#ifndef DISABLE_BRANCH_PROFILING
17#define DISABLE_BRANCH_PROFILING
18#endif
19
20#include <linux/kernel.h> 15#include <linux/kernel.h>
21#include <linux/time.h> 16#include <linux/time.h>
22#include <linux/string.h> 17#include <linux/string.h>
@@ -26,13 +21,6 @@
26#include <asm/clocksource.h> 21#include <asm/clocksource.h>
27#include <asm/vvar.h> 22#include <asm/vvar.h>
28 23
29#undef TICK_PRIV_BIT
30#ifdef CONFIG_SPARC64
31#define TICK_PRIV_BIT (1UL << 63)
32#else
33#define TICK_PRIV_BIT (1ULL << 63)
34#endif
35
36#ifdef CONFIG_SPARC64 24#ifdef CONFIG_SPARC64
37#define SYSCALL_STRING \ 25#define SYSCALL_STRING \
38 "ta 0x6d;" \ 26 "ta 0x6d;" \
@@ -60,24 +48,22 @@
60 * Compute the vvar page's address in the process address space, and return it 48 * Compute the vvar page's address in the process address space, and return it
61 * as a pointer to the vvar_data. 49 * as a pointer to the vvar_data.
62 */ 50 */
63static notrace noinline struct vvar_data * 51notrace static __always_inline struct vvar_data *get_vvar_data(void)
64get_vvar_data(void)
65{ 52{
66 unsigned long ret; 53 unsigned long ret;
67 54
68 /* 55 /*
69 * vdso data page is the first vDSO page so grab the return address 56 * vdso data page is the first vDSO page so grab the PC
70 * and move up a page to get to the data page. 57 * and move up a page to get to the data page.
71 */ 58 */
72 ret = (unsigned long)__builtin_return_address(0); 59 __asm__("rd %%pc, %0" : "=r" (ret));
73 ret &= ~(8192 - 1); 60 ret &= ~(8192 - 1);
74 ret -= 8192; 61 ret -= 8192;
75 62
76 return (struct vvar_data *) ret; 63 return (struct vvar_data *) ret;
77} 64}
78 65
79static notrace long 66notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
80vdso_fallback_gettime(long clock, struct timespec *ts)
81{ 67{
82 register long num __asm__("g1") = __NR_clock_gettime; 68 register long num __asm__("g1") = __NR_clock_gettime;
83 register long o0 __asm__("o0") = clock; 69 register long o0 __asm__("o0") = clock;
@@ -88,8 +74,7 @@ vdso_fallback_gettime(long clock, struct timespec *ts)
88 return o0; 74 return o0;
89} 75}
90 76
91static notrace __always_inline long 77notrace static long vdso_fallback_gettimeofday(struct timeval *tv, struct timezone *tz)
92vdso_fallback_gettimeofday(struct timeval *tv, struct timezone *tz)
93{ 78{
94 register long num __asm__("g1") = __NR_gettimeofday; 79 register long num __asm__("g1") = __NR_gettimeofday;
95 register long o0 __asm__("o0") = (long) tv; 80 register long o0 __asm__("o0") = (long) tv;
@@ -101,38 +86,43 @@ vdso_fallback_gettimeofday(struct timeval *tv, struct timezone *tz)
101} 86}
102 87
103#ifdef CONFIG_SPARC64 88#ifdef CONFIG_SPARC64
104static notrace noinline u64 89notrace static __always_inline u64 vread_tick(void)
105vread_tick(void) { 90{
106 u64 ret; 91 u64 ret;
107 92
108 __asm__ __volatile__("rd %%asr24, %0 \n" 93 __asm__ __volatile__("1:\n\t"
109 ".section .vread_tick_patch, \"ax\" \n" 94 "rd %%tick, %0\n\t"
110 "rd %%tick, %0 \n" 95 ".pushsection .tick_patch, \"a\"\n\t"
111 ".previous \n" 96 ".word 1b - ., 1f - .\n\t"
112 : "=&r" (ret)); 97 ".popsection\n\t"
113 return ret & ~TICK_PRIV_BIT; 98 ".pushsection .tick_patch_replacement, \"ax\"\n\t"
99 "1:\n\t"
100 "rd %%asr24, %0\n\t"
101 ".popsection\n"
102 : "=r" (ret));
103 return ret;
114} 104}
115#else 105#else
116static notrace noinline u64 106notrace static __always_inline u64 vread_tick(void)
117vread_tick(void)
118{ 107{
119 unsigned int lo, hi; 108 register unsigned long long ret asm("o4");
120 109
121 __asm__ __volatile__("rd %%asr24, %%g1\n\t" 110 __asm__ __volatile__("1:\n\t"
122 "srlx %%g1, 32, %1\n\t" 111 "rd %%tick, %L0\n\t"
123 "srl %%g1, 0, %0\n" 112 "srlx %L0, 32, %H0\n\t"
124 ".section .vread_tick_patch, \"ax\" \n" 113 ".pushsection .tick_patch, \"a\"\n\t"
125 "rd %%tick, %%g1\n" 114 ".word 1b - ., 1f - .\n\t"
126 ".previous \n" 115 ".popsection\n\t"
127 : "=&r" (lo), "=&r" (hi) 116 ".pushsection .tick_patch_replacement, \"ax\"\n\t"
128 : 117 "1:\n\t"
129 : "g1"); 118 "rd %%asr24, %L0\n\t"
130 return lo | ((u64)hi << 32); 119 ".popsection\n"
120 : "=r" (ret));
121 return ret;
131} 122}
132#endif 123#endif
133 124
134static notrace inline u64 125notrace static __always_inline u64 vgetsns(struct vvar_data *vvar)
135vgetsns(struct vvar_data *vvar)
136{ 126{
137 u64 v; 127 u64 v;
138 u64 cycles; 128 u64 cycles;
@@ -142,13 +132,12 @@ vgetsns(struct vvar_data *vvar)
142 return v * vvar->clock.mult; 132 return v * vvar->clock.mult;
143} 133}
144 134
145static notrace noinline int 135notrace static __always_inline int do_realtime(struct vvar_data *vvar,
146do_realtime(struct vvar_data *vvar, struct timespec *ts) 136 struct timespec *ts)
147{ 137{
148 unsigned long seq; 138 unsigned long seq;
149 u64 ns; 139 u64 ns;
150 140
151 ts->tv_nsec = 0;
152 do { 141 do {
153 seq = vvar_read_begin(vvar); 142 seq = vvar_read_begin(vvar);
154 ts->tv_sec = vvar->wall_time_sec; 143 ts->tv_sec = vvar->wall_time_sec;
@@ -157,18 +146,18 @@ do_realtime(struct vvar_data *vvar, struct timespec *ts)
157 ns >>= vvar->clock.shift; 146 ns >>= vvar->clock.shift;
158 } while (unlikely(vvar_read_retry(vvar, seq))); 147 } while (unlikely(vvar_read_retry(vvar, seq)));
159 148
160 timespec_add_ns(ts, ns); 149 ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
150 ts->tv_nsec = ns;
161 151
162 return 0; 152 return 0;
163} 153}
164 154
165static notrace noinline int 155notrace static __always_inline int do_monotonic(struct vvar_data *vvar,
166do_monotonic(struct vvar_data *vvar, struct timespec *ts) 156 struct timespec *ts)
167{ 157{
168 unsigned long seq; 158 unsigned long seq;
169 u64 ns; 159 u64 ns;
170 160
171 ts->tv_nsec = 0;
172 do { 161 do {
173 seq = vvar_read_begin(vvar); 162 seq = vvar_read_begin(vvar);
174 ts->tv_sec = vvar->monotonic_time_sec; 163 ts->tv_sec = vvar->monotonic_time_sec;
@@ -177,13 +166,14 @@ do_monotonic(struct vvar_data *vvar, struct timespec *ts)
177 ns >>= vvar->clock.shift; 166 ns >>= vvar->clock.shift;
178 } while (unlikely(vvar_read_retry(vvar, seq))); 167 } while (unlikely(vvar_read_retry(vvar, seq)));
179 168
180 timespec_add_ns(ts, ns); 169 ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
170 ts->tv_nsec = ns;
181 171
182 return 0; 172 return 0;
183} 173}
184 174
185static notrace noinline int 175notrace static int do_realtime_coarse(struct vvar_data *vvar,
186do_realtime_coarse(struct vvar_data *vvar, struct timespec *ts) 176 struct timespec *ts)
187{ 177{
188 unsigned long seq; 178 unsigned long seq;
189 179
@@ -195,8 +185,8 @@ do_realtime_coarse(struct vvar_data *vvar, struct timespec *ts)
195 return 0; 185 return 0;
196} 186}
197 187
198static notrace noinline int 188notrace static int do_monotonic_coarse(struct vvar_data *vvar,
199do_monotonic_coarse(struct vvar_data *vvar, struct timespec *ts) 189 struct timespec *ts)
200{ 190{
201 unsigned long seq; 191 unsigned long seq;
202 192
diff --git a/arch/sparc/vdso/vdso-layout.lds.S b/arch/sparc/vdso/vdso-layout.lds.S
index f2c83abaca12..ed36d49e1617 100644
--- a/arch/sparc/vdso/vdso-layout.lds.S
+++ b/arch/sparc/vdso/vdso-layout.lds.S
@@ -73,11 +73,8 @@ SECTIONS
73 73
74 .text : { *(.text*) } :text =0x90909090, 74 .text : { *(.text*) } :text =0x90909090,
75 75
76 .vread_tick_patch : { 76 .tick_patch : { *(.tick_patch) } :text
77 vread_tick_patch_start = .; 77 .tick_patch_insns : { *(.tick_patch_insns) } :text
78 *(.vread_tick_patch)
79 vread_tick_patch_end = .;
80 }
81 78
82 /DISCARD/ : { 79 /DISCARD/ : {
83 *(.discard) 80 *(.discard)
diff --git a/arch/sparc/vdso/vdso2c.c b/arch/sparc/vdso/vdso2c.c
index 9f5b1cd6d51d..ab7504176a7f 100644
--- a/arch/sparc/vdso/vdso2c.c
+++ b/arch/sparc/vdso/vdso2c.c
@@ -63,9 +63,6 @@ enum {
63 sym_vvar_start, 63 sym_vvar_start,
64 sym_VDSO_FAKE_SECTION_TABLE_START, 64 sym_VDSO_FAKE_SECTION_TABLE_START,
65 sym_VDSO_FAKE_SECTION_TABLE_END, 65 sym_VDSO_FAKE_SECTION_TABLE_END,
66 sym_vread_tick,
67 sym_vread_tick_patch_start,
68 sym_vread_tick_patch_end
69}; 66};
70 67
71struct vdso_sym { 68struct vdso_sym {
@@ -81,9 +78,6 @@ struct vdso_sym required_syms[] = {
81 [sym_VDSO_FAKE_SECTION_TABLE_END] = { 78 [sym_VDSO_FAKE_SECTION_TABLE_END] = {
82 "VDSO_FAKE_SECTION_TABLE_END", 0 79 "VDSO_FAKE_SECTION_TABLE_END", 0
83 }, 80 },
84 [sym_vread_tick] = {"vread_tick", 1},
85 [sym_vread_tick_patch_start] = {"vread_tick_patch_start", 1},
86 [sym_vread_tick_patch_end] = {"vread_tick_patch_end", 1}
87}; 81};
88 82
89__attribute__((format(printf, 1, 2))) __attribute__((noreturn)) 83__attribute__((format(printf, 1, 2))) __attribute__((noreturn))
diff --git a/arch/sparc/vdso/vdso2c.h b/arch/sparc/vdso/vdso2c.h
index 808decb0f7be..4df005cf98c0 100644
--- a/arch/sparc/vdso/vdso2c.h
+++ b/arch/sparc/vdso/vdso2c.h
@@ -17,10 +17,11 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len,
17 unsigned long mapping_size; 17 unsigned long mapping_size;
18 int i; 18 int i;
19 unsigned long j; 19 unsigned long j;
20 20 ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr, *secstrings_hdr,
21 ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr; 21 *patch_sec = NULL;
22 ELF(Ehdr) *hdr = (ELF(Ehdr) *)raw_addr; 22 ELF(Ehdr) *hdr = (ELF(Ehdr) *)raw_addr;
23 ELF(Dyn) *dyn = 0, *dyn_end = 0; 23 ELF(Dyn) *dyn = 0, *dyn_end = 0;
24 const char *secstrings;
24 INT_BITS syms[NSYMS] = {}; 25 INT_BITS syms[NSYMS] = {};
25 26
26 ELF(Phdr) *pt = (ELF(Phdr) *)(raw_addr + GET_BE(&hdr->e_phoff)); 27 ELF(Phdr) *pt = (ELF(Phdr) *)(raw_addr + GET_BE(&hdr->e_phoff));
@@ -63,11 +64,18 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len,
63 } 64 }
64 65
65 /* Walk the section table */ 66 /* Walk the section table */
67 secstrings_hdr = raw_addr + GET_BE(&hdr->e_shoff) +
68 GET_BE(&hdr->e_shentsize)*GET_BE(&hdr->e_shstrndx);
69 secstrings = raw_addr + GET_BE(&secstrings_hdr->sh_offset);
66 for (i = 0; i < GET_BE(&hdr->e_shnum); i++) { 70 for (i = 0; i < GET_BE(&hdr->e_shnum); i++) {
67 ELF(Shdr) *sh = raw_addr + GET_BE(&hdr->e_shoff) + 71 ELF(Shdr) *sh = raw_addr + GET_BE(&hdr->e_shoff) +
68 GET_BE(&hdr->e_shentsize) * i; 72 GET_BE(&hdr->e_shentsize) * i;
69 if (GET_BE(&sh->sh_type) == SHT_SYMTAB) 73 if (GET_BE(&sh->sh_type) == SHT_SYMTAB)
70 symtab_hdr = sh; 74 symtab_hdr = sh;
75
76 if (!strcmp(secstrings + GET_BE(&sh->sh_name),
77 ".tick_patch"))
78 patch_sec = sh;
71 } 79 }
72 80
73 if (!symtab_hdr) 81 if (!symtab_hdr)
@@ -134,6 +142,12 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len,
134 fprintf(outfile, "const struct vdso_image %s_builtin = {\n", name); 142 fprintf(outfile, "const struct vdso_image %s_builtin = {\n", name);
135 fprintf(outfile, "\t.data = raw_data,\n"); 143 fprintf(outfile, "\t.data = raw_data,\n");
136 fprintf(outfile, "\t.size = %lu,\n", mapping_size); 144 fprintf(outfile, "\t.size = %lu,\n", mapping_size);
145 if (patch_sec) {
146 fprintf(outfile, "\t.tick_patch = %lu,\n",
147 (unsigned long)GET_BE(&patch_sec->sh_offset));
148 fprintf(outfile, "\t.tick_patch_len = %lu,\n",
149 (unsigned long)GET_BE(&patch_sec->sh_size));
150 }
137 for (i = 0; i < NSYMS; i++) { 151 for (i = 0; i < NSYMS; i++) {
138 if (required_syms[i].export && syms[i]) 152 if (required_syms[i].export && syms[i])
139 fprintf(outfile, "\t.sym_%s = %" PRIi64 ",\n", 153 fprintf(outfile, "\t.sym_%s = %" PRIi64 ",\n",
diff --git a/arch/sparc/vdso/vma.c b/arch/sparc/vdso/vma.c
index 5eaff3c1aa0c..8874a27d8adc 100644
--- a/arch/sparc/vdso/vma.c
+++ b/arch/sparc/vdso/vma.c
@@ -16,6 +16,8 @@
16#include <linux/linkage.h> 16#include <linux/linkage.h>
17#include <linux/random.h> 17#include <linux/random.h>
18#include <linux/elf.h> 18#include <linux/elf.h>
19#include <asm/cacheflush.h>
20#include <asm/spitfire.h>
19#include <asm/vdso.h> 21#include <asm/vdso.h>
20#include <asm/vvar.h> 22#include <asm/vvar.h>
21#include <asm/page.h> 23#include <asm/page.h>
@@ -40,7 +42,25 @@ static struct vm_special_mapping vdso_mapping32 = {
40 42
41struct vvar_data *vvar_data; 43struct vvar_data *vvar_data;
42 44
43#define SAVE_INSTR_SIZE 4 45struct tick_patch_entry {
46 s32 orig, repl;
47};
48
49static void stick_patch(const struct vdso_image *image)
50{
51 struct tick_patch_entry *p, *p_end;
52
53 p = image->data + image->tick_patch;
54 p_end = (void *)p + image->tick_patch_len;
55 while (p < p_end) {
56 u32 *instr = (void *)&p->orig + p->orig;
57 u32 *repl = (void *)&p->repl + p->repl;
58
59 *instr = *repl;
60 flushi(instr);
61 p++;
62 }
63}
44 64
45/* 65/*
46 * Allocate pages for the vdso and vvar, and copy in the vdso text from the 66 * Allocate pages for the vdso and vvar, and copy in the vdso text from the
@@ -68,21 +88,8 @@ int __init init_vdso_image(const struct vdso_image *image,
68 if (!cpp) 88 if (!cpp)
69 goto oom; 89 goto oom;
70 90
71 if (vdso_fix_stick) { 91 if (tlb_type != spitfire)
72 /* 92 stick_patch(image);
73 * If the system uses %tick instead of %stick, patch the VDSO
74 * with instruction reading %tick instead of %stick.
75 */
76 unsigned int j, k = SAVE_INSTR_SIZE;
77 unsigned char *data = image->data;
78
79 for (j = image->sym_vread_tick_patch_start;
80 j < image->sym_vread_tick_patch_end; j++) {
81
82 data[image->sym_vread_tick + k] = data[j];
83 k++;
84 }
85 }
86 93
87 for (i = 0; i < cnpages; i++) { 94 for (i = 0; i < cnpages; i++) {
88 cp = alloc_page(GFP_KERNEL); 95 cp = alloc_page(GFP_KERNEL);