]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/rtclock_asm.h
dba69a6e742ae828f223b408b5c383f5a313afb3
[apple/xnu.git] / osfmk / i386 / rtclock_asm.h
1 /*
2 * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31 /*
32 * @APPLE_FREE_COPYRIGHT@
33 */
34 /*
35 * File: rtclock_asm.h
36 * Purpose: Assembly routines for handling the machine dependent
37 * real-time clock.
38 */
39
40 #ifndef _I386_RTCLOCK_H_
41 #define _I386_RTCLOCK_H_
42
43 #include <i386/pal_rtclock_asm.h>
44
45 /*
46 * Nanotime returned in %rax.
47 * Computed from tsc based on the scale factor and an implicit 32 bit shift.
48 * This code must match what _rtc_nanotime_read does in
49 * machine_routines_asm.s. Failure to do so can
50 * result in "weird" timing results.
51 *
52 * Uses: %rsi, %rdi, %rdx, %rcx
53 */
54 #define NANOTIME \
55 movq %gs:CPU_NANOTIME,%rdi ; \
56 PAL_RTC_NANOTIME_READ_FAST()
57
58 /*
59 * Add 64-bit delta in register reg to timer pointed to by register treg.
60 */
61 #define TIMER_UPDATE(treg,reg,offset) \
62 addq reg,(offset)+TIMER_ALL(treg) /* add timer */
63
64 /*
65 * Add time delta to old timer and start new.
66 * Uses: %rsi, %rdi, %rdx, %rcx, %rax
67 */
68 #define TIMER_EVENT(old,new) \
69 NANOTIME /* %rax := nanosecs */ ; \
70 movq %rax,%rsi /* save timestamp */ ; \
71 movq %gs:CPU_ACTIVE_THREAD,%rcx /* get thread */ ; \
72 subq (old##_TIMER)+TIMER_TSTAMP(%rcx),%rax /* compute elapsed */; \
73 TIMER_UPDATE(%rcx,%rax,old##_TIMER) /* update timer */ ; \
74 leaq (new##_TIMER)(%rcx),%rcx /* point to new timer */ ; \
75 movq %rsi,TIMER_TSTAMP(%rcx) /* set timestamp */ ; \
76 movq %gs:CPU_PROCESSOR,%rdx /* get processor */ ; \
77 movq %rcx,THREAD_TIMER(%rdx) /* set current timer */ ; \
78 movq %rsi,%rax /* restore timestamp */ ; \
79 subq (old##_STATE)+TIMER_TSTAMP(%rdx),%rax /* compute elapsed */; \
80 TIMER_UPDATE(%rdx,%rax,old##_STATE) /* update timer */ ; \
81 leaq (new##_STATE)(%rdx),%rcx /* point to new state */ ; \
82 movq %rcx,CURRENT_STATE(%rdx) /* set current state */ ; \
83 movq %rsi,TIMER_TSTAMP(%rcx) /* set timestamp */
84
85 /*
86 * Update time on user trap entry.
87 * Uses: %rsi, %rdi, %rdx, %rcx, %rax
88 */
89 #define TIME_TRAP_UENTRY TIMER_EVENT(USER,SYSTEM)
90
91 /*
92 * update time on user trap exit.
93 * Uses: %rsi, %rdi, %rdx, %rcx, %rax
94 */
95 #define TIME_TRAP_UEXIT TIMER_EVENT(SYSTEM,USER)
96
97 /*
98 * update time on interrupt entry.
99 * Uses: %rsi, %rdi, %rdx, %rcx, %rax
100 * Saves processor state info on stack.
101 */
102 #define TIME_INT_ENTRY \
103 NANOTIME /* %rax := nanosecs */ ; \
104 movq %rax,%gs:CPU_INT_EVENT_TIME /* save in cpu data */ ; \
105 movq %rax,%rsi /* save timestamp */ ; \
106 movq %gs:CPU_PROCESSOR,%rdx /* get processor */ ; \
107 movq THREAD_TIMER(%rdx),%rcx /* get current timer */ ; \
108 subq TIMER_TSTAMP(%rcx),%rax /* compute elapsed */ ; \
109 TIMER_UPDATE(%rcx,%rax,0) /* update timer */ ; \
110 movq KERNEL_TIMER(%rdx),%rcx /* get kernel timer */ ; \
111 movq %rsi,TIMER_TSTAMP(%rcx) /* set timestamp */ ; \
112 movq %rsi,%rax /* restore timestamp */ ; \
113 movq CURRENT_STATE(%rdx),%rcx /* get current state */ ; \
114 pushq %rcx /* save state */ ; \
115 subq TIMER_TSTAMP(%rcx),%rax /* compute elapsed */ ; \
116 TIMER_UPDATE(%rcx,%rax,0) /* update timer */ ; \
117 leaq IDLE_STATE(%rdx),%rax /* get idle state */ ; \
118 cmpq %rax,%rcx /* compare current */ ; \
119 je 0f /* skip if equal */ ; \
120 leaq SYSTEM_STATE(%rdx),%rcx /* get system state */ ; \
121 movq %rcx,CURRENT_STATE(%rdx) /* set current state */ ; \
122 0: movq %rsi,TIMER_TSTAMP(%rcx) /* set timestamp */
123
124 /*
125 * update time on interrupt exit.
126 * Uses: %rsi, %rdi, %rdx, %rcx, %rax
127 * Restores processor state info from stack.
128 */
129 #define TIME_INT_EXIT \
130 NANOTIME /* %rax := nanosecs */ ; \
131 movq %rax,%rsi /* save timestamp */ ; \
132 movq %gs:CPU_PROCESSOR,%rdx /* get processor */ ; \
133 movq KERNEL_TIMER(%rdx),%rcx /* get kernel timer */ ; \
134 subq TIMER_TSTAMP(%rcx),%rax /* compute elapsed */ ; \
135 TIMER_UPDATE(%rcx,%rax,0) /* update timer */ ; \
136 movq THREAD_TIMER(%rdx),%rcx /* interrupted timer */ ; \
137 movq %rsi,TIMER_TSTAMP(%rcx) /* set timestamp */ ; \
138 movq %rsi,%rax /* restore timestamp */ ; \
139 movq CURRENT_STATE(%rdx),%rcx /* get current state */ ; \
140 subq TIMER_TSTAMP(%rcx),%rax /* compute elapsed */ ; \
141 TIMER_UPDATE(%rcx,%rax,0) /* update timer */ ; \
142 popq %rcx /* restore state */ ; \
143 movq %rcx,CURRENT_STATE(%rdx) /* set current state */ ; \
144 movq %rsi,TIMER_TSTAMP(%rcx) /* set timestamp */ ; \
145 movq $0,%gs:CPU_INT_EVENT_TIME /* clear interrupt entry time */
146
147
148 /*
149 * Check for vtimers for task.
150 * task_reg is register pointing to current task
151 * thread_reg is register pointing to current thread
152 */
153 #define TASK_VTIMER_CHECK(task_reg,thread_reg) \
154 cmpl $0,TASK_VTIMERS(task_reg) ; \
155 jz 1f ; \
156 orl $(AST_BSD),%gs:CPU_PENDING_AST /* Set pending AST */ ; \
157 lock ; \
158 orl $(AST_BSD),TH_AST(thread_reg) /* Set thread AST */ ; \
159 1: ; \
160
161 #endif /* _I386_RTCLOCK_H_ */