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