]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
39236c6e | 2 | * Copyright (c) 2000-2012 Apple Inc. All rights reserved. |
1c79356b | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
0a7de745 | 5 | * |
2d21ac55 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 License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
0a7de745 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
0a7de745 | 17 | * |
2d21ac55 A |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
0a7de745 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
27 | */ |
28 | /* | |
29 | * @OSF_COPYRIGHT@ | |
30 | */ | |
31 | ||
32 | /* | |
33 | * File: i386/rtclock.c | |
34 | * Purpose: Routines for handling the machine dependent | |
91447636 A |
35 | * real-time clock. Historically, this clock is |
36 | * generated by the Intel 8254 Programmable Interval | |
37 | * Timer, but local apic timers are now used for | |
38 | * this purpose with the master time reference being | |
39 | * the cpu clock counted by the timestamp MSR. | |
1c79356b A |
40 | */ |
41 | ||
55e303ae A |
42 | |
43 | #include <mach/mach_types.h> | |
44 | ||
1c79356b | 45 | #include <kern/cpu_data.h> |
91447636 | 46 | #include <kern/cpu_number.h> |
1c79356b | 47 | #include <kern/clock.h> |
55e303ae | 48 | #include <kern/host_notify.h> |
1c79356b A |
49 | #include <kern/macro_help.h> |
50 | #include <kern/misc_protos.h> | |
51 | #include <kern/spl.h> | |
91447636 | 52 | #include <kern/assert.h> |
39236c6e | 53 | #include <kern/timer_queue.h> |
1c79356b A |
54 | #include <mach/vm_prot.h> |
55 | #include <vm/pmap.h> | |
0a7de745 | 56 | #include <vm/vm_kern.h> /* for kernel_map */ |
0c530ab8 | 57 | #include <architecture/i386/pio.h> |
55e303ae | 58 | #include <i386/machine_cpu.h> |
91447636 | 59 | #include <i386/cpuid.h> |
91447636 | 60 | #include <i386/cpu_threads.h> |
b0d623f7 | 61 | #include <i386/mp.h> |
91447636 | 62 | #include <i386/machine_routines.h> |
6d2010ae | 63 | #include <i386/pal_routines.h> |
b0d623f7 A |
64 | #include <i386/proc_reg.h> |
65 | #include <i386/misc_protos.h> | |
55e303ae | 66 | #include <pexpert/pexpert.h> |
91447636 A |
67 | #include <machine/limits.h> |
68 | #include <machine/commpage.h> | |
69 | #include <sys/kdebug.h> | |
0c530ab8 | 70 | #include <i386/tsc.h> |
6d2010ae | 71 | #include <i386/rtclock_protos.h> |
0a7de745 | 72 | #define UI_CPUFREQ_ROUNDING_FACTOR 10000000 |
1c79356b | 73 | |
0a7de745 | 74 | int rtclock_init(void); |
6601e61a | 75 | |
0a7de745 | 76 | uint64_t tsc_rebase_abs_time = 0; |
b0d623f7 | 77 | |
f427ee49 A |
78 | volatile uint64_t gAcpiLastSleepTscBase = 0; |
79 | volatile uint64_t gAcpiLastSleepNanoBase = 0; | |
80 | volatile uint64_t gAcpiLastWakeTscBase = 0; | |
81 | volatile uint64_t gAcpiLastWakeNanoBase = 0; | |
82 | ||
0a7de745 A |
83 | static void rtc_set_timescale(uint64_t cycles); |
84 | static uint64_t rtc_export_speed(uint64_t cycles); | |
8f6c56a5 | 85 | |
060df5ea A |
86 | void |
87 | rtc_timer_start(void) | |
88 | { | |
89 | /* | |
90 | * Force a complete re-evaluation of timer deadlines. | |
91 | */ | |
39236c6e A |
92 | x86_lcpu()->rtcDeadline = EndOfAllTime; |
93 | timer_resync_deadlines(); | |
060df5ea A |
94 | } |
95 | ||
b0d623f7 A |
96 | static inline uint32_t |
97 | _absolutetime_to_microtime(uint64_t abstime, clock_sec_t *secs, clock_usec_t *microsecs) | |
98 | { | |
99 | uint32_t remain; | |
b0d623f7 A |
100 | *secs = abstime / (uint64_t)NSEC_PER_SEC; |
101 | remain = (uint32_t)(abstime % (uint64_t)NSEC_PER_SEC); | |
102 | *microsecs = remain / NSEC_PER_USEC; | |
b0d623f7 A |
103 | return remain; |
104 | } | |
105 | ||
106 | static inline void | |
107 | _absolutetime_to_nanotime(uint64_t abstime, clock_sec_t *secs, clock_usec_t *nanosecs) | |
108 | { | |
b0d623f7 A |
109 | *secs = abstime / (uint64_t)NSEC_PER_SEC; |
110 | *nanosecs = (clock_usec_t)(abstime % (uint64_t)NSEC_PER_SEC); | |
b0d623f7 A |
111 | } |
112 | ||
91447636 A |
113 | /* |
114 | * Nanotime/mach_absolutime_time | |
115 | * ----------------------------- | |
0c530ab8 A |
116 | * The timestamp counter (TSC) - which counts cpu clock cycles and can be read |
117 | * efficiently by the kernel and in userspace - is the reference for all timing. | |
118 | * The cpu clock rate is platform-dependent and may stop or be reset when the | |
119 | * processor is napped/slept. As a result, nanotime is the software abstraction | |
120 | * used to maintain a monotonic clock, adjusted from an outside reference as needed. | |
91447636 A |
121 | * |
122 | * The kernel maintains nanotime information recording: | |
0a7de745 | 123 | * - the ratio of tsc to nanoseconds |
91447636 A |
124 | * with this ratio expressed as a 32-bit scale and shift |
125 | * (power of 2 divider); | |
0c530ab8 | 126 | * - { tsc_base, ns_base } pair of corresponding timestamps. |
6601e61a | 127 | * |
0a7de745 | 128 | * The tuple {tsc_base, ns_base, scale, shift} is exported in the commpage |
0c530ab8 | 129 | * for the userspace nanotime routine to read. |
6601e61a | 130 | * |
0c530ab8 A |
131 | * All of the routines which update the nanotime data are non-reentrant. This must |
132 | * be guaranteed by the caller. | |
91447636 A |
133 | */ |
134 | static inline void | |
6d2010ae | 135 | rtc_nanotime_set_commpage(pal_rtc_nanotime_t *rntp) |
91447636 | 136 | { |
0c530ab8 A |
137 | commpage_set_nanotime(rntp->tsc_base, rntp->ns_base, rntp->scale, rntp->shift); |
138 | } | |
6601e61a | 139 | |
0c530ab8 A |
140 | /* |
141 | * rtc_nanotime_init: | |
142 | * | |
143 | * Intialize the nanotime info from the base time. | |
144 | */ | |
145 | static inline void | |
6d2010ae | 146 | _rtc_nanotime_init(pal_rtc_nanotime_t *rntp, uint64_t base) |
0c530ab8 | 147 | { |
0a7de745 | 148 | uint64_t tsc = rdtsc64(); |
21362eb3 | 149 | |
6d2010ae | 150 | _pal_rtc_nanotime_store(tsc, base, rntp->scale, rntp->shift, rntp); |
91447636 A |
151 | } |
152 | ||
39037602 | 153 | void |
0c530ab8 | 154 | rtc_nanotime_init(uint64_t base) |
91447636 | 155 | { |
f427ee49 A |
156 | gAcpiLastSleepTscBase = pal_rtc_nanotime_info.tsc_base; |
157 | gAcpiLastSleepNanoBase = pal_rtc_nanotime_info.ns_base; | |
158 | ||
6d2010ae | 159 | _rtc_nanotime_init(&pal_rtc_nanotime_info, base); |
f427ee49 A |
160 | |
161 | gAcpiLastWakeTscBase = pal_rtc_nanotime_info.tsc_base; | |
162 | gAcpiLastWakeNanoBase = pal_rtc_nanotime_info.ns_base; | |
163 | ||
6d2010ae | 164 | rtc_nanotime_set_commpage(&pal_rtc_nanotime_info); |
91447636 A |
165 | } |
166 | ||
0c530ab8 A |
167 | /* |
168 | * rtc_nanotime_init_commpage: | |
169 | * | |
170 | * Call back from the commpage initialization to | |
171 | * cause the commpage data to be filled in once the | |
172 | * commpages have been created. | |
173 | */ | |
174 | void | |
175 | rtc_nanotime_init_commpage(void) | |
91447636 | 176 | { |
0a7de745 | 177 | spl_t s = splclock(); |
0c530ab8 | 178 | |
6d2010ae | 179 | rtc_nanotime_set_commpage(&pal_rtc_nanotime_info); |
0c530ab8 | 180 | splx(s); |
91447636 A |
181 | } |
182 | ||
0c530ab8 A |
183 | /* |
184 | * rtc_nanotime_read: | |
185 | * | |
186 | * Returns the current nanotime value, accessable from any | |
187 | * context. | |
188 | */ | |
2d21ac55 | 189 | static inline uint64_t |
91447636 A |
190 | rtc_nanotime_read(void) |
191 | { | |
0a7de745 | 192 | return _rtc_nanotime_read(&pal_rtc_nanotime_info); |
91447636 A |
193 | } |
194 | ||
91447636 | 195 | /* |
0c530ab8 A |
196 | * rtc_clock_napped: |
197 | * | |
4a3eedf9 A |
198 | * Invoked from power management when we exit from a low C-State (>= C4) |
199 | * and the TSC has stopped counting. The nanotime data is updated according | |
200 | * to the provided value which represents the new value for nanotime. | |
91447636 | 201 | */ |
0c530ab8 | 202 | void |
4a3eedf9 | 203 | rtc_clock_napped(uint64_t base, uint64_t tsc_base) |
0c530ab8 | 204 | { |
0a7de745 A |
205 | pal_rtc_nanotime_t *rntp = &pal_rtc_nanotime_info; |
206 | uint64_t oldnsecs; | |
207 | uint64_t newnsecs; | |
208 | uint64_t tsc; | |
2d21ac55 A |
209 | |
210 | assert(!ml_get_interrupts_enabled()); | |
4a3eedf9 | 211 | tsc = rdtsc64(); |
bd504ef0 A |
212 | oldnsecs = rntp->ns_base + _rtc_tsc_to_nanoseconds(tsc - rntp->tsc_base, rntp); |
213 | newnsecs = base + _rtc_tsc_to_nanoseconds(tsc - tsc_base, rntp); | |
0a7de745 | 214 | |
4a3eedf9 A |
215 | /* |
216 | * Only update the base values if time using the new base values | |
217 | * is later than the time using the old base values. | |
218 | */ | |
219 | if (oldnsecs < newnsecs) { | |
0a7de745 A |
220 | _pal_rtc_nanotime_store(tsc_base, base, rntp->scale, rntp->shift, rntp); |
221 | rtc_nanotime_set_commpage(rntp); | |
4a3eedf9 | 222 | } |
0c530ab8 A |
223 | } |
224 | ||
0b4c1975 A |
225 | /* |
226 | * Invoked from power management to correct the SFLM TSC entry drift problem: | |
6d2010ae A |
227 | * a small delta is added to the tsc_base. This is equivalent to nudgin time |
228 | * backwards. We require this to be on the order of a TSC quantum which won't | |
229 | * cause callers of mach_absolute_time() to see time going backwards! | |
0b4c1975 A |
230 | */ |
231 | void | |
232 | rtc_clock_adjust(uint64_t tsc_base_delta) | |
233 | { | |
0a7de745 | 234 | pal_rtc_nanotime_t *rntp = &pal_rtc_nanotime_info; |
0b4c1975 | 235 | |
0a7de745 A |
236 | assert(!ml_get_interrupts_enabled()); |
237 | assert(tsc_base_delta < 100ULL); /* i.e. it's small */ | |
238 | _rtc_nanotime_adjust(tsc_base_delta, rntp); | |
239 | rtc_nanotime_set_commpage(rntp); | |
0b4c1975 A |
240 | } |
241 | ||
1c79356b | 242 | /* |
0c530ab8 A |
243 | * rtc_sleep_wakeup: |
244 | * | |
6d2010ae | 245 | * Invoked from power management when we have awoken from a sleep (S3) |
bd504ef0 A |
246 | * and the TSC has been reset, or from Deep Idle (S0) sleep when the TSC |
247 | * has progressed. The nanotime data is updated based on the passed-in value. | |
0c530ab8 A |
248 | * |
249 | * The caller must guarantee non-reentrancy. | |
91447636 A |
250 | */ |
251 | void | |
0c530ab8 | 252 | rtc_sleep_wakeup( |
0a7de745 | 253 | uint64_t base) |
91447636 | 254 | { |
0a7de745 | 255 | /* Set fixed configuration for lapic timers */ |
fe8ab488 | 256 | rtc_timer->rtc_config(); |
060df5ea | 257 | |
91447636 A |
258 | /* |
259 | * Reset nanotime. | |
260 | * The timestamp counter will have been reset | |
261 | * but nanotime (uptime) marches onward. | |
91447636 | 262 | */ |
0c530ab8 | 263 | rtc_nanotime_init(base); |
91447636 A |
264 | } |
265 | ||
39037602 | 266 | void |
0a7de745 A |
267 | rtc_decrementer_configure(void) |
268 | { | |
39037602 A |
269 | rtc_timer->rtc_config(); |
270 | } | |
fe8ab488 A |
271 | /* |
272 | * rtclock_early_init() is called very early at boot to | |
273 | * establish mach_absolute_time() and set it to zero. | |
274 | */ | |
275 | void | |
276 | rtclock_early_init(void) | |
277 | { | |
278 | assert(tscFreq); | |
279 | rtc_set_timescale(tscFreq); | |
280 | } | |
281 | ||
91447636 A |
282 | /* |
283 | * Initialize the real-time clock device. | |
284 | * In addition, various variables used to support the clock are initialized. | |
1c79356b A |
285 | */ |
286 | int | |
0c530ab8 | 287 | rtclock_init(void) |
1c79356b | 288 | { |
0a7de745 | 289 | uint64_t cycles; |
91447636 | 290 | |
0c530ab8 A |
291 | assert(!ml_get_interrupts_enabled()); |
292 | ||
91447636 | 293 | if (cpu_number() == master_cpu) { |
0c530ab8 | 294 | assert(tscFreq); |
0c530ab8 | 295 | |
91447636 | 296 | /* |
0c530ab8 | 297 | * Adjust and set the exported cpu speed. |
91447636 | 298 | */ |
0c530ab8 | 299 | cycles = rtc_export_speed(tscFreq); |
91447636 A |
300 | |
301 | /* | |
302 | * Set min/max to actual. | |
303 | * ACPI may update these later if speed-stepping is detected. | |
304 | */ | |
0c530ab8 A |
305 | gPEClockFrequencyInfo.cpu_frequency_min_hz = cycles; |
306 | gPEClockFrequencyInfo.cpu_frequency_max_hz = cycles; | |
91447636 | 307 | |
060df5ea | 308 | rtc_timer_init(); |
91447636 | 309 | clock_timebase_init(); |
0c530ab8 | 310 | ml_init_lock_timeout(); |
bd504ef0 | 311 | ml_init_delay_spin_threshold(10); |
1c79356b | 312 | } |
91447636 | 313 | |
0a7de745 | 314 | /* Set fixed configuration for lapic timers */ |
fe8ab488 | 315 | rtc_timer->rtc_config(); |
060df5ea | 316 | rtc_timer_start(); |
91447636 | 317 | |
0a7de745 | 318 | return 1; |
1c79356b A |
319 | } |
320 | ||
0a7de745 | 321 | // utility routine |
0c530ab8 | 322 | // Code to calculate how many processor cycles are in a second... |
1c79356b | 323 | |
0c530ab8 A |
324 | static void |
325 | rtc_set_timescale(uint64_t cycles) | |
1c79356b | 326 | { |
0a7de745 | 327 | pal_rtc_nanotime_t *rntp = &pal_rtc_nanotime_info; |
bd504ef0 | 328 | uint32_t shift = 0; |
0a7de745 | 329 | |
bd504ef0 | 330 | /* the "scale" factor will overflow unless cycles>SLOW_TSC_THRESHOLD */ |
0a7de745 A |
331 | |
332 | while (cycles <= SLOW_TSC_THRESHOLD) { | |
bd504ef0 A |
333 | shift++; |
334 | cycles <<= 1; | |
335 | } | |
0a7de745 | 336 | |
b0d623f7 | 337 | rntp->scale = (uint32_t)(((uint64_t)NSEC_PER_SEC << 32) / cycles); |
2d21ac55 | 338 | |
bd504ef0 | 339 | rntp->shift = shift; |
1c79356b | 340 | |
15129b1c A |
341 | /* |
342 | * On some platforms, the TSC is not reset at warm boot. But the | |
343 | * rebase time must be relative to the current boot so we can't use | |
344 | * mach_absolute_time(). Instead, we convert the TSC delta since boot | |
345 | * to nanoseconds. | |
346 | */ | |
0a7de745 | 347 | if (tsc_rebase_abs_time == 0) { |
15129b1c | 348 | tsc_rebase_abs_time = _rtc_tsc_to_nanoseconds( |
0a7de745 A |
349 | rdtsc64() - tsc_at_boot, rntp); |
350 | } | |
b0d623f7 | 351 | |
0c530ab8 | 352 | rtc_nanotime_init(0); |
1c79356b A |
353 | } |
354 | ||
91447636 | 355 | static uint64_t |
0c530ab8 | 356 | rtc_export_speed(uint64_t cyc_per_sec) |
9bccf70c | 357 | { |
0a7de745 A |
358 | pal_rtc_nanotime_t *rntp = &pal_rtc_nanotime_info; |
359 | uint64_t cycles; | |
1c79356b | 360 | |
0a7de745 | 361 | if (rntp->shift != 0) { |
fe8ab488 | 362 | printf("Slow TSC, rtc_nanotime.shift == %d\n", rntp->shift); |
0a7de745 A |
363 | } |
364 | ||
0c530ab8 | 365 | /* Round: */ |
0a7de745 A |
366 | cycles = ((cyc_per_sec + (UI_CPUFREQ_ROUNDING_FACTOR / 2)) |
367 | / UI_CPUFREQ_ROUNDING_FACTOR) | |
368 | * UI_CPUFREQ_ROUNDING_FACTOR; | |
9bccf70c | 369 | |
91447636 A |
370 | /* |
371 | * Set current measured speed. | |
372 | */ | |
0a7de745 A |
373 | if (cycles >= 0x100000000ULL) { |
374 | gPEClockFrequencyInfo.cpu_clock_rate_hz = 0xFFFFFFFFUL; | |
375 | } else { | |
376 | gPEClockFrequencyInfo.cpu_clock_rate_hz = (unsigned long)cycles; | |
377 | } | |
378 | gPEClockFrequencyInfo.cpu_frequency_hz = cycles; | |
55e303ae | 379 | |
0c530ab8 | 380 | kprintf("[RTCLOCK] frequency %llu (%llu)\n", cycles, cyc_per_sec); |
0a7de745 | 381 | return cycles; |
9bccf70c | 382 | } |
1c79356b | 383 | |
55e303ae A |
384 | void |
385 | clock_get_system_microtime( | |
0a7de745 A |
386 | clock_sec_t *secs, |
387 | clock_usec_t *microsecs) | |
9bccf70c | 388 | { |
0a7de745 | 389 | uint64_t now = rtc_nanotime_read(); |
6601e61a | 390 | |
b0d623f7 | 391 | _absolutetime_to_microtime(now, secs, microsecs); |
1c79356b A |
392 | } |
393 | ||
55e303ae A |
394 | void |
395 | clock_get_system_nanotime( | |
0a7de745 A |
396 | clock_sec_t *secs, |
397 | clock_nsec_t *nanosecs) | |
55e303ae | 398 | { |
0a7de745 | 399 | uint64_t now = rtc_nanotime_read(); |
8f6c56a5 | 400 | |
b0d623f7 | 401 | _absolutetime_to_nanotime(now, secs, nanosecs); |
6601e61a A |
402 | } |
403 | ||
404 | void | |
5ba3f43e | 405 | clock_gettimeofday_set_commpage(uint64_t abstime, uint64_t sec, uint64_t frac, uint64_t scale, uint64_t tick_per_sec) |
0c530ab8 | 406 | { |
5ba3f43e | 407 | commpage_set_timestamp(abstime, sec, frac, scale, tick_per_sec); |
91447636 A |
408 | } |
409 | ||
1c79356b A |
410 | void |
411 | clock_timebase_info( | |
0a7de745 | 412 | mach_timebase_info_t info) |
1c79356b | 413 | { |
91447636 | 414 | info->numer = info->denom = 1; |
0a7de745 | 415 | } |
1c79356b | 416 | |
1c79356b | 417 | /* |
91447636 | 418 | * Real-time clock device interrupt. |
1c79356b | 419 | */ |
1c79356b | 420 | void |
0c530ab8 | 421 | rtclock_intr( |
0a7de745 | 422 | x86_saved_state_t *tregs) |
1c79356b | 423 | { |
0a7de745 A |
424 | uint64_t rip; |
425 | boolean_t user_mode = FALSE; | |
91447636 A |
426 | |
427 | assert(get_preemption_level() > 0); | |
428 | assert(!ml_get_interrupts_enabled()); | |
429 | ||
0c530ab8 | 430 | if (is_saved_state64(tregs) == TRUE) { |
0a7de745 A |
431 | x86_saved_state64_t *regs; |
432 | ||
0c530ab8 | 433 | regs = saved_state64(tregs); |
5d5c5d0d | 434 | |
0a7de745 | 435 | if (regs->isf.cs & 0x03) { |
b0d623f7 | 436 | user_mode = TRUE; |
0a7de745 | 437 | } |
0c530ab8 A |
438 | rip = regs->isf.rip; |
439 | } else { | |
0a7de745 | 440 | x86_saved_state32_t *regs; |
8ad349bb | 441 | |
0c530ab8 | 442 | regs = saved_state32(tregs); |
4452a7af | 443 | |
0a7de745 A |
444 | if (regs->cs & 0x03) { |
445 | user_mode = TRUE; | |
446 | } | |
0c530ab8 A |
447 | rip = regs->eip; |
448 | } | |
89b3af67 | 449 | |
0c530ab8 | 450 | /* call the generic etimer */ |
39236c6e | 451 | timer_intr(user_mode, rip); |
5d5c5d0d A |
452 | } |
453 | ||
060df5ea | 454 | |
0c530ab8 | 455 | /* |
0a7de745 | 456 | * Request timer pop from the hardware |
0c530ab8 A |
457 | */ |
458 | ||
060df5ea | 459 | uint64_t |
fe8ab488 | 460 | setPop(uint64_t time) |
5d5c5d0d | 461 | { |
0a7de745 A |
462 | uint64_t now; |
463 | uint64_t pop; | |
060df5ea A |
464 | |
465 | /* 0 and EndOfAllTime are special-cases for "clear the timer" */ | |
0a7de745 | 466 | if (time == 0 || time == EndOfAllTime) { |
060df5ea A |
467 | time = EndOfAllTime; |
468 | now = 0; | |
fe8ab488 | 469 | pop = rtc_timer->rtc_set(0, 0); |
060df5ea | 470 | } else { |
0a7de745 | 471 | now = rtc_nanotime_read(); /* The time in nanoseconds */ |
fe8ab488 | 472 | pop = rtc_timer->rtc_set(time, now); |
060df5ea | 473 | } |
4452a7af | 474 | |
6d2010ae | 475 | /* Record requested and actual deadlines set */ |
060df5ea | 476 | x86_lcpu()->rtcDeadline = time; |
0a7de745 | 477 | x86_lcpu()->rtcPop = pop; |
4452a7af | 478 | |
060df5ea | 479 | return pop - now; |
89b3af67 A |
480 | } |
481 | ||
6601e61a A |
482 | uint64_t |
483 | mach_absolute_time(void) | |
4452a7af | 484 | { |
0c530ab8 A |
485 | return rtc_nanotime_read(); |
486 | } | |
487 | ||
3e170ce0 A |
488 | uint64_t |
489 | mach_approximate_time(void) | |
490 | { | |
491 | return rtc_nanotime_read(); | |
492 | } | |
493 | ||
0c530ab8 A |
494 | void |
495 | clock_interval_to_absolutetime_interval( | |
0a7de745 A |
496 | uint32_t interval, |
497 | uint32_t scale_factor, | |
498 | uint64_t *result) | |
0c530ab8 A |
499 | { |
500 | *result = (uint64_t)interval * scale_factor; | |
91447636 A |
501 | } |
502 | ||
503 | void | |
504 | absolutetime_to_microtime( | |
0a7de745 A |
505 | uint64_t abstime, |
506 | clock_sec_t *secs, | |
507 | clock_usec_t *microsecs) | |
91447636 | 508 | { |
b0d623f7 | 509 | _absolutetime_to_microtime(abstime, secs, microsecs); |
1c79356b A |
510 | } |
511 | ||
6601e61a | 512 | void |
0c530ab8 | 513 | nanotime_to_absolutetime( |
0a7de745 A |
514 | clock_sec_t secs, |
515 | clock_nsec_t nanosecs, | |
516 | uint64_t *result) | |
1c79356b | 517 | { |
0c530ab8 | 518 | *result = ((uint64_t)secs * NSEC_PER_SEC) + nanosecs; |
1c79356b A |
519 | } |
520 | ||
521 | void | |
522 | absolutetime_to_nanoseconds( | |
0a7de745 A |
523 | uint64_t abstime, |
524 | uint64_t *result) | |
1c79356b | 525 | { |
0b4e3aa0 | 526 | *result = abstime; |
1c79356b A |
527 | } |
528 | ||
529 | void | |
530 | nanoseconds_to_absolutetime( | |
0a7de745 A |
531 | uint64_t nanoseconds, |
532 | uint64_t *result) | |
1c79356b | 533 | { |
0b4e3aa0 | 534 | *result = nanoseconds; |
1c79356b A |
535 | } |
536 | ||
55e303ae | 537 | void |
91447636 | 538 | machine_delay_until( |
39236c6e | 539 | uint64_t interval, |
0a7de745 | 540 | uint64_t deadline) |
55e303ae | 541 | { |
39236c6e A |
542 | (void)interval; |
543 | while (mach_absolute_time() < deadline) { | |
544 | cpu_pause(); | |
0a7de745 | 545 | } |
55e303ae | 546 | } |