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