aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/vdso
diff options
context:
space:
mode:
authorStefani Seibold <stefani@seibold.net>2014-03-17 18:22:09 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2014-03-18 15:52:37 -0400
commit7a59ed415f5b57469e22e41fc4188d5399e0b194 (patch)
treefb57bae076853fbcbd44af62fb07d77d3c44125b /arch/x86/vdso
parentb4b541a610c4db8643b36030ee5012203ca65778 (diff)
x86, vdso: Add 32 bit VDSO time support for 32 bit kernel
This patch add the time support for 32 bit a VDSO to a 32 bit kernel. For 32 bit programs running on a 32 bit kernel, the same mechanism is used as for 64 bit programs running on a 64 bit kernel. Reviewed-by: Andy Lutomirski <luto@amacapital.net> Signed-off-by: Stefani Seibold <stefani@seibold.net> Link: http://lkml.kernel.org/r/1395094933-14252-10-git-send-email-stefani@seibold.net Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/vdso')
-rw-r--r--arch/x86/vdso/Makefile8
-rw-r--r--arch/x86/vdso/vclock_gettime.c76
-rw-r--r--arch/x86/vdso/vdso-layout.lds.S22
-rw-r--r--arch/x86/vdso/vdso32-setup.c47
-rw-r--r--arch/x86/vdso/vdso32/vclock_gettime.c9
-rw-r--r--arch/x86/vdso/vdso32/vdso32.lds.S11
6 files changed, 162 insertions, 11 deletions
diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile
index 7a3d13e23f25..6cef7a1b014c 100644
--- a/arch/x86/vdso/Makefile
+++ b/arch/x86/vdso/Makefile
@@ -146,8 +146,16 @@ KBUILD_AFLAGS_32 := $(filter-out -m64,$(KBUILD_AFLAGS))
146$(vdso32-images:%=$(obj)/%.dbg): KBUILD_AFLAGS = $(KBUILD_AFLAGS_32) 146$(vdso32-images:%=$(obj)/%.dbg): KBUILD_AFLAGS = $(KBUILD_AFLAGS_32)
147$(vdso32-images:%=$(obj)/%.dbg): asflags-$(CONFIG_X86_64) += -m32 147$(vdso32-images:%=$(obj)/%.dbg): asflags-$(CONFIG_X86_64) += -m32
148 148
149KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS))
150KBUILD_CFLAGS_32 := $(filter-out -mcmodel=kernel,$(KBUILD_CFLAGS_32))
151KBUILD_CFLAGS_32 := $(filter-out -fno-pic,$(KBUILD_CFLAGS_32))
152KBUILD_CFLAGS_32 := $(filter-out -mfentry,$(KBUILD_CFLAGS_32))
153KBUILD_CFLAGS_32 += -m32 -msoft-float -mregparm=0 -fpic
154$(vdso32-images:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_32)
155
149$(vdso32-images:%=$(obj)/%.dbg): $(obj)/vdso32-%.so.dbg: FORCE \ 156$(vdso32-images:%=$(obj)/%.dbg): $(obj)/vdso32-%.so.dbg: FORCE \
150 $(obj)/vdso32/vdso32.lds \ 157 $(obj)/vdso32/vdso32.lds \
158 $(obj)/vdso32/vclock_gettime.o \
151 $(obj)/vdso32/note.o \ 159 $(obj)/vdso32/note.o \
152 $(obj)/vdso32/%.o 160 $(obj)/vdso32/%.o
153 $(call if_changed,vdso) 161 $(call if_changed,vdso)
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c
index 09dae4a1c6dc..90bb5e8027ac 100644
--- a/arch/x86/vdso/vclock_gettime.c
+++ b/arch/x86/vdso/vclock_gettime.c
@@ -4,6 +4,9 @@
4 * 4 *
5 * Fast user context implementation of clock_gettime, gettimeofday, and time. 5 * Fast user context implementation of clock_gettime, gettimeofday, and time.
6 * 6 *
7 * 32 Bit compat layer by Stefani Seibold <stefani@seibold.net>
8 * sponsored by Rohde & Schwarz GmbH & Co. KG Munich/Germany
9 *
7 * The code should have no internal unresolved relocations. 10 * The code should have no internal unresolved relocations.
8 * Check with readelf after changing. 11 * Check with readelf after changing.
9 */ 12 */
@@ -12,13 +15,11 @@
12#define DISABLE_BRANCH_PROFILING 15#define DISABLE_BRANCH_PROFILING
13 16
14#include <linux/kernel.h> 17#include <linux/kernel.h>
15#include <linux/posix-timers.h> 18#include <uapi/linux/time.h>
16#include <linux/time.h>
17#include <linux/string.h> 19#include <linux/string.h>
18#include <asm/vsyscall.h> 20#include <asm/vsyscall.h>
19#include <asm/fixmap.h> 21#include <asm/fixmap.h>
20#include <asm/vgtod.h> 22#include <asm/vgtod.h>
21#include <asm/timex.h>
22#include <asm/hpet.h> 23#include <asm/hpet.h>
23#include <asm/unistd.h> 24#include <asm/unistd.h>
24#include <asm/io.h> 25#include <asm/io.h>
@@ -26,6 +27,12 @@
26 27
27#define gtod (&VVAR(vsyscall_gtod_data)) 28#define gtod (&VVAR(vsyscall_gtod_data))
28 29
30extern int __vdso_clock_gettime(clockid_t clock, struct timespec *ts);
31extern int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz);
32extern time_t __vdso_time(time_t *t);
33
34#ifndef BUILD_VDSO32
35
29static notrace cycle_t vread_hpet(void) 36static notrace cycle_t vread_hpet(void)
30{ 37{
31 return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + HPET_COUNTER); 38 return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + HPET_COUNTER);
@@ -118,6 +125,59 @@ static notrace cycle_t vread_pvclock(int *mode)
118} 125}
119#endif 126#endif
120 127
128#else
129
130extern u8 hpet_page
131 __attribute__((visibility("hidden")));
132
133#ifdef CONFIG_HPET_TIMER
134static notrace cycle_t vread_hpet(void)
135{
136 return readl((const void __iomem *)(&hpet_page + HPET_COUNTER));
137}
138#endif
139
140notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
141{
142 long ret;
143
144 asm(
145 "mov %%ebx, %%edx \n"
146 "mov %2, %%ebx \n"
147 "call VDSO32_vsyscall \n"
148 "mov %%edx, %%ebx \n"
149 : "=a" (ret)
150 : "0" (__NR_clock_gettime), "g" (clock), "c" (ts)
151 : "memory", "edx");
152 return ret;
153}
154
155notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
156{
157 long ret;
158
159 asm(
160 "mov %%ebx, %%edx \n"
161 "mov %2, %%ebx \n"
162 "call VDSO32_vsyscall \n"
163 "mov %%edx, %%ebx \n"
164 : "=a" (ret)
165 : "0" (__NR_gettimeofday), "g" (tv), "c" (tz)
166 : "memory", "edx");
167 return ret;
168}
169
170#ifdef CONFIG_PARAVIRT_CLOCK
171
172static notrace cycle_t vread_pvclock(int *mode)
173{
174 *mode = VCLOCK_NONE;
175 return 0;
176}
177#endif
178
179#endif
180
121notrace static cycle_t vread_tsc(void) 181notrace static cycle_t vread_tsc(void)
122{ 182{
123 cycle_t ret; 183 cycle_t ret;
@@ -131,7 +191,7 @@ notrace static cycle_t vread_tsc(void)
131 * but no one has ever seen it happen. 191 * but no one has ever seen it happen.
132 */ 192 */
133 rdtsc_barrier(); 193 rdtsc_barrier();
134 ret = (cycle_t)vget_cycles(); 194 ret = (cycle_t)__native_read_tsc();
135 195
136 last = gtod->clock.cycle_last; 196 last = gtod->clock.cycle_last;
137 197
@@ -152,12 +212,14 @@ notrace static cycle_t vread_tsc(void)
152 212
153notrace static inline u64 vgetsns(int *mode) 213notrace static inline u64 vgetsns(int *mode)
154{ 214{
155 long v; 215 u64 v;
156 cycles_t cycles; 216 cycles_t cycles;
157 if (gtod->clock.vclock_mode == VCLOCK_TSC) 217 if (gtod->clock.vclock_mode == VCLOCK_TSC)
158 cycles = vread_tsc(); 218 cycles = vread_tsc();
219#ifdef CONFIG_HPET_TIMER
159 else if (gtod->clock.vclock_mode == VCLOCK_HPET) 220 else if (gtod->clock.vclock_mode == VCLOCK_HPET)
160 cycles = vread_hpet(); 221 cycles = vread_hpet();
222#endif
161#ifdef CONFIG_PARAVIRT_CLOCK 223#ifdef CONFIG_PARAVIRT_CLOCK
162 else if (gtod->clock.vclock_mode == VCLOCK_PVCLOCK) 224 else if (gtod->clock.vclock_mode == VCLOCK_PVCLOCK)
163 cycles = vread_pvclock(mode); 225 cycles = vread_pvclock(mode);
@@ -189,7 +251,7 @@ notrace static int __always_inline do_realtime(struct timespec *ts)
189 return mode; 251 return mode;
190} 252}
191 253
192notrace static int do_monotonic(struct timespec *ts) 254notrace static int __always_inline do_monotonic(struct timespec *ts)
193{ 255{
194 unsigned long seq; 256 unsigned long seq;
195 u64 ns; 257 u64 ns;
@@ -284,7 +346,7 @@ int gettimeofday(struct timeval *, struct timezone *)
284 */ 346 */
285notrace time_t __vdso_time(time_t *t) 347notrace time_t __vdso_time(time_t *t)
286{ 348{
287 /* This is atomic on x86_64 so we don't need any locks. */ 349 /* This is atomic on x86 so we don't need any locks. */
288 time_t result = ACCESS_ONCE(gtod->wall_time_sec); 350 time_t result = ACCESS_ONCE(gtod->wall_time_sec);
289 351
290 if (t) 352 if (t)
diff --git a/arch/x86/vdso/vdso-layout.lds.S b/arch/x86/vdso/vdso-layout.lds.S
index 8c550c1976f3..c6d0e1bf27a4 100644
--- a/arch/x86/vdso/vdso-layout.lds.S
+++ b/arch/x86/vdso/vdso-layout.lds.S
@@ -6,6 +6,24 @@
6 6
7SECTIONS 7SECTIONS
8{ 8{
9#ifdef BUILD_VDSO32
10#include <asm/vdso32.h>
11
12 .hpet_sect : {
13 hpet_page = . - VDSO_OFFSET(VDSO_HPET_PAGE);
14 } :text :hpet_sect
15
16 .vvar_sect : {
17 vvar = . - VDSO_OFFSET(VDSO_VVAR_PAGE);
18
19 /* Place all vvars at the offsets in asm/vvar.h. */
20#define EMIT_VVAR(name, offset) vvar_ ## name = vvar + offset;
21#define __VVAR_KERNEL_LDS
22#include <asm/vvar.h>
23#undef __VVAR_KERNEL_LDS
24#undef EMIT_VVAR
25 } :text :vvar_sect
26#endif
9 . = SIZEOF_HEADERS; 27 . = SIZEOF_HEADERS;
10 28
11 .hash : { *(.hash) } :text 29 .hash : { *(.hash) } :text
@@ -61,4 +79,8 @@ PHDRS
61 dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ 79 dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
62 note PT_NOTE FLAGS(4); /* PF_R */ 80 note PT_NOTE FLAGS(4); /* PF_R */
63 eh_frame_hdr PT_GNU_EH_FRAME; 81 eh_frame_hdr PT_GNU_EH_FRAME;
82#ifdef BUILD_VDSO32
83 vvar_sect PT_NULL FLAGS(4); /* PF_R */
84 hpet_sect PT_NULL FLAGS(4); /* PF_R */
85#endif
64} 86}
diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c
index e0fc767bcad3..e10abdf4cc10 100644
--- a/arch/x86/vdso/vdso32-setup.c
+++ b/arch/x86/vdso/vdso32-setup.c
@@ -25,6 +25,9 @@
25#include <asm/tlbflush.h> 25#include <asm/tlbflush.h>
26#include <asm/vdso.h> 26#include <asm/vdso.h>
27#include <asm/proto.h> 27#include <asm/proto.h>
28#include <asm/fixmap.h>
29#include <asm/hpet.h>
30#include <asm/vvar.h>
28 31
29#ifdef CONFIG_COMPAT_VDSO 32#ifdef CONFIG_COMPAT_VDSO
30#define VDSO_DEFAULT 0 33#define VDSO_DEFAULT 0
@@ -141,6 +144,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
141 struct mm_struct *mm = current->mm; 144 struct mm_struct *mm = current->mm;
142 unsigned long addr; 145 unsigned long addr;
143 int ret = 0; 146 int ret = 0;
147 struct vm_area_struct *vma;
144 148
145#ifdef CONFIG_X86_X32_ABI 149#ifdef CONFIG_X86_X32_ABI
146 if (test_thread_flag(TIF_X32)) 150 if (test_thread_flag(TIF_X32))
@@ -163,14 +167,49 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
163 /* 167 /*
164 * MAYWRITE to allow gdb to COW and set breakpoints 168 * MAYWRITE to allow gdb to COW and set breakpoints
165 */ 169 */
166 ret = install_special_mapping(mm, addr, PAGE_SIZE, 170 ret = install_special_mapping(mm,
167 VM_READ|VM_EXEC| 171 addr,
168 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, 172 VDSO_OFFSET(VDSO_PAGES - VDSO_PREV_PAGES),
169 vdso32_pages); 173 VM_READ|VM_EXEC|
174 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
175 vdso32_pages);
170 176
171 if (ret) 177 if (ret)
172 goto up_fail; 178 goto up_fail;
173 179
180 vma = _install_special_mapping(mm,
181 addr - VDSO_OFFSET(VDSO_PREV_PAGES),
182 VDSO_OFFSET(VDSO_PREV_PAGES),
183 VM_READ,
184 NULL);
185
186 if (IS_ERR(vma)) {
187 ret = PTR_ERR(vma);
188 goto up_fail;
189 }
190
191 ret = remap_pfn_range(vma,
192 addr - VDSO_OFFSET(VDSO_VVAR_PAGE),
193 __pa_symbol(&__vvar_page) >> PAGE_SHIFT,
194 PAGE_SIZE,
195 PAGE_READONLY);
196
197 if (ret)
198 goto up_fail;
199
200#ifdef CONFIG_HPET_TIMER
201 if (hpet_address) {
202 ret = io_remap_pfn_range(vma,
203 addr - VDSO_OFFSET(VDSO_HPET_PAGE),
204 hpet_address >> PAGE_SHIFT,
205 PAGE_SIZE,
206 pgprot_noncached(PAGE_READONLY));
207
208 if (ret)
209 goto up_fail;
210 }
211#endif
212
174 current_thread_info()->sysenter_return = 213 current_thread_info()->sysenter_return =
175 VDSO32_SYMBOL(addr, SYSENTER_RETURN); 214 VDSO32_SYMBOL(addr, SYSENTER_RETURN);
176 215
diff --git a/arch/x86/vdso/vdso32/vclock_gettime.c b/arch/x86/vdso/vdso32/vclock_gettime.c
new file mode 100644
index 000000000000..ca65e4213d63
--- /dev/null
+++ b/arch/x86/vdso/vdso32/vclock_gettime.c
@@ -0,0 +1,9 @@
1#define BUILD_VDSO32
2
3#ifndef CONFIG_CC_OPTIMIZE_FOR_SIZE
4#undef CONFIG_OPTIMIZE_INLINING
5#endif
6
7#undef CONFIG_X86_PPRO_FENCE
8
9#include "../vclock_gettime.c"
diff --git a/arch/x86/vdso/vdso32/vdso32.lds.S b/arch/x86/vdso/vdso32/vdso32.lds.S
index 90e7aa90dbe4..28c460703bbc 100644
--- a/arch/x86/vdso/vdso32/vdso32.lds.S
+++ b/arch/x86/vdso/vdso32/vdso32.lds.S
@@ -8,6 +8,11 @@
8 * values visible using the asm-x86/vdso.h macros from the kernel proper. 8 * values visible using the asm-x86/vdso.h macros from the kernel proper.
9 */ 9 */
10 10
11#include <asm/page.h>
12
13#define BUILD_VDSO32
14#define VDSO_PRELINK 0
15
11#include "../vdso-layout.lds.S" 16#include "../vdso-layout.lds.S"
12 17
13/* The ELF entry point can be used to set the AT_SYSINFO value. */ 18/* The ELF entry point can be used to set the AT_SYSINFO value. */
@@ -23,6 +28,9 @@ VERSION
23 __kernel_vsyscall; 28 __kernel_vsyscall;
24 __kernel_sigreturn; 29 __kernel_sigreturn;
25 __kernel_rt_sigreturn; 30 __kernel_rt_sigreturn;
31 __vdso_clock_gettime;
32 __vdso_gettimeofday;
33 __vdso_time;
26 local: *; 34 local: *;
27 }; 35 };
28} 36}
@@ -33,3 +41,6 @@ VERSION
33VDSO32_vsyscall = __kernel_vsyscall; 41VDSO32_vsyscall = __kernel_vsyscall;
34VDSO32_sigreturn = __kernel_sigreturn; 42VDSO32_sigreturn = __kernel_sigreturn;
35VDSO32_rt_sigreturn = __kernel_rt_sigreturn; 43VDSO32_rt_sigreturn = __kernel_rt_sigreturn;
44VDSO32_clock_gettime = clock_gettime;
45VDSO32_gettimeofday = gettimeofday;
46VDSO32_time = time;