aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel/vdso
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2012-03-05 06:49:31 -0500
committerCatalin Marinas <catalin.marinas@arm.com>2012-09-17 08:42:09 -0400
commit9031fefde6f2ac1d1e5e0f8f4b22db4a091229bb (patch)
treea0663ffbc50293991604badf82f263dd50c009c7 /arch/arm64/kernel/vdso
parent7992d60dc46576bc6f6429d87f313462141db6d2 (diff)
arm64: VDSO support
This patch adds VDSO support for 64-bit applications. The VDSO code is currently used for sys_rt_sigreturn() and optimised gettimeofday() (using the user-accessible generic counter). Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Acked-by: Tony Lindgren <tony@atomide.com> Acked-by: Nicolas Pitre <nico@linaro.org> Acked-by: Olof Johansson <olof@lixom.net> Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Acked-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/arm64/kernel/vdso')
-rw-r--r--arch/arm64/kernel/vdso/.gitignore2
-rw-r--r--arch/arm64/kernel/vdso/Makefile63
-rwxr-xr-xarch/arm64/kernel/vdso/gen_vdso_offsets.sh15
-rw-r--r--arch/arm64/kernel/vdso/gettimeofday.S242
-rw-r--r--arch/arm64/kernel/vdso/note.S28
-rw-r--r--arch/arm64/kernel/vdso/sigreturn.S37
-rw-r--r--arch/arm64/kernel/vdso/vdso.S33
-rw-r--r--arch/arm64/kernel/vdso/vdso.lds.S100
8 files changed, 520 insertions, 0 deletions
diff --git a/arch/arm64/kernel/vdso/.gitignore b/arch/arm64/kernel/vdso/.gitignore
new file mode 100644
index 000000000000..b8cc94e9698b
--- /dev/null
+++ b/arch/arm64/kernel/vdso/.gitignore
@@ -0,0 +1,2 @@
1vdso.lds
2vdso-offsets.h
diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile
new file mode 100644
index 000000000000..d8064af42e62
--- /dev/null
+++ b/arch/arm64/kernel/vdso/Makefile
@@ -0,0 +1,63 @@
1#
2# Building a vDSO image for AArch64.
3#
4# Author: Will Deacon <will.deacon@arm.com>
5# Heavily based on the vDSO Makefiles for other archs.
6#
7
8obj-vdso := gettimeofday.o note.o sigreturn.o
9
10# Build rules
11targets := $(obj-vdso) vdso.so vdso.so.dbg
12obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
13
14ccflags-y := -shared -fno-common -fno-builtin
15ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 \
16 $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
17
18obj-y += vdso.o
19extra-y += vdso.lds vdso-offsets.h
20CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
21
22# Force dependency (incbin is bad)
23$(obj)/vdso.o : $(obj)/vdso.so
24
25# Link rule for the .so file, .lds has to be first
26$(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso)
27 $(call if_changed,vdsold)
28
29# Strip rule for the .so file
30$(obj)/%.so: OBJCOPYFLAGS := -S
31$(obj)/%.so: $(obj)/%.so.dbg FORCE
32 $(call if_changed,objcopy)
33
34# Generate VDSO offsets using helper script
35gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh
36quiet_cmd_vdsosym = VDSOSYM $@
37define cmd_vdsosym
38 $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@ && \
39 cp $@ include/generated/
40endef
41
42$(obj)/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE
43 $(call if_changed,vdsosym)
44
45# Assembly rules for the .S files
46$(obj-vdso): %.o: %.S
47 $(call if_changed_dep,vdsoas)
48
49# Actual build commands
50quiet_cmd_vdsold = VDSOL $@
51 cmd_vdsold = $(CC) $(c_flags) -Wl,-T $^ -o $@
52quiet_cmd_vdsoas = VDSOA $@
53 cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $<
54
55# Install commands for the unstripped file
56quiet_cmd_vdso_install = INSTALL $@
57 cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
58
59vdso.so: $(obj)/vdso.so.dbg
60 @mkdir -p $(MODLIB)/vdso
61 $(call cmd,vdso_install)
62
63vdso_install: vdso.so
diff --git a/arch/arm64/kernel/vdso/gen_vdso_offsets.sh b/arch/arm64/kernel/vdso/gen_vdso_offsets.sh
new file mode 100755
index 000000000000..01924ff071ad
--- /dev/null
+++ b/arch/arm64/kernel/vdso/gen_vdso_offsets.sh
@@ -0,0 +1,15 @@
1#!/bin/sh
2
3#
4# Match symbols in the DSO that look like VDSO_*; produce a header file
5# of constant offsets into the shared object.
6#
7# Doing this inside the Makefile will break the $(filter-out) function,
8# causing Kbuild to rebuild the vdso-offsets header file every time.
9#
10# Author: Will Deacon <will.deacon@arm.com
11#
12
13LC_ALL=C
14sed -n -e 's/^00*/0/' -e \
15's/^\([0-9a-fA-F]*\) . VDSO_\([a-zA-Z0-9_]*\)$/\#define vdso_offset_\2\t0x\1/p'
diff --git a/arch/arm64/kernel/vdso/gettimeofday.S b/arch/arm64/kernel/vdso/gettimeofday.S
new file mode 100644
index 000000000000..dcb8c203a3b2
--- /dev/null
+++ b/arch/arm64/kernel/vdso/gettimeofday.S
@@ -0,0 +1,242 @@
1/*
2 * Userspace implementations of gettimeofday() and friends.
3 *
4 * Copyright (C) 2012 ARM Limited
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: Will Deacon <will.deacon@arm.com>
19 */
20
21#include <linux/linkage.h>
22#include <asm/asm-offsets.h>
23#include <asm/unistd.h>
24
25#define NSEC_PER_SEC_LO16 0xca00
26#define NSEC_PER_SEC_HI16 0x3b9a
27
28vdso_data .req x6
29use_syscall .req w7
30seqcnt .req w8
31
32 .macro seqcnt_acquire
339999: ldr seqcnt, [vdso_data, #VDSO_TB_SEQ_COUNT]
34 tbnz seqcnt, #0, 9999b
35 dmb ishld
36 ldr use_syscall, [vdso_data, #VDSO_USE_SYSCALL]
37 .endm
38
39 .macro seqcnt_read, cnt
40 dmb ishld
41 ldr \cnt, [vdso_data, #VDSO_TB_SEQ_COUNT]
42 .endm
43
44 .macro seqcnt_check, cnt, fail
45 cmp \cnt, seqcnt
46 b.ne \fail
47 .endm
48
49 .text
50
51/* int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz); */
52ENTRY(__kernel_gettimeofday)
53 .cfi_startproc
54 mov x2, x30
55 .cfi_register x30, x2
56
57 /* Acquire the sequence counter and get the timespec. */
58 adr vdso_data, _vdso_data
591: seqcnt_acquire
60 cbnz use_syscall, 4f
61
62 /* If tv is NULL, skip to the timezone code. */
63 cbz x0, 2f
64 bl __do_get_tspec
65 seqcnt_check w13, 1b
66
67 /* Convert ns to us. */
68 mov x11, #1000
69 udiv x10, x10, x11
70 stp x9, x10, [x0, #TVAL_TV_SEC]
712:
72 /* If tz is NULL, return 0. */
73 cbz x1, 3f
74 ldp w4, w5, [vdso_data, #VDSO_TZ_MINWEST]
75 seqcnt_read w13
76 seqcnt_check w13, 1b
77 stp w4, w5, [x1, #TZ_MINWEST]
783:
79 mov x0, xzr
80 ret x2
814:
82 /* Syscall fallback. */
83 mov x8, #__NR_gettimeofday
84 svc #0
85 ret x2
86 .cfi_endproc
87ENDPROC(__kernel_gettimeofday)
88
89/* int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp); */
90ENTRY(__kernel_clock_gettime)
91 .cfi_startproc
92 cmp w0, #CLOCK_REALTIME
93 ccmp w0, #CLOCK_MONOTONIC, #0x4, ne
94 b.ne 2f
95
96 mov x2, x30
97 .cfi_register x30, x2
98
99 /* Get kernel timespec. */
100 adr vdso_data, _vdso_data
1011: seqcnt_acquire
102 cbnz use_syscall, 7f
103
104 bl __do_get_tspec
105 seqcnt_check w13, 1b
106
107 cmp w0, #CLOCK_MONOTONIC
108 b.ne 6f
109
110 /* Get wtm timespec. */
111 ldp x14, x15, [vdso_data, #VDSO_WTM_CLK_SEC]
112
113 /* Check the sequence counter. */
114 seqcnt_read w13
115 seqcnt_check w13, 1b
116 b 4f
1172:
118 cmp w0, #CLOCK_REALTIME_COARSE
119 ccmp w0, #CLOCK_MONOTONIC_COARSE, #0x4, ne
120 b.ne 8f
121
122 /* Get coarse timespec. */
123 adr vdso_data, _vdso_data
1243: seqcnt_acquire
125 ldp x9, x10, [vdso_data, #VDSO_XTIME_CRS_SEC]
126
127 cmp w0, #CLOCK_MONOTONIC_COARSE
128 b.ne 6f
129
130 /* Get wtm timespec. */
131 ldp x14, x15, [vdso_data, #VDSO_WTM_CLK_SEC]
132
133 /* Check the sequence counter. */
134 seqcnt_read w13
135 seqcnt_check w13, 3b
1364:
137 /* Add on wtm timespec. */
138 add x9, x9, x14
139 add x10, x10, x15
140
141 /* Normalise the new timespec. */
142 mov x14, #NSEC_PER_SEC_LO16
143 movk x14, #NSEC_PER_SEC_HI16, lsl #16
144 cmp x10, x14
145 b.lt 5f
146 sub x10, x10, x14
147 add x9, x9, #1
1485:
149 cmp x10, #0
150 b.ge 6f
151 add x10, x10, x14
152 sub x9, x9, #1
153
1546: /* Store to the user timespec. */
155 stp x9, x10, [x1, #TSPEC_TV_SEC]
156 mov x0, xzr
157 ret x2
1587:
159 mov x30, x2
1608: /* Syscall fallback. */
161 mov x8, #__NR_clock_gettime
162 svc #0
163 ret
164 .cfi_endproc
165ENDPROC(__kernel_clock_gettime)
166
167/* int __kernel_clock_getres(clockid_t clock_id, struct timespec *res); */
168ENTRY(__kernel_clock_getres)
169 .cfi_startproc
170 cbz w1, 3f
171
172 cmp w0, #CLOCK_REALTIME
173 ccmp w0, #CLOCK_MONOTONIC, #0x4, ne
174 b.ne 1f
175
176 ldr x2, 5f
177 b 2f
1781:
179 cmp w0, #CLOCK_REALTIME_COARSE
180 ccmp w0, #CLOCK_MONOTONIC_COARSE, #0x4, ne
181 b.ne 4f
182 ldr x2, 6f
1832:
184 stp xzr, x2, [x1]
185
1863: /* res == NULL. */
187 mov w0, wzr
188 ret
189
1904: /* Syscall fallback. */
191 mov x8, #__NR_clock_getres
192 svc #0
193 ret
1945:
195 .quad CLOCK_REALTIME_RES
1966:
197 .quad CLOCK_COARSE_RES
198 .cfi_endproc
199ENDPROC(__kernel_clock_getres)
200
201/*
202 * Read the current time from the architected counter.
203 * Expects vdso_data to be initialised.
204 * Clobbers the temporary registers (x9 - x15).
205 * Returns:
206 * - (x9, x10) = (ts->tv_sec, ts->tv_nsec)
207 * - (x11, x12) = (xtime->tv_sec, xtime->tv_nsec)
208 * - w13 = vDSO sequence counter
209 */
210ENTRY(__do_get_tspec)
211 .cfi_startproc
212
213 /* Read from the vDSO data page. */
214 ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST]
215 ldp x11, x12, [vdso_data, #VDSO_XTIME_CLK_SEC]
216 ldp w14, w15, [vdso_data, #VDSO_CS_MULT]
217 seqcnt_read w13
218
219 /* Read the physical counter. */
220 isb
221 mrs x9, cntpct_el0
222
223 /* Calculate cycle delta and convert to ns. */
224 sub x10, x9, x10
225 /* We can only guarantee 56 bits of precision. */
226 movn x9, #0xff0, lsl #48
227 and x10, x9, x10
228 mul x10, x10, x14
229 lsr x10, x10, x15
230
231 /* Use the kernel time to calculate the new timespec. */
232 add x10, x12, x10
233 mov x14, #NSEC_PER_SEC_LO16
234 movk x14, #NSEC_PER_SEC_HI16, lsl #16
235 udiv x15, x10, x14
236 add x9, x15, x11
237 mul x14, x14, x15
238 sub x10, x10, x14
239
240 ret
241 .cfi_endproc
242ENDPROC(__do_get_tspec)
diff --git a/arch/arm64/kernel/vdso/note.S b/arch/arm64/kernel/vdso/note.S
new file mode 100644
index 000000000000..b82c85e5d972
--- /dev/null
+++ b/arch/arm64/kernel/vdso/note.S
@@ -0,0 +1,28 @@
1/*
2 * Copyright (C) 2012 ARM Limited
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Will Deacon <will.deacon@arm.com>
17 *
18 * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
19 * Here we can supply some information useful to userland.
20 */
21
22#include <linux/uts.h>
23#include <linux/version.h>
24#include <linux/elfnote.h>
25
26ELFNOTE_START(Linux, 0, "a")
27 .long LINUX_VERSION_CODE
28ELFNOTE_END
diff --git a/arch/arm64/kernel/vdso/sigreturn.S b/arch/arm64/kernel/vdso/sigreturn.S
new file mode 100644
index 000000000000..20d98effa7dd
--- /dev/null
+++ b/arch/arm64/kernel/vdso/sigreturn.S
@@ -0,0 +1,37 @@
1/*
2 * Sigreturn trampoline for returning from a signal when the SA_RESTORER
3 * flag is not set.
4 *
5 * Copyright (C) 2012 ARM Limited
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Will Deacon <will.deacon@arm.com>
20 */
21
22#include <linux/linkage.h>
23#include <asm/unistd.h>
24
25 .text
26
27 nop
28ENTRY(__kernel_rt_sigreturn)
29 .cfi_startproc
30 .cfi_signal_frame
31 .cfi_def_cfa x29, 0
32 .cfi_offset x29, 0 * 8
33 .cfi_offset x30, 1 * 8
34 mov x8, #__NR_rt_sigreturn
35 svc #0
36 .cfi_endproc
37ENDPROC(__kernel_rt_sigreturn)
diff --git a/arch/arm64/kernel/vdso/vdso.S b/arch/arm64/kernel/vdso/vdso.S
new file mode 100644
index 000000000000..60c1db54b41a
--- /dev/null
+++ b/arch/arm64/kernel/vdso/vdso.S
@@ -0,0 +1,33 @@
1/*
2 * Copyright (C) 2012 ARM Limited
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Will Deacon <will.deacon@arm.com>
17 */
18
19#include <linux/init.h>
20#include <linux/linkage.h>
21#include <linux/const.h>
22#include <asm/page.h>
23
24 __PAGE_ALIGNED_DATA
25
26 .globl vdso_start, vdso_end
27 .balign PAGE_SIZE
28vdso_start:
29 .incbin "arch/arm64/kernel/vdso/vdso.so"
30 .balign PAGE_SIZE
31vdso_end:
32
33 .previous
diff --git a/arch/arm64/kernel/vdso/vdso.lds.S b/arch/arm64/kernel/vdso/vdso.lds.S
new file mode 100644
index 000000000000..8154b8d1c826
--- /dev/null
+++ b/arch/arm64/kernel/vdso/vdso.lds.S
@@ -0,0 +1,100 @@
1/*
2 * GNU linker script for the VDSO library.
3*
4 * Copyright (C) 2012 ARM Limited
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: Will Deacon <will.deacon@arm.com>
19 * Heavily based on the vDSO linker scripts for other archs.
20 */
21
22#include <linux/const.h>
23#include <asm/page.h>
24#include <asm/vdso.h>
25
26OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64", "elf64-littleaarch64")
27OUTPUT_ARCH(aarch64)
28
29SECTIONS
30{
31 . = VDSO_LBASE + SIZEOF_HEADERS;
32
33 .hash : { *(.hash) } :text
34 .gnu.hash : { *(.gnu.hash) }
35 .dynsym : { *(.dynsym) }
36 .dynstr : { *(.dynstr) }
37 .gnu.version : { *(.gnu.version) }
38 .gnu.version_d : { *(.gnu.version_d) }
39 .gnu.version_r : { *(.gnu.version_r) }
40
41 .note : { *(.note.*) } :text :note
42
43 . = ALIGN(16);
44
45 .text : { *(.text*) } :text =0xd503201f
46 PROVIDE (__etext = .);
47 PROVIDE (_etext = .);
48 PROVIDE (etext = .);
49
50 .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
51 .eh_frame : { KEEP (*(.eh_frame)) } :text
52
53 .dynamic : { *(.dynamic) } :text :dynamic
54
55 .rodata : { *(.rodata*) } :text
56
57 _end = .;
58 PROVIDE(end = .);
59
60 . = ALIGN(PAGE_SIZE);
61 PROVIDE(_vdso_data = .);
62
63 /DISCARD/ : {
64 *(.note.GNU-stack)
65 *(.data .data.* .gnu.linkonce.d.* .sdata*)
66 *(.bss .sbss .dynbss .dynsbss)
67 }
68}
69
70/*
71 * We must supply the ELF program headers explicitly to get just one
72 * PT_LOAD segment, and set the flags explicitly to make segments read-only.
73 */
74PHDRS
75{
76 text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
77 dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
78 note PT_NOTE FLAGS(4); /* PF_R */
79 eh_frame_hdr PT_GNU_EH_FRAME;
80}
81
82/*
83 * This controls what symbols we export from the DSO.
84 */
85VERSION
86{
87 LINUX_2.6.39 {
88 global:
89 __kernel_rt_sigreturn;
90 __kernel_gettimeofday;
91 __kernel_clock_gettime;
92 __kernel_clock_getres;
93 local: *;
94 };
95}
96
97/*
98 * Make the sigreturn code visible to the kernel.
99 */
100VDSO_sigtramp = __kernel_rt_sigreturn;