aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/vdso32
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-11-11 05:15:21 -0500
committerPaul Mackerras <paulus@samba.org>2005-11-11 06:25:39 -0500
commita7f290dad32ee34d931561b7943c858fe2aae503 (patch)
tree850f04ed9ffba8aef6e151fa9c9e8a0c667bb795 /arch/powerpc/kernel/vdso32
parent6761c4a07378e19e3710bb69cea65795774529b1 (diff)
[PATCH] powerpc: Merge vdso's and add vdso support to 32 bits kernel
This patch moves the vdso's to arch/powerpc, adds support for the 32 bits vdso to the 32 bits kernel, rename systemcfg (finally !), and adds some new (still untested) routines to both vdso's: clock_gettime() with support for CLOCK_REALTIME and CLOCK_MONOTONIC, clock_getres() (same clocks) and get_tbfreq() for glibc to retreive the timebase frequency. Tom,Steve: The implementation of get_tbfreq() I've done for 32 bits returns a long long (r3, r4) not a long. This is such that if we ever add support for >4Ghz timebases on ppc32, the userland interface won't have to change. I have tested gettimeofday() using some glibc patches in both ppc32 and ppc64 kernels using 32 bits userland (I haven't had a chance to test a 64 bits userland yet, but the implementation didn't change and was tested earlier). I haven't tested yet the new functions. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/vdso32')
-rw-r--r--arch/powerpc/kernel/vdso32/Makefile40
-rw-r--r--arch/powerpc/kernel/vdso32/cacheflush.S67
-rw-r--r--arch/powerpc/kernel/vdso32/datapage.S84
-rw-r--r--arch/powerpc/kernel/vdso32/gettimeofday.S315
-rw-r--r--arch/powerpc/kernel/vdso32/note.S25
-rw-r--r--arch/powerpc/kernel/vdso32/sigtramp.S300
-rw-r--r--arch/powerpc/kernel/vdso32/vdso32.lds.S117
-rw-r--r--arch/powerpc/kernel/vdso32/vdso32_wrapper.S13
8 files changed, 961 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/vdso32/Makefile b/arch/powerpc/kernel/vdso32/Makefile
new file mode 100644
index 000000000000..758331d4d1a5
--- /dev/null
+++ b/arch/powerpc/kernel/vdso32/Makefile
@@ -0,0 +1,40 @@
1
2# List of files in the vdso, has to be asm only for now
3
4obj-vdso32 = sigtramp.o gettimeofday.o datapage.o cacheflush.o note.o
5
6# Build rules
7
8ifeq ($(CONFIG_PPC32),y)
9CROSS32CC := $(CC)
10endif
11
12targets := $(obj-vdso32) vdso32.so
13obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32))
14
15
16EXTRA_CFLAGS := -shared -s -fno-common -fno-builtin
17EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso32.so.1
18EXTRA_AFLAGS := -D__VDSO32__ -s
19
20obj-y += vdso32_wrapper.o
21extra-y += vdso32.lds
22CPPFLAGS_vdso32.lds += -P -C -U$(ARCH)
23
24# Force dependency (incbin is bad)
25$(obj)/vdso32_wrapper.o : $(obj)/vdso32.so
26
27# link rule for the .so file, .lds has to be first
28$(obj)/vdso32.so: $(src)/vdso32.lds $(obj-vdso32)
29 $(call if_changed,vdso32ld)
30
31# assembly rules for the .S files
32$(obj-vdso32): %.o: %.S
33 $(call if_changed_dep,vdso32as)
34
35# actual build commands
36quiet_cmd_vdso32ld = VDSO32L $@
37 cmd_vdso32ld = $(CROSS32CC) $(c_flags) -Wl,-T $^ -o $@
38quiet_cmd_vdso32as = VDSO32A $@
39 cmd_vdso32as = $(CROSS32CC) $(a_flags) -c -o $@ $<
40
diff --git a/arch/powerpc/kernel/vdso32/cacheflush.S b/arch/powerpc/kernel/vdso32/cacheflush.S
new file mode 100644
index 000000000000..c8db993574ee
--- /dev/null
+++ b/arch/powerpc/kernel/vdso32/cacheflush.S
@@ -0,0 +1,67 @@
1/*
2 * vDSO provided cache flush routines
3 *
4 * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org),
5 * IBM Corp.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 */
12#include <linux/config.h>
13#include <asm/processor.h>
14#include <asm/ppc_asm.h>
15#include <asm/vdso.h>
16#include <asm/asm-offsets.h>
17
18 .text
19
20/*
21 * Default "generic" version of __kernel_sync_dicache.
22 *
23 * void __kernel_sync_dicache(unsigned long start, unsigned long end)
24 *
25 * Flushes the data cache & invalidate the instruction cache for the
26 * provided range [start, end[
27 *
28 * Note: all CPUs supported by this kernel have a 128 bytes cache
29 * line size so we don't have to peek that info from the datapage
30 */
31V_FUNCTION_BEGIN(__kernel_sync_dicache)
32 .cfi_startproc
33 li r5,127
34 andc r6,r3,r5 /* round low to line bdy */
35 subf r8,r6,r4 /* compute length */
36 add r8,r8,r5 /* ensure we get enough */
37 srwi. r8,r8,7 /* compute line count */
38 beqlr /* nothing to do? */
39 mtctr r8
40 mr r3,r6
411: dcbst 0,r3
42 addi r3,r3,128
43 bdnz 1b
44 sync
45 mtctr r8
461: icbi 0,r6
47 addi r6,r6,128
48 bdnz 1b
49 isync
50 li r3,0
51 blr
52 .cfi_endproc
53V_FUNCTION_END(__kernel_sync_dicache)
54
55
56/*
57 * POWER5 version of __kernel_sync_dicache
58 */
59V_FUNCTION_BEGIN(__kernel_sync_dicache_p5)
60 .cfi_startproc
61 sync
62 isync
63 li r3,0
64 blr
65 .cfi_endproc
66V_FUNCTION_END(__kernel_sync_dicache_p5)
67
diff --git a/arch/powerpc/kernel/vdso32/datapage.S b/arch/powerpc/kernel/vdso32/datapage.S
new file mode 100644
index 000000000000..a08c26e87835
--- /dev/null
+++ b/arch/powerpc/kernel/vdso32/datapage.S
@@ -0,0 +1,84 @@
1/*
2 * Access to the shared data page by the vDSO & syscall map
3 *
4 * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), IBM Corp.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <linux/config.h>
13#include <asm/processor.h>
14#include <asm/ppc_asm.h>
15#include <asm/asm-offsets.h>
16#include <asm/unistd.h>
17#include <asm/vdso.h>
18
19 .text
20V_FUNCTION_BEGIN(__get_datapage)
21 .cfi_startproc
22 /* We don't want that exposed or overridable as we want other objects
23 * to be able to bl directly to here
24 */
25 .protected __get_datapage
26 .hidden __get_datapage
27
28 mflr r0
29 .cfi_register lr,r0
30
31 bcl 20,31,1f
32 .global __kernel_datapage_offset;
33__kernel_datapage_offset:
34 .long 0
351:
36 mflr r3
37 mtlr r0
38 lwz r0,0(r3)
39 add r3,r0,r3
40 blr
41 .cfi_endproc
42V_FUNCTION_END(__get_datapage)
43
44/*
45 * void *__kernel_get_syscall_map(unsigned int *syscall_count) ;
46 *
47 * returns a pointer to the syscall map. the map is agnostic to the
48 * size of "long", unlike kernel bitops, it stores bits from top to
49 * bottom so that memory actually contains a linear bitmap
50 * check for syscall N by testing bit (0x80000000 >> (N & 0x1f)) of
51 * 32 bits int at N >> 5.
52 */
53V_FUNCTION_BEGIN(__kernel_get_syscall_map)
54 .cfi_startproc
55 mflr r12
56 .cfi_register lr,r12
57
58 mr r4,r3
59 bl __get_datapage@local
60 mtlr r12
61 addi r3,r3,CFG_SYSCALL_MAP32
62 cmpli cr0,r4,0
63 beqlr
64 li r0,__NR_syscalls
65 stw r0,0(r4)
66 blr
67 .cfi_endproc
68V_FUNCTION_END(__kernel_get_syscall_map)
69
70/*
71 * void unsigned long long __kernel_get_tbfreq(void);
72 *
73 * returns the timebase frequency in HZ
74 */
75V_FUNCTION_BEGIN(__kernel_get_tbfreq)
76 .cfi_startproc
77 mflr r12
78 .cfi_register lr,r12
79 bl __get_datapage@local
80 lwz r3,CFG_TB_TICKS_PER_SEC(r3)
81 lwz r4,(CFG_TB_TICKS_PER_SEC + 4)(r3)
82 mtlr r12
83 .cfi_endproc
84V_FUNCTION_END(__kernel_get_tbfreq)
diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S
new file mode 100644
index 000000000000..aeb5fc9b87b3
--- /dev/null
+++ b/arch/powerpc/kernel/vdso32/gettimeofday.S
@@ -0,0 +1,315 @@
1/*
2 * Userland implementation of gettimeofday() for 32 bits processes in a
3 * ppc64 kernel for use in the vDSO
4 *
5 * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org,
6 * IBM Corp.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13#include <linux/config.h>
14#include <asm/processor.h>
15#include <asm/ppc_asm.h>
16#include <asm/vdso.h>
17#include <asm/asm-offsets.h>
18#include <asm/unistd.h>
19
20 .text
21/*
22 * Exact prototype of gettimeofday
23 *
24 * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz);
25 *
26 */
27V_FUNCTION_BEGIN(__kernel_gettimeofday)
28 .cfi_startproc
29 mflr r12
30 .cfi_register lr,r12
31
32 mr r10,r3 /* r10 saves tv */
33 mr r11,r4 /* r11 saves tz */
34 bl __get_datapage@local /* get data page */
35 mr r9, r3 /* datapage ptr in r9 */
36 bl __do_get_xsec@local /* get xsec from tb & kernel */
37 bne- 2f /* out of line -> do syscall */
38
39 /* seconds are xsec >> 20 */
40 rlwinm r5,r4,12,20,31
41 rlwimi r5,r3,12,0,19
42 stw r5,TVAL32_TV_SEC(r10)
43
44 /* get remaining xsec and convert to usec. we scale
45 * up remaining xsec by 12 bits and get the top 32 bits
46 * of the multiplication
47 */
48 rlwinm r5,r4,12,0,19
49 lis r6,1000000@h
50 ori r6,r6,1000000@l
51 mulhwu r5,r5,r6
52 stw r5,TVAL32_TV_USEC(r10)
53
54 cmpli cr0,r11,0 /* check if tz is NULL */
55 beq 1f
56 lwz r4,CFG_TZ_MINUTEWEST(r9)/* fill tz */
57 lwz r5,CFG_TZ_DSTTIME(r9)
58 stw r4,TZONE_TZ_MINWEST(r11)
59 stw r5,TZONE_TZ_DSTTIME(r11)
60
611: mtlr r12
62 li r3,0
63 blr
64
652:
66 mtlr r12
67 mr r3,r10
68 mr r4,r11
69 li r0,__NR_gettimeofday
70 sc
71 blr
72 .cfi_endproc
73V_FUNCTION_END(__kernel_gettimeofday)
74
75/*
76 * Exact prototype of clock_gettime()
77 *
78 * int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp);
79 *
80 */
81V_FUNCTION_BEGIN(__kernel_clock_gettime)
82 .cfi_startproc
83 /* Check for supported clock IDs */
84 cmpli cr0,r3,CLOCK_REALTIME
85 cmpli cr1,r3,CLOCK_MONOTONIC
86 cror cr0,cr0,cr1
87 bne cr0,99f
88
89 mflr r12 /* r12 saves lr */
90 .cfi_register lr,r12
91 mr r10,r3 /* r10 saves id */
92 mr r11,r4 /* r11 saves tp */
93 bl __get_datapage@local /* get data page */
94 mr r9, r3 /* datapage ptr in r9 */
95 beq cr1,50f /* if monotonic -> jump there */
96
97 /*
98 * CLOCK_REALTIME
99 */
100
101 bl __do_get_xsec@local /* get xsec from tb & kernel */
102 bne- 98f /* out of line -> do syscall */
103
104 /* seconds are xsec >> 20 */
105 rlwinm r5,r4,12,20,31
106 rlwimi r5,r3,12,0,19
107 stw r5,TSPC32_TV_SEC(r11)
108
109 /* get remaining xsec and convert to nsec. we scale
110 * up remaining xsec by 12 bits and get the top 32 bits
111 * of the multiplication, then we multiply by 1000
112 */
113 rlwinm r5,r4,12,0,19
114 lis r6,1000000@h
115 ori r6,r6,1000000@l
116 mulhwu r5,r5,r6
117 mulli r5,r5,1000
118 stw r5,TSPC32_TV_NSEC(r11)
119 mtlr r12
120 li r3,0
121 blr
122
123 /*
124 * CLOCK_MONOTONIC
125 */
126
12750: bl __do_get_xsec@local /* get xsec from tb & kernel */
128 bne- 98f /* out of line -> do syscall */
129
130 /* seconds are xsec >> 20 */
131 rlwinm r6,r4,12,20,31
132 rlwimi r6,r3,12,0,19
133
134 /* get remaining xsec and convert to nsec. we scale
135 * up remaining xsec by 12 bits and get the top 32 bits
136 * of the multiplication, then we multiply by 1000
137 */
138 rlwinm r7,r4,12,0,19
139 lis r5,1000000@h
140 ori r5,r5,1000000@l
141 mulhwu r7,r7,r5
142 mulli r7,r7,1000
143
144 /* now we must fixup using wall to monotonic. We need to snapshot
145 * that value and do the counter trick again. Fortunately, we still
146 * have the counter value in r8 that was returned by __do_get_xsec.
147 * At this point, r6,r7 contain our sec/nsec values, r3,r4 and r5
148 * can be used
149 */
150
151 lwz r3,WTOM_CLOCK_SEC(r9)
152 lwz r4,WTOM_CLOCK_NSEC(r9)
153
154 /* We now have our result in r3,r4. We create a fake dependency
155 * on that result and re-check the counter
156 */
157 or r5,r4,r3
158 xor r0,r5,r5
159 add r9,r9,r0
160#ifdef CONFIG_PPC64
161 lwz r0,(CFG_TB_UPDATE_COUNT+4)(r9)
162#else
163 lwz r0,(CFG_TB_UPDATE_COUNT)(r9)
164#endif
165 cmpl cr0,r8,r0 /* check if updated */
166 bne- 50b
167
168 /* Calculate and store result. Note that this mimmics the C code,
169 * which may cause funny results if nsec goes negative... is that
170 * possible at all ?
171 */
172 add r3,r3,r6
173 add r4,r4,r7
174 lis r5,NSEC_PER_SEC@h
175 ori r5,r5,NSEC_PER_SEC@l
176 cmpli cr0,r4,r5
177 blt 1f
178 subf r4,r5,r4
179 addi r3,r3,1
1801: stw r3,TSPC32_TV_SEC(r11)
181 stw r4,TSPC32_TV_NSEC(r11)
182
183 mtlr r12
184 li r3,0
185 blr
186
187 /*
188 * syscall fallback
189 */
19098:
191 mtlr r12
192 mr r3,r10
193 mr r4,r11
19499:
195 li r0,__NR_clock_gettime
196 sc
197 blr
198 .cfi_endproc
199V_FUNCTION_END(__kernel_clock_gettime)
200
201
202/*
203 * Exact prototype of clock_getres()
204 *
205 * int __kernel_clock_getres(clockid_t clock_id, struct timespec *res);
206 *
207 */
208V_FUNCTION_BEGIN(__kernel_clock_getres)
209 .cfi_startproc
210 /* Check for supported clock IDs */
211 cmpwi cr0,r3,CLOCK_REALTIME
212 cmpwi cr1,r3,CLOCK_MONOTONIC
213 cror cr0,cr0,cr1
214 bne cr0,99f
215
216 li r3,0
217 cmpli cr0,r4,0
218 beqlr
219 lis r5,CLOCK_REALTIME_RES@h
220 ori r5,r5,CLOCK_REALTIME_RES@l
221 stw r3,TSPC32_TV_SEC(r4)
222 stw r5,TSPC32_TV_NSEC(r4)
223 blr
224
225 /*
226 * syscall fallback
227 */
22899:
229 li r0,__NR_clock_getres
230 sc
231 blr
232 .cfi_endproc
233V_FUNCTION_END(__kernel_clock_getres)
234
235
236/*
237 * This is the core of gettimeofday() & friends, it returns the xsec
238 * value in r3 & r4 and expects the datapage ptr (non clobbered)
239 * in r9. clobbers r0,r4,r5,r6,r7,r8.
240 * When returning, r8 contains the counter value that can be reused
241 * by the monotonic clock implementation
242 */
243__do_get_xsec:
244 .cfi_startproc
245 /* Check for update count & load values. We use the low
246 * order 32 bits of the update count
247 */
248#ifdef CONFIG_PPC64
2491: lwz r8,(CFG_TB_UPDATE_COUNT+4)(r9)
250#else
2511: lwz r8,(CFG_TB_UPDATE_COUNT)(r9)
252#endif
253 andi. r0,r8,1 /* pending update ? loop */
254 bne- 1b
255 xor r0,r8,r8 /* create dependency */
256 add r9,r9,r0
257
258 /* Load orig stamp (offset to TB) */
259 lwz r5,CFG_TB_ORIG_STAMP(r9)
260 lwz r6,(CFG_TB_ORIG_STAMP+4)(r9)
261
262 /* Get a stable TB value */
2632: mftbu r3
264 mftbl r4
265 mftbu r0
266 cmpl cr0,r3,r0
267 bne- 2b
268
269 /* Substract tb orig stamp. If the high part is non-zero, we jump to
270 * the slow path which call the syscall.
271 * If it's ok, then we have our 32 bits tb_ticks value in r7
272 */
273 subfc r7,r6,r4
274 subfe. r0,r5,r3
275 bne- 3f
276
277 /* Load scale factor & do multiplication */
278 lwz r5,CFG_TB_TO_XS(r9) /* load values */
279 lwz r6,(CFG_TB_TO_XS+4)(r9)
280 mulhwu r4,r7,r5
281 mulhwu r6,r7,r6
282 mullw r0,r7,r5
283 addc r6,r6,r0
284
285 /* At this point, we have the scaled xsec value in r4 + XER:CA
286 * we load & add the stamp since epoch
287 */
288 lwz r5,CFG_STAMP_XSEC(r9)
289 lwz r6,(CFG_STAMP_XSEC+4)(r9)
290 adde r4,r4,r6
291 addze r3,r5
292
293 /* We now have our result in r3,r4. We create a fake dependency
294 * on that result and re-check the counter
295 */
296 or r6,r4,r3
297 xor r0,r6,r6
298 add r9,r9,r0
299#ifdef CONFIG_PPC64
300 lwz r0,(CFG_TB_UPDATE_COUNT+4)(r9)
301#else
302 lwz r0,(CFG_TB_UPDATE_COUNT)(r9)
303#endif
304 cmpl cr0,r8,r0 /* check if updated */
305 bne- 1b
306
307 /* Warning ! The caller expects CR:EQ to be set to indicate a
308 * successful calculation (so it won't fallback to the syscall
309 * method). We have overriden that CR bit in the counter check,
310 * but fortunately, the loop exit condition _is_ CR:EQ set, so
311 * we can exit safely here. If you change this code, be careful
312 * of that side effect.
313 */
3143: blr
315 .cfi_endproc
diff --git a/arch/powerpc/kernel/vdso32/note.S b/arch/powerpc/kernel/vdso32/note.S
new file mode 100644
index 000000000000..d4b5be4f3d5f
--- /dev/null
+++ b/arch/powerpc/kernel/vdso32/note.S
@@ -0,0 +1,25 @@
1/*
2 * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
3 * Here we can supply some information useful to userland.
4 */
5
6#include <linux/uts.h>
7#include <linux/version.h>
8
9#define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type) \
10 .section name, flags; \
11 .balign 4; \
12 .long 1f - 0f; /* name length */ \
13 .long 3f - 2f; /* data length */ \
14 .long type; /* note type */ \
150: .asciz vendor; /* vendor name */ \
161: .balign 4; \
172:
18
19#define ASM_ELF_NOTE_END \
203: .balign 4; /* pad out section */ \
21 .previous
22
23 ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0)
24 .long LINUX_VERSION_CODE
25 ASM_ELF_NOTE_END
diff --git a/arch/powerpc/kernel/vdso32/sigtramp.S b/arch/powerpc/kernel/vdso32/sigtramp.S
new file mode 100644
index 000000000000..e04642781917
--- /dev/null
+++ b/arch/powerpc/kernel/vdso32/sigtramp.S
@@ -0,0 +1,300 @@
1/*
2 * Signal trampolines for 32 bits processes in a ppc64 kernel for
3 * use in the vDSO
4 *
5 * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), IBM Corp.
6 * Copyright (C) 2004 Alan Modra (amodra@au.ibm.com)), IBM Corp.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13#include <linux/config.h>
14#include <asm/processor.h>
15#include <asm/ppc_asm.h>
16#include <asm/unistd.h>
17#include <asm/vdso.h>
18
19 .text
20
21/* The nop here is a hack. The dwarf2 unwind routines subtract 1 from
22 the return address to get an address in the middle of the presumed
23 call instruction. Since we don't have a call here, we artifically
24 extend the range covered by the unwind info by adding a nop before
25 the real start. */
26 nop
27V_FUNCTION_BEGIN(__kernel_sigtramp32)
28.Lsig_start = . - 4
29 li r0,__NR_sigreturn
30 sc
31.Lsig_end:
32V_FUNCTION_END(__kernel_sigtramp32)
33
34.Lsigrt_start:
35 nop
36V_FUNCTION_BEGIN(__kernel_sigtramp_rt32)
37 li r0,__NR_rt_sigreturn
38 sc
39.Lsigrt_end:
40V_FUNCTION_END(__kernel_sigtramp_rt32)
41
42 .section .eh_frame,"a",@progbits
43
44/* Register r1 can be found at offset 4 of a pt_regs structure.
45 A pointer to the pt_regs is stored in memory at the old sp plus PTREGS. */
46#define cfa_save \
47 .byte 0x0f; /* DW_CFA_def_cfa_expression */ \
48 .uleb128 9f - 1f; /* length */ \
491: \
50 .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \
51 .byte 0x06; /* DW_OP_deref */ \
52 .byte 0x23; .uleb128 RSIZE; /* DW_OP_plus_uconst */ \
53 .byte 0x06; /* DW_OP_deref */ \
549:
55
56/* Register REGNO can be found at offset OFS of a pt_regs structure.
57 A pointer to the pt_regs is stored in memory at the old sp plus PTREGS. */
58#define rsave(regno, ofs) \
59 .byte 0x10; /* DW_CFA_expression */ \
60 .uleb128 regno; /* regno */ \
61 .uleb128 9f - 1f; /* length */ \
621: \
63 .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \
64 .byte 0x06; /* DW_OP_deref */ \
65 .ifne ofs; \
66 .byte 0x23; .uleb128 ofs; /* DW_OP_plus_uconst */ \
67 .endif; \
689:
69
70/* If msr bit 1<<25 is set, then VMX register REGNO is at offset REGNO*16
71 of the VMX reg struct. The VMX reg struct is at offset VREGS of
72 the pt_regs struct. This macro is for REGNO == 0, and contains
73 'subroutines' that the other macros jump to. */
74#define vsave_msr0(regno) \
75 .byte 0x10; /* DW_CFA_expression */ \
76 .uleb128 regno + 77; /* regno */ \
77 .uleb128 9f - 1f; /* length */ \
781: \
79 .byte 0x30 + regno; /* DW_OP_lit0 */ \
802: \
81 .byte 0x40; /* DW_OP_lit16 */ \
82 .byte 0x1e; /* DW_OP_mul */ \
833: \
84 .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \
85 .byte 0x06; /* DW_OP_deref */ \
86 .byte 0x12; /* DW_OP_dup */ \
87 .byte 0x23; /* DW_OP_plus_uconst */ \
88 .uleb128 33*RSIZE; /* msr offset */ \
89 .byte 0x06; /* DW_OP_deref */ \
90 .byte 0x0c; .long 1 << 25; /* DW_OP_const4u */ \
91 .byte 0x1a; /* DW_OP_and */ \
92 .byte 0x12; /* DW_OP_dup, ret 0 if bra taken */ \
93 .byte 0x30; /* DW_OP_lit0 */ \
94 .byte 0x29; /* DW_OP_eq */ \
95 .byte 0x28; .short 0x7fff; /* DW_OP_bra to end */ \
96 .byte 0x13; /* DW_OP_drop, pop the 0 */ \
97 .byte 0x23; .uleb128 VREGS; /* DW_OP_plus_uconst */ \
98 .byte 0x22; /* DW_OP_plus */ \
99 .byte 0x2f; .short 0x7fff; /* DW_OP_skip to end */ \
1009:
101
102/* If msr bit 1<<25 is set, then VMX register REGNO is at offset REGNO*16
103 of the VMX reg struct. REGNO is 1 thru 31. */
104#define vsave_msr1(regno) \
105 .byte 0x10; /* DW_CFA_expression */ \
106 .uleb128 regno + 77; /* regno */ \
107 .uleb128 9f - 1f; /* length */ \
1081: \
109 .byte 0x30 + regno; /* DW_OP_lit n */ \
110 .byte 0x2f; .short 2b - 9f; /* DW_OP_skip */ \
1119:
112
113/* If msr bit 1<<25 is set, then VMX register REGNO is at offset OFS of
114 the VMX save block. */
115#define vsave_msr2(regno, ofs) \
116 .byte 0x10; /* DW_CFA_expression */ \
117 .uleb128 regno + 77; /* regno */ \
118 .uleb128 9f - 1f; /* length */ \
1191: \
120 .byte 0x0a; .short ofs; /* DW_OP_const2u */ \
121 .byte 0x2f; .short 3b - 9f; /* DW_OP_skip */ \
1229:
123
124/* VMX register REGNO is at offset OFS of the VMX save area. */
125#define vsave(regno, ofs) \
126 .byte 0x10; /* DW_CFA_expression */ \
127 .uleb128 regno + 77; /* regno */ \
128 .uleb128 9f - 1f; /* length */ \
1291: \
130 .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \
131 .byte 0x06; /* DW_OP_deref */ \
132 .byte 0x23; .uleb128 VREGS; /* DW_OP_plus_uconst */ \
133 .byte 0x23; .uleb128 ofs; /* DW_OP_plus_uconst */ \
1349:
135
136/* This is where the pt_regs pointer can be found on the stack. */
137#define PTREGS 64+28
138
139/* Size of regs. */
140#define RSIZE 4
141
142/* This is the offset of the VMX regs. */
143#define VREGS 48*RSIZE+34*8
144
145/* Describe where general purpose regs are saved. */
146#define EH_FRAME_GEN \
147 cfa_save; \
148 rsave ( 0, 0*RSIZE); \
149 rsave ( 2, 2*RSIZE); \
150 rsave ( 3, 3*RSIZE); \
151 rsave ( 4, 4*RSIZE); \
152 rsave ( 5, 5*RSIZE); \
153 rsave ( 6, 6*RSIZE); \
154 rsave ( 7, 7*RSIZE); \
155 rsave ( 8, 8*RSIZE); \
156 rsave ( 9, 9*RSIZE); \
157 rsave (10, 10*RSIZE); \
158 rsave (11, 11*RSIZE); \
159 rsave (12, 12*RSIZE); \
160 rsave (13, 13*RSIZE); \
161 rsave (14, 14*RSIZE); \
162 rsave (15, 15*RSIZE); \
163 rsave (16, 16*RSIZE); \
164 rsave (17, 17*RSIZE); \
165 rsave (18, 18*RSIZE); \
166 rsave (19, 19*RSIZE); \
167 rsave (20, 20*RSIZE); \
168 rsave (21, 21*RSIZE); \
169 rsave (22, 22*RSIZE); \
170 rsave (23, 23*RSIZE); \
171 rsave (24, 24*RSIZE); \
172 rsave (25, 25*RSIZE); \
173 rsave (26, 26*RSIZE); \
174 rsave (27, 27*RSIZE); \
175 rsave (28, 28*RSIZE); \
176 rsave (29, 29*RSIZE); \
177 rsave (30, 30*RSIZE); \
178 rsave (31, 31*RSIZE); \
179 rsave (67, 32*RSIZE); /* ap, used as temp for nip */ \
180 rsave (65, 36*RSIZE); /* lr */ \
181 rsave (70, 38*RSIZE) /* cr */
182
183/* Describe where the FP regs are saved. */
184#define EH_FRAME_FP \
185 rsave (32, 48*RSIZE + 0*8); \
186 rsave (33, 48*RSIZE + 1*8); \
187 rsave (34, 48*RSIZE + 2*8); \
188 rsave (35, 48*RSIZE + 3*8); \
189 rsave (36, 48*RSIZE + 4*8); \
190 rsave (37, 48*RSIZE + 5*8); \
191 rsave (38, 48*RSIZE + 6*8); \
192 rsave (39, 48*RSIZE + 7*8); \
193 rsave (40, 48*RSIZE + 8*8); \
194 rsave (41, 48*RSIZE + 9*8); \
195 rsave (42, 48*RSIZE + 10*8); \
196 rsave (43, 48*RSIZE + 11*8); \
197 rsave (44, 48*RSIZE + 12*8); \
198 rsave (45, 48*RSIZE + 13*8); \
199 rsave (46, 48*RSIZE + 14*8); \
200 rsave (47, 48*RSIZE + 15*8); \
201 rsave (48, 48*RSIZE + 16*8); \
202 rsave (49, 48*RSIZE + 17*8); \
203 rsave (50, 48*RSIZE + 18*8); \
204 rsave (51, 48*RSIZE + 19*8); \
205 rsave (52, 48*RSIZE + 20*8); \
206 rsave (53, 48*RSIZE + 21*8); \
207 rsave (54, 48*RSIZE + 22*8); \
208 rsave (55, 48*RSIZE + 23*8); \
209 rsave (56, 48*RSIZE + 24*8); \
210 rsave (57, 48*RSIZE + 25*8); \
211 rsave (58, 48*RSIZE + 26*8); \
212 rsave (59, 48*RSIZE + 27*8); \
213 rsave (60, 48*RSIZE + 28*8); \
214 rsave (61, 48*RSIZE + 29*8); \
215 rsave (62, 48*RSIZE + 30*8); \
216 rsave (63, 48*RSIZE + 31*8)
217
218/* Describe where the VMX regs are saved. */
219#ifdef CONFIG_ALTIVEC
220#define EH_FRAME_VMX \
221 vsave_msr0 ( 0); \
222 vsave_msr1 ( 1); \
223 vsave_msr1 ( 2); \
224 vsave_msr1 ( 3); \
225 vsave_msr1 ( 4); \
226 vsave_msr1 ( 5); \
227 vsave_msr1 ( 6); \
228 vsave_msr1 ( 7); \
229 vsave_msr1 ( 8); \
230 vsave_msr1 ( 9); \
231 vsave_msr1 (10); \
232 vsave_msr1 (11); \
233 vsave_msr1 (12); \
234 vsave_msr1 (13); \
235 vsave_msr1 (14); \
236 vsave_msr1 (15); \
237 vsave_msr1 (16); \
238 vsave_msr1 (17); \
239 vsave_msr1 (18); \
240 vsave_msr1 (19); \
241 vsave_msr1 (20); \
242 vsave_msr1 (21); \
243 vsave_msr1 (22); \
244 vsave_msr1 (23); \
245 vsave_msr1 (24); \
246 vsave_msr1 (25); \
247 vsave_msr1 (26); \
248 vsave_msr1 (27); \
249 vsave_msr1 (28); \
250 vsave_msr1 (29); \
251 vsave_msr1 (30); \
252 vsave_msr1 (31); \
253 vsave_msr2 (33, 32*16+12); \
254 vsave (32, 32*16)
255#else
256#define EH_FRAME_VMX
257#endif
258
259.Lcie:
260 .long .Lcie_end - .Lcie_start
261.Lcie_start:
262 .long 0 /* CIE ID */
263 .byte 1 /* Version number */
264 .string "zR" /* NUL-terminated augmentation string */
265 .uleb128 4 /* Code alignment factor */
266 .sleb128 -4 /* Data alignment factor */
267 .byte 67 /* Return address register column, ap */
268 .uleb128 1 /* Augmentation value length */
269 .byte 0x1b /* DW_EH_PE_pcrel | DW_EH_PE_sdata4. */
270 .byte 0x0c,1,0 /* DW_CFA_def_cfa: r1 ofs 0 */
271 .balign 4
272.Lcie_end:
273
274 .long .Lfde0_end - .Lfde0_start
275.Lfde0_start:
276 .long .Lfde0_start - .Lcie /* CIE pointer. */
277 .long .Lsig_start - . /* PC start, length */
278 .long .Lsig_end - .Lsig_start
279 .uleb128 0 /* Augmentation */
280 EH_FRAME_GEN
281 EH_FRAME_FP
282 EH_FRAME_VMX
283 .balign 4
284.Lfde0_end:
285
286/* We have a different stack layout for rt_sigreturn. */
287#undef PTREGS
288#define PTREGS 64+16+128+20+28
289
290 .long .Lfde1_end - .Lfde1_start
291.Lfde1_start:
292 .long .Lfde1_start - .Lcie /* CIE pointer. */
293 .long .Lsigrt_start - . /* PC start, length */
294 .long .Lsigrt_end - .Lsigrt_start
295 .uleb128 0 /* Augmentation */
296 EH_FRAME_GEN
297 EH_FRAME_FP
298 EH_FRAME_VMX
299 .balign 4
300.Lfde1_end:
diff --git a/arch/powerpc/kernel/vdso32/vdso32.lds.S b/arch/powerpc/kernel/vdso32/vdso32.lds.S
new file mode 100644
index 000000000000..f4bad720cb0a
--- /dev/null
+++ b/arch/powerpc/kernel/vdso32/vdso32.lds.S
@@ -0,0 +1,117 @@
1
2/*
3 * This is the infamous ld script for the 32 bits vdso
4 * library
5 */
6#include <asm/vdso.h>
7
8/* Default link addresses for the vDSOs */
9OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc")
10OUTPUT_ARCH(powerpc:common)
11ENTRY(_start)
12
13SECTIONS
14{
15 . = VDSO32_LBASE + SIZEOF_HEADERS;
16 .hash : { *(.hash) } :text
17 .dynsym : { *(.dynsym) }
18 .dynstr : { *(.dynstr) }
19 .gnu.version : { *(.gnu.version) }
20 .gnu.version_d : { *(.gnu.version_d) }
21 .gnu.version_r : { *(.gnu.version_r) }
22
23 .note : { *(.note.*) } :text :note
24
25 . = ALIGN (16);
26 .text :
27 {
28 *(.text .stub .text.* .gnu.linkonce.t.*)
29 }
30 PROVIDE (__etext = .);
31 PROVIDE (_etext = .);
32 PROVIDE (etext = .);
33
34 /* Other stuff is appended to the text segment: */
35 .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
36 .rodata1 : { *(.rodata1) }
37
38 .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
39 .eh_frame : { KEEP (*(.eh_frame)) } :text
40 .gcc_except_table : { *(.gcc_except_table) }
41 .fixup : { *(.fixup) }
42
43 .dynamic : { *(.dynamic) } :text :dynamic
44 .got : { *(.got) }
45 .plt : { *(.plt) }
46
47 _end = .;
48 __end = .;
49 PROVIDE (end = .);
50
51
52 /* Stabs debugging sections are here too
53 */
54 .stab 0 : { *(.stab) }
55 .stabstr 0 : { *(.stabstr) }
56 .stab.excl 0 : { *(.stab.excl) }
57 .stab.exclstr 0 : { *(.stab.exclstr) }
58 .stab.index 0 : { *(.stab.index) }
59 .stab.indexstr 0 : { *(.stab.indexstr) }
60 .comment 0 : { *(.comment) }
61 .debug 0 : { *(.debug) }
62 .line 0 : { *(.line) }
63
64 .debug_srcinfo 0 : { *(.debug_srcinfo) }
65 .debug_sfnames 0 : { *(.debug_sfnames) }
66
67 .debug_aranges 0 : { *(.debug_aranges) }
68 .debug_pubnames 0 : { *(.debug_pubnames) }
69
70 .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
71 .debug_abbrev 0 : { *(.debug_abbrev) }
72 .debug_line 0 : { *(.debug_line) }
73 .debug_frame 0 : { *(.debug_frame) }
74 .debug_str 0 : { *(.debug_str) }
75 .debug_loc 0 : { *(.debug_loc) }
76 .debug_macinfo 0 : { *(.debug_macinfo) }
77
78 .debug_weaknames 0 : { *(.debug_weaknames) }
79 .debug_funcnames 0 : { *(.debug_funcnames) }
80 .debug_typenames 0 : { *(.debug_typenames) }
81 .debug_varnames 0 : { *(.debug_varnames) }
82
83 /DISCARD/ : { *(.note.GNU-stack) }
84 /DISCARD/ : { *(.data .data.* .gnu.linkonce.d.* .sdata*) }
85 /DISCARD/ : { *(.bss .sbss .dynbss .dynsbss) }
86}
87
88
89PHDRS
90{
91 text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
92 note PT_NOTE FLAGS(4); /* PF_R */
93 dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
94 eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */
95}
96
97
98/*
99 * This controls what symbols we export from the DSO.
100 */
101VERSION
102{
103 VDSO_VERSION_STRING {
104 global:
105 __kernel_datapage_offset; /* Has to be there for the kernel to find */
106 __kernel_get_syscall_map;
107 __kernel_gettimeofday;
108 __kernel_clock_gettime;
109 __kernel_clock_getres;
110 __kernel_get_tbfreq;
111 __kernel_sync_dicache;
112 __kernel_sync_dicache_p5;
113 __kernel_sigtramp32;
114 __kernel_sigtramp_rt32;
115 local: *;
116 };
117}
diff --git a/arch/powerpc/kernel/vdso32/vdso32_wrapper.S b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S
new file mode 100644
index 000000000000..556f0caa5d84
--- /dev/null
+++ b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S
@@ -0,0 +1,13 @@
1#include <linux/init.h>
2#include <asm/page.h>
3
4 .section ".data.page_aligned"
5
6 .globl vdso32_start, vdso32_end
7 .balign PAGE_SIZE
8vdso32_start:
9 .incbin "arch/powerpc/kernel/vdso32/vdso32.so"
10 .balign PAGE_SIZE
11vdso32_end:
12
13 .previous