blob: 05909f75430707677ace1f5237245f1fb27442a8 [file] [log] [blame]
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +11001/*
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 */
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +110013#include <asm/processor.h>
14#include <asm/ppc_asm.h>
15#include <asm/vdso.h>
16#include <asm/asm-offsets.h>
17#include <asm/unistd.h>
18
19 .text
20/*
21 * Exact prototype of gettimeofday
22 *
23 * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz);
24 *
25 */
26V_FUNCTION_BEGIN(__kernel_gettimeofday)
27 .cfi_startproc
28 mflr r12
29 .cfi_register lr,r12
30
31 mr r10,r3 /* r10 saves tv */
32 mr r11,r4 /* r11 saves tz */
33 bl __get_datapage@local /* get data page */
34 mr r9, r3 /* datapage ptr in r9 */
35 bl __do_get_xsec@local /* get xsec from tb & kernel */
36 bne- 2f /* out of line -> do syscall */
37
38 /* seconds are xsec >> 20 */
39 rlwinm r5,r4,12,20,31
40 rlwimi r5,r3,12,0,19
41 stw r5,TVAL32_TV_SEC(r10)
42
43 /* get remaining xsec and convert to usec. we scale
44 * up remaining xsec by 12 bits and get the top 32 bits
45 * of the multiplication
46 */
47 rlwinm r5,r4,12,0,19
48 lis r6,1000000@h
49 ori r6,r6,1000000@l
50 mulhwu r5,r5,r6
51 stw r5,TVAL32_TV_USEC(r10)
52
53 cmpli cr0,r11,0 /* check if tz is NULL */
54 beq 1f
55 lwz r4,CFG_TZ_MINUTEWEST(r9)/* fill tz */
56 lwz r5,CFG_TZ_DSTTIME(r9)
57 stw r4,TZONE_TZ_MINWEST(r11)
58 stw r5,TZONE_TZ_DSTTIME(r11)
59
601: mtlr r12
Benjamin Herrenschmidt5d66da32005-11-16 13:54:32 +110061 crclr cr0*4+so
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +110062 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
Benjamin Herrenschmidt0c37ec22005-11-14 14:55:58 +110086 cror cr0*4+eq,cr0*4+eq,cr1*4+eq
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +110087 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 */
Benjamin Herrenschmidt0c37ec22005-11-14 14:55:58 +110094 mr r9,r3 /* datapage ptr in r9 */
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +110095 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
Benjamin Herrenschmidt5d66da32005-11-16 13:54:32 +1100120 crclr cr0*4+so
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +1100121 li r3,0
122 blr
123
124 /*
125 * CLOCK_MONOTONIC
126 */
127
12850: bl __do_get_xsec@local /* get xsec from tb & kernel */
129 bne- 98f /* out of line -> do syscall */
130
131 /* seconds are xsec >> 20 */
132 rlwinm r6,r4,12,20,31
133 rlwimi r6,r3,12,0,19
134
135 /* get remaining xsec and convert to nsec. we scale
136 * up remaining xsec by 12 bits and get the top 32 bits
137 * of the multiplication, then we multiply by 1000
138 */
139 rlwinm r7,r4,12,0,19
140 lis r5,1000000@h
141 ori r5,r5,1000000@l
142 mulhwu r7,r7,r5
143 mulli r7,r7,1000
144
145 /* now we must fixup using wall to monotonic. We need to snapshot
146 * that value and do the counter trick again. Fortunately, we still
147 * have the counter value in r8 that was returned by __do_get_xsec.
148 * At this point, r6,r7 contain our sec/nsec values, r3,r4 and r5
149 * can be used
150 */
151
152 lwz r3,WTOM_CLOCK_SEC(r9)
153 lwz r4,WTOM_CLOCK_NSEC(r9)
154
155 /* We now have our result in r3,r4. We create a fake dependency
156 * on that result and re-check the counter
157 */
158 or r5,r4,r3
159 xor r0,r5,r5
160 add r9,r9,r0
161#ifdef CONFIG_PPC64
162 lwz r0,(CFG_TB_UPDATE_COUNT+4)(r9)
163#else
164 lwz r0,(CFG_TB_UPDATE_COUNT)(r9)
165#endif
166 cmpl cr0,r8,r0 /* check if updated */
167 bne- 50b
168
169 /* Calculate and store result. Note that this mimmics the C code,
170 * which may cause funny results if nsec goes negative... is that
171 * possible at all ?
172 */
173 add r3,r3,r6
174 add r4,r4,r7
175 lis r5,NSEC_PER_SEC@h
176 ori r5,r5,NSEC_PER_SEC@l
Benjamin Herrenschmidt0c37ec22005-11-14 14:55:58 +1100177 cmpl cr0,r4,r5
178 cmpli cr1,r4,0
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +1100179 blt 1f
180 subf r4,r5,r4
181 addi r3,r3,1
Benjamin Herrenschmidt0c37ec22005-11-14 14:55:58 +11001821: bge cr1,1f
183 addi r3,r3,-1
184 add r4,r4,r5
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +11001851: stw r3,TSPC32_TV_SEC(r11)
186 stw r4,TSPC32_TV_NSEC(r11)
187
188 mtlr r12
Benjamin Herrenschmidt5d66da32005-11-16 13:54:32 +1100189 crclr cr0*4+so
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +1100190 li r3,0
191 blr
192
193 /*
194 * syscall fallback
195 */
19698:
197 mtlr r12
198 mr r3,r10
199 mr r4,r11
20099:
201 li r0,__NR_clock_gettime
202 sc
203 blr
204 .cfi_endproc
205V_FUNCTION_END(__kernel_clock_gettime)
206
207
208/*
209 * Exact prototype of clock_getres()
210 *
211 * int __kernel_clock_getres(clockid_t clock_id, struct timespec *res);
212 *
213 */
214V_FUNCTION_BEGIN(__kernel_clock_getres)
215 .cfi_startproc
216 /* Check for supported clock IDs */
217 cmpwi cr0,r3,CLOCK_REALTIME
218 cmpwi cr1,r3,CLOCK_MONOTONIC
Benjamin Herrenschmidt0c37ec22005-11-14 14:55:58 +1100219 cror cr0*4+eq,cr0*4+eq,cr1*4+eq
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +1100220 bne cr0,99f
221
222 li r3,0
223 cmpli cr0,r4,0
Benjamin Herrenschmidt5d66da32005-11-16 13:54:32 +1100224 crclr cr0*4+so
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +1100225 beqlr
226 lis r5,CLOCK_REALTIME_RES@h
227 ori r5,r5,CLOCK_REALTIME_RES@l
228 stw r3,TSPC32_TV_SEC(r4)
229 stw r5,TSPC32_TV_NSEC(r4)
230 blr
231
232 /*
233 * syscall fallback
234 */
23599:
236 li r0,__NR_clock_getres
237 sc
238 blr
239 .cfi_endproc
240V_FUNCTION_END(__kernel_clock_getres)
241
242
243/*
244 * This is the core of gettimeofday() & friends, it returns the xsec
245 * value in r3 & r4 and expects the datapage ptr (non clobbered)
246 * in r9. clobbers r0,r4,r5,r6,r7,r8.
247 * When returning, r8 contains the counter value that can be reused
248 * by the monotonic clock implementation
249 */
250__do_get_xsec:
251 .cfi_startproc
252 /* Check for update count & load values. We use the low
253 * order 32 bits of the update count
254 */
255#ifdef CONFIG_PPC64
2561: lwz r8,(CFG_TB_UPDATE_COUNT+4)(r9)
257#else
2581: lwz r8,(CFG_TB_UPDATE_COUNT)(r9)
259#endif
260 andi. r0,r8,1 /* pending update ? loop */
261 bne- 1b
262 xor r0,r8,r8 /* create dependency */
263 add r9,r9,r0
264
265 /* Load orig stamp (offset to TB) */
266 lwz r5,CFG_TB_ORIG_STAMP(r9)
267 lwz r6,(CFG_TB_ORIG_STAMP+4)(r9)
268
269 /* Get a stable TB value */
2702: mftbu r3
271 mftbl r4
272 mftbu r0
273 cmpl cr0,r3,r0
274 bne- 2b
275
276 /* Substract tb orig stamp. If the high part is non-zero, we jump to
277 * the slow path which call the syscall.
278 * If it's ok, then we have our 32 bits tb_ticks value in r7
279 */
280 subfc r7,r6,r4
281 subfe. r0,r5,r3
282 bne- 3f
283
284 /* Load scale factor & do multiplication */
285 lwz r5,CFG_TB_TO_XS(r9) /* load values */
286 lwz r6,(CFG_TB_TO_XS+4)(r9)
287 mulhwu r4,r7,r5
288 mulhwu r6,r7,r6
289 mullw r0,r7,r5
290 addc r6,r6,r0
291
292 /* At this point, we have the scaled xsec value in r4 + XER:CA
293 * we load & add the stamp since epoch
294 */
295 lwz r5,CFG_STAMP_XSEC(r9)
296 lwz r6,(CFG_STAMP_XSEC+4)(r9)
297 adde r4,r4,r6
298 addze r3,r5
299
300 /* We now have our result in r3,r4. We create a fake dependency
301 * on that result and re-check the counter
302 */
303 or r6,r4,r3
304 xor r0,r6,r6
305 add r9,r9,r0
306#ifdef CONFIG_PPC64
307 lwz r0,(CFG_TB_UPDATE_COUNT+4)(r9)
308#else
309 lwz r0,(CFG_TB_UPDATE_COUNT)(r9)
310#endif
311 cmpl cr0,r8,r0 /* check if updated */
312 bne- 1b
313
314 /* Warning ! The caller expects CR:EQ to be set to indicate a
315 * successful calculation (so it won't fallback to the syscall
316 * method). We have overriden that CR bit in the counter check,
317 * but fortunately, the loop exit condition _is_ CR:EQ set, so
318 * we can exit safely here. If you change this code, be careful
319 * of that side effect.
320 */
3213: blr
322 .cfi_endproc