]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ppc/commpage/gettimeofday.s
xnu-792.12.6.tar.gz
[apple/xnu.git] / osfmk / ppc / commpage / gettimeofday.s
CommitLineData
55e303ae 1/*
8ad349bb 2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
55e303ae 3 *
8ad349bb 4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
55e303ae 5 *
8ad349bb
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
55e303ae
A
29 */
30
31#define ASSEMBLER
32#include <sys/appleapiopts.h>
33#include <ppc/asm.h> // EXT, LEXT
34#include <machine/cpu_capabilities.h>
35#include <machine/commpage.h>
36
8ad349bb
A
37#define USEC_PER_SEC 1000000
38
39
55e303ae
A
40/* The red zone is used to move data between GPRs and FPRs: */
41
42#define rzTicks -8 // elapsed ticks since timestamp (double)
43#define rzSeconds -16 // seconds since timestamp (double)
44#define rzUSeconds -24 // useconds since timestamp (double)
45
46
47 .text
48 .align 2
55e303ae
A
49
50
51// *********************************
52// * G E T T I M E O F D A Y _ 3 2 *
53// *********************************
54//
55// This is a subroutine of gettimeofday.c that gets the seconds and microseconds
56// in user mode, usually without having to make a system call. We do not deal with
57// the timezone. The kernel maintains the following values in the comm page:
58//
8ad349bb 59// _COMM_PAGE_TIMESTAMP = a BSD-style pair of uint_32's for seconds and microseconds
55e303ae
A
60//
61// _COMM_PAGE_TIMEBASE = the timebase at which the timestamp was valid
62//
63// _COMM_PAGE_SEC_PER_TICK = multiply timebase ticks by this to get seconds (double)
64//
65// _COMM_PAGE_2_TO_52 = double precision constant 2**52
66//
67// _COMM_PAGE_10_TO_6 = double precision constant 10**6
68//
69// We have to be careful to read these values atomically. The kernel updates them
70// asynchronously to account for drift or time changes (eg, ntp.) We adopt the
71// convention that (timebase==0) means the timestamp is invalid, in which case we
72// return a bad status so our caller can make the system call.
73//
74// r3 = ptr to user's timeval structure (should not be null)
75
91447636 76gettimeofday_32: // int gettimeofday(timeval *tp);
55e303ae
A
770:
78 lwz r5,_COMM_PAGE_TIMEBASE+0(0) // r5,r6 = TBR at timestamp
79 lwz r6,_COMM_PAGE_TIMEBASE+4(0)
8ad349bb
A
80 lwz r7,_COMM_PAGE_TIMESTAMP+0(0) // r7 = timestamp seconds
81 lwz r8,_COMM_PAGE_TIMESTAMP+4(0) // r8 = timestamp microseconds
55e303ae
A
82 lfd f1,_COMM_PAGE_SEC_PER_TICK(0)
831:
84 mftbu r10 // r10,r11 = current timebase
85 mftb r11
86 mftbu r12
87 cmplw r10,r12
88 bne- 1b
89 or. r0,r5,r6 // timebase 0? (ie, is timestamp invalid?)
90
91 sync // create a barrier (patched to NOP if UP)
92
93 lwz r0,_COMM_PAGE_TIMEBASE+0(0) // then load data a 2nd time
94 lwz r12,_COMM_PAGE_TIMEBASE+4(0)
8ad349bb 95 lwz r2,_COMM_PAGE_TIMESTAMP+0(0)
55e303ae
A
96 lwz r9,_COMM_PAGE_TIMESTAMP+4(0)
97 cmplw cr6,r5,r0 // did we read a consistent set?
98 cmplw cr7,r6,r12
99 beq- 3f // timestamp is disabled so return bad status
8ad349bb 100 cmplw cr1,r2,r7
55e303ae
A
101 cmplw cr5,r9,r8
102 crand cr0_eq,cr6_eq,cr7_eq
8ad349bb
A
103 crand cr1_eq,cr1_eq,cr5_eq
104 crand cr0_eq,cr0_eq,cr1_eq
55e303ae
A
105 bne- 0b // loop until we have a consistent set of data
106
107 subfc r11,r6,r11 // compute ticks since timestamp
108 lwz r9,_COMM_PAGE_2_TO_52(0) // get exponent for (2**52)
109 subfe r10,r5,r10 // complete 64-bit subtract
8ad349bb 110 lfd f2,_COMM_PAGE_2_TO_52(0) // f3 <- (2**52)
55e303ae
A
111 srwi. r0,r10,2 // if more than 2**34 ticks have elapsed...
112 stw r11,rzTicks+4(r1) // store elapsed ticks into red zone
113 or r10,r10,r9 // convert long-long in (r10,r11) into double
114 bne- 3f // ...call kernel to reprime timestamp
115
116 stw r10,rzTicks(r1) // complete double
8ad349bb
A
117 lis r12,hi16(USEC_PER_SEC)
118 ori r12,r12,lo16(USEC_PER_SEC)
119
55e303ae
A
120 lfd f3,rzTicks(r1) // get elapsed ticks since timestamp + 2**52
121 fsub f4,f3,f2 // subtract 2**52 and normalize
122 fmul f5,f4,f1 // f5 <- elapsed seconds since timestamp
123 lfd f3,_COMM_PAGE_10_TO_6(0) // get 10**6
124 fctiwz f6,f5 // convert to integer
125 stfd f6,rzSeconds(r1) // store integer seconds into red zone
126 stw r9,rzSeconds(r1) // prepare to reload as floating pt
127 lfd f6,rzSeconds(r1) // get seconds + 2**52
128 fsub f6,f6,f2 // f6 <- integral seconds
129 fsub f6,f5,f6 // f6 <- fractional part of elapsed seconds
130 fmul f6,f6,f3 // f6 <- fractional elapsed useconds
131 fctiwz f6,f6 // convert useconds to integer
132 stfd f6,rzUSeconds(r1) // store useconds into red zone
133
134 lwz r5,rzSeconds+4(r1) // r5 <- seconds since timestamp
8ad349bb
A
135 lwz r6,rzUSeconds+4(r1) // r6 <- useconds since timestamp
136 add r7,r7,r5 // add elapsed seconds to timestamp seconds
137 add r8,r8,r6 // ditto useconds
55e303ae 138
8ad349bb
A
139 cmplw r8,r12 // r8 >= USEC_PER_SEC ?
140 blt 2f // no
141 addi r7,r7,1 // add 1 to secs
142 sub r8,r8,r12 // subtract USEC_PER_SEC from usecs
1432:
144 stw r7,0(r3) // store secs//usecs into user's timeval
145 stw r8,4(r3)
55e303ae
A
146 li r3,0 // return success
147 blr
1483: // too long since last timestamp or this code is disabled
149 li r3,1 // return bad status so our caller will make syscall
150 blr
151
91447636 152 COMMPAGE_DESCRIPTOR(gettimeofday_32,_COMM_PAGE_GETTIMEOFDAY,0,k64Bit,kCommPageSYNC+kCommPage32)
55e303ae
A
153
154
91447636
A
155// ***************************************
156// * G E T T I M E O F D A Y _ G 5 _ 3 2 *
157// ***************************************
158//
159// This routine is called in 32-bit mode on 64-bit processors. A timeval is a struct of
8ad349bb 160// a long seconds and int useconds, so it's size depends on mode.
55e303ae 161
91447636 162gettimeofday_g5_32: // int gettimeofday(timeval *tp);
55e303ae
A
1630:
164 ld r6,_COMM_PAGE_TIMEBASE(0) // r6 = TBR at timestamp
8ad349bb 165 ld r8,_COMM_PAGE_TIMESTAMP(0) // r8 = timestamp (seconds,useconds)
55e303ae
A
166 lfd f1,_COMM_PAGE_SEC_PER_TICK(0)
167 mftb r10 // r10 = get current timebase
168 lwsync // create a barrier if MP (patched to NOP if UP)
169 ld r11,_COMM_PAGE_TIMEBASE(0) // then get data a 2nd time
170 ld r12,_COMM_PAGE_TIMESTAMP(0)
171 cmpdi cr1,r6,0 // is the timestamp disabled?
172 cmpld cr6,r6,r11 // did we read a consistent set?
173 cmpld cr7,r8,r12
174 beq-- cr1,3f // exit if timestamp disabled
175 crand cr6_eq,cr7_eq,cr6_eq
176 sub r11,r10,r6 // compute elapsed ticks from timestamp
177 bne-- cr6,0b // loop until we have a consistent set of data
178
179 srdi. r0,r11,35 // has it been more than 2**35 ticks since last timestamp?
180 std r11,rzTicks(r1) // put ticks in redzone where we can "lfd" it
181 bne-- 3f // timestamp too old, so reprime
182
183 lfd f3,rzTicks(r1) // get elapsed ticks since timestamp (fixed pt)
184 fcfid f4,f3 // float the tick count
185 fmul f5,f4,f1 // f5 <- elapsed seconds since timestamp
186 lfd f3,_COMM_PAGE_10_TO_6(0) // get 10**6
187 fctidz f6,f5 // convert integer seconds to fixed pt
188 stfd f6,rzSeconds(r1) // save fixed pt integer seconds in red zone
189 fcfid f6,f6 // float the integer seconds
190 fsub f6,f5,f6 // f6 <- fractional part of elapsed seconds
191 fmul f6,f6,f3 // f6 <- fractional elapsed useconds
192 fctidz f6,f6 // convert useconds to fixed pt integer
193 stfd f6,rzUSeconds(r1) // store useconds into red zone
194
8ad349bb
A
195 lis r12,hi16(USEC_PER_SEC) // r12 <- 10**6
196 srdi r7,r8,32 // extract seconds from doubleword timestamp
55e303ae 197 lwz r5,rzSeconds+4(r1) // r5 <- seconds since timestamp
8ad349bb
A
198 ori r12,r12,lo16(USEC_PER_SEC)
199 lwz r6,rzUSeconds+4(r1) // r6 <- useconds since timestamp
200 add r7,r7,r5 // add elapsed seconds to timestamp seconds
201 add r8,r8,r6 // ditto useconds
55e303ae 202
8ad349bb
A
203 cmplw r8,r12 // r8 >= USEC_PER_SEC ?
204 blt 2f // no
205 addi r7,r7,1 // add 1 to secs
206 sub r8,r8,r12 // subtract USEC_PER_SEC from usecs
2072:
208 stw r7,0(r3) // store secs//usecs into user's timeval
209 stw r8,4(r3)
55e303ae
A
210 li r3,0 // return success
211 blr
2123: // too long since last timestamp or this code is disabled
213 li r3,1 // return bad status so our caller will make syscall
214 blr
215
91447636
A
216 COMMPAGE_DESCRIPTOR(gettimeofday_g5_32,_COMM_PAGE_GETTIMEOFDAY,k64Bit,0,kCommPageSYNC+kCommPage32)
217
218
219// ***************************************
220// * G E T T I M E O F D A Y _ G 5 _ 6 4 *
221// ***************************************
222//
223// This routine is called in 64-bit mode on 64-bit processors. A timeval is a struct of
8ad349bb 224// a long seconds and int useconds, so it's size depends on mode.
91447636
A
225
226gettimeofday_g5_64: // int gettimeofday(timeval *tp);
2270:
228 ld r6,_COMM_PAGE_TIMEBASE(0) // r6 = TBR at timestamp
8ad349bb 229 ld r8,_COMM_PAGE_TIMESTAMP(0) // r8 = timestamp (seconds,useconds)
91447636
A
230 lfd f1,_COMM_PAGE_SEC_PER_TICK(0)
231 mftb r10 // r10 = get current timebase
232 lwsync // create a barrier if MP (patched to NOP if UP)
233 ld r11,_COMM_PAGE_TIMEBASE(0) // then get data a 2nd time
234 ld r12,_COMM_PAGE_TIMESTAMP(0)
235 cmpdi cr1,r6,0 // is the timestamp disabled?
236 cmpld cr6,r6,r11 // did we read a consistent set?
237 cmpld cr7,r8,r12
238 beq-- cr1,3f // exit if timestamp disabled
239 crand cr6_eq,cr7_eq,cr6_eq
240 sub r11,r10,r6 // compute elapsed ticks from timestamp
241 bne-- cr6,0b // loop until we have a consistent set of data
242
243 srdi. r0,r11,35 // has it been more than 2**35 ticks since last timestamp?
244 std r11,rzTicks(r1) // put ticks in redzone where we can "lfd" it
245 bne-- 3f // timestamp too old, so reprime
246
247 lfd f3,rzTicks(r1) // get elapsed ticks since timestamp (fixed pt)
248 fcfid f4,f3 // float the tick count
249 fmul f5,f4,f1 // f5 <- elapsed seconds since timestamp
250 lfd f3,_COMM_PAGE_10_TO_6(0) // get 10**6
251 fctidz f6,f5 // convert integer seconds to fixed pt
252 stfd f6,rzSeconds(r1) // save fixed pt integer seconds in red zone
253 fcfid f6,f6 // float the integer seconds
254 fsub f6,f5,f6 // f6 <- fractional part of elapsed seconds
255 fmul f6,f6,f3 // f6 <- fractional elapsed useconds
256 fctidz f6,f6 // convert useconds to fixed pt integer
257 stfd f6,rzUSeconds(r1) // store useconds into red zone
258
8ad349bb
A
259 lis r12,hi16(USEC_PER_SEC) // r12 <- 10**6
260 srdi r7,r8,32 // extract seconds from doubleword timestamp
91447636 261 lwz r5,rzSeconds+4(r1) // r5 <- seconds since timestamp
8ad349bb
A
262 ori r12,r12,lo16(USEC_PER_SEC)
263 lwz r6,rzUSeconds+4(r1) // r6 <- useconds since timestamp
264 add r7,r7,r5 // add elapsed seconds to timestamp seconds
265 add r8,r8,r6 // ditto useconds
91447636 266
8ad349bb
A
267 cmplw r8,r12 // r8 >= USEC_PER_SEC ?
268 blt 2f // no
269 addi r7,r7,1 // add 1 to secs
270 sub r8,r8,r12 // subtract USEC_PER_SEC from usecs
2712:
272 std r7,0(r3) // store secs//usecs into user's timeval
273 stw r8,8(r3)
91447636
A
274 li r3,0 // return success
275 blr
2763: // too long since last timestamp or this code is disabled
277 li r3,1 // return bad status so our caller will make syscall
278 blr
279
280 COMMPAGE_DESCRIPTOR(gettimeofday_g5_64,_COMM_PAGE_GETTIMEOFDAY,k64Bit,0,kCommPageSYNC+kCommPage64)
55e303ae
A
281
282