diff options
author | Stefani Seibold <stefani@seibold.net> | 2014-03-17 18:22:09 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2014-03-18 15:52:37 -0400 |
commit | 7a59ed415f5b57469e22e41fc4188d5399e0b194 (patch) | |
tree | fb57bae076853fbcbd44af62fb07d77d3c44125b /arch/x86/vdso | |
parent | b4b541a610c4db8643b36030ee5012203ca65778 (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/Makefile | 8 | ||||
-rw-r--r-- | arch/x86/vdso/vclock_gettime.c | 76 | ||||
-rw-r--r-- | arch/x86/vdso/vdso-layout.lds.S | 22 | ||||
-rw-r--r-- | arch/x86/vdso/vdso32-setup.c | 47 | ||||
-rw-r--r-- | arch/x86/vdso/vdso32/vclock_gettime.c | 9 | ||||
-rw-r--r-- | arch/x86/vdso/vdso32/vdso32.lds.S | 11 |
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 | ||
149 | KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS)) | ||
150 | KBUILD_CFLAGS_32 := $(filter-out -mcmodel=kernel,$(KBUILD_CFLAGS_32)) | ||
151 | KBUILD_CFLAGS_32 := $(filter-out -fno-pic,$(KBUILD_CFLAGS_32)) | ||
152 | KBUILD_CFLAGS_32 := $(filter-out -mfentry,$(KBUILD_CFLAGS_32)) | ||
153 | KBUILD_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 | ||
30 | extern int __vdso_clock_gettime(clockid_t clock, struct timespec *ts); | ||
31 | extern int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz); | ||
32 | extern time_t __vdso_time(time_t *t); | ||
33 | |||
34 | #ifndef BUILD_VDSO32 | ||
35 | |||
29 | static notrace cycle_t vread_hpet(void) | 36 | static 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 | |||
130 | extern u8 hpet_page | ||
131 | __attribute__((visibility("hidden"))); | ||
132 | |||
133 | #ifdef CONFIG_HPET_TIMER | ||
134 | static notrace cycle_t vread_hpet(void) | ||
135 | { | ||
136 | return readl((const void __iomem *)(&hpet_page + HPET_COUNTER)); | ||
137 | } | ||
138 | #endif | ||
139 | |||
140 | notrace 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 | |||
155 | notrace 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 | |||
172 | static notrace cycle_t vread_pvclock(int *mode) | ||
173 | { | ||
174 | *mode = VCLOCK_NONE; | ||
175 | return 0; | ||
176 | } | ||
177 | #endif | ||
178 | |||
179 | #endif | ||
180 | |||
121 | notrace static cycle_t vread_tsc(void) | 181 | notrace 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 | ||
153 | notrace static inline u64 vgetsns(int *mode) | 213 | notrace 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 | ||
192 | notrace static int do_monotonic(struct timespec *ts) | 254 | notrace 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 | */ |
285 | notrace time_t __vdso_time(time_t *t) | 347 | notrace 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 | ||
7 | SECTIONS | 7 | SECTIONS |
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 | |||
33 | VDSO32_vsyscall = __kernel_vsyscall; | 41 | VDSO32_vsyscall = __kernel_vsyscall; |
34 | VDSO32_sigreturn = __kernel_sigreturn; | 42 | VDSO32_sigreturn = __kernel_sigreturn; |
35 | VDSO32_rt_sigreturn = __kernel_rt_sigreturn; | 43 | VDSO32_rt_sigreturn = __kernel_rt_sigreturn; |
44 | VDSO32_clock_gettime = clock_gettime; | ||
45 | VDSO32_gettimeofday = gettimeofday; | ||
46 | VDSO32_time = time; | ||