1/* 2 * Copyright (c) 2004-2010 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#if defined(__i386__) 46 47/* 48 * Nanotime returned in %edx:%eax. 49 * Computed from tsc based on the scale factor 50 * and an implicit 32 bit shift. 51 * 52 * Uses %eax, %ebx, %ecx, %edx, %esi, %edi. 53 */ 54#define NANOTIME \ 55 mov %gs:CPU_NANOTIME,%edi ; \ 56 PAL_RTC_NANOTIME_READ_FAST() 57 58 59/* 60 * Add 64-bit delta in register dreg : areg to timer pointed to by register treg. 61 */ 62#define TIMER_UPDATE(treg,dreg,areg,offset) \ 63 addl (TIMER_LOW+(offset))(treg),areg /* add low bits */ ; \ 64 adcl dreg,(TIMER_HIGH+(offset))(treg) /* carry high bits */; \ 65 movl areg,(TIMER_LOW+(offset))(treg) /* updated low bit */; \ 66 movl (TIMER_HIGH+(offset))(treg),dreg /* copy high bits */ ; \ 67 movl dreg,(TIMER_HIGHCHK+(offset))(treg) /* to high check */ 68 69/* 70 * Add time delta to old timer and start new. 71 */ 72#define TIMER_EVENT(old,new) \ 73 NANOTIME /* edx:eax nanosecs */ ; \ 74 movl %eax,%esi /* save timestamp */ ; \ 75 movl %edx,%edi /* save timestamp */ ; \ 76 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */ ; \ 77 subl (old##_TIMER)+TIMER_TSTAMP(%ecx),%eax /* elapsed */ ; \ 78 sbbl (old##_TIMER)+TIMER_TSTAMP+4(%ecx),%edx /* time */ ; \ 79 TIMER_UPDATE(%ecx,%edx,%eax,old##_TIMER) /* update timer */ ; \ 80 movl %esi,(new##_TIMER)+TIMER_TSTAMP(%ecx) /* set timestamp */ ; \ 81 movl %edi,(new##_TIMER)+TIMER_TSTAMP+4(%ecx) /* set timestamp */ ; \ 82 leal (new##_TIMER)(%ecx), %ecx /* compute new timer pointer */ ; \ 83 movl %gs:CPU_PROCESSOR,%ebx /* get current processor */ ; \ 84 movl %ecx,THREAD_TIMER(%ebx) /* set current timer */ ; \ 85 movl %esi,%eax /* restore timestamp */ ; \ 86 movl %edi,%edx /* restore timestamp */ ; \ 87 subl (old##_STATE)+TIMER_TSTAMP(%ebx),%eax /* elapsed */ ; \ 88 sbbl (old##_STATE)+TIMER_TSTAMP+4(%ebx),%edx /* time */ ; \ 89 TIMER_UPDATE(%ebx,%edx,%eax,old##_STATE)/* update timer */ ; \ 90 leal (new##_STATE)(%ebx),%ecx /* new state pointer */ ; \ 91 movl %ecx,CURRENT_STATE(%ebx) /* set current state */ ; \ 92 movl %esi,TIMER_TSTAMP(%ecx) /* set timestamp */ ; \ 93 movl %edi,TIMER_TSTAMP+4(%ecx) /* set timestamp */ 94 95/* 96 * Update time on user trap entry. 97 * Uses %eax,%ebx,%ecx,%edx,%esi,%edi. 98 */ 99#define TIME_TRAP_UENTRY TIMER_EVENT(USER,SYSTEM) 100 101/* 102 * update time on user trap exit. 103 * Uses %eax,%ebx,%ecx,%edx,%esi,%edi. 104 */ 105#define TIME_TRAP_UEXIT TIMER_EVENT(SYSTEM,USER) 106 107/* 108 * update time on interrupt entry. 109 * Uses %eax,%ebx,%ecx,%edx,%esi,%edi. 110 * Saves processor state info on stack. 111 */ 112#define TIME_INT_ENTRY \ 113 NANOTIME /* edx:eax nanosecs */ ; \ 114 movl %eax,%gs:CPU_INT_EVENT_TIME /* save in cpu data */ ; \ 115 movl %edx,%gs:CPU_INT_EVENT_TIME+4 /* save in cpu data */ ; \ 116 movl %eax,%esi /* save timestamp */ ; \ 117 movl %edx,%edi /* save timestamp */ ; \ 118 movl %gs:CPU_PROCESSOR,%ebx /* get current processor */ ; \ 119 movl THREAD_TIMER(%ebx),%ecx /* get current timer */ ; \ 120 subl TIMER_TSTAMP(%ecx),%eax /* compute elapsed time */ ; \ 121 sbbl TIMER_TSTAMP+4(%ecx),%edx /* compute elapsed time */ ; \ 122 TIMER_UPDATE(%ecx,%edx,%eax,0) /* update timer */ ; \ 123 movl KERNEL_TIMER(%ebx),%ecx /* point to kernel timer */ ; \ 124 movl %esi,TIMER_TSTAMP(%ecx) /* set timestamp */ ; \ 125 movl %edi,TIMER_TSTAMP+4(%ecx) /* set timestamp */ ; \ 126 movl %esi,%eax /* restore timestamp */ ; \ 127 movl %edi,%edx /* restore timestamp */ ; \ 128 movl CURRENT_STATE(%ebx),%ecx /* get current state */ ; \ 129 pushl %ecx /* save state */ ; \ 130 subl TIMER_TSTAMP(%ecx),%eax /* compute elapsed time */ ; \ 131 sbbl TIMER_TSTAMP+4(%ecx),%edx /* compute elapsed time */ ; \ 132 TIMER_UPDATE(%ecx,%edx,%eax,0) /* update timer */ ; \ 133 leal IDLE_STATE(%ebx),%eax /* get idle state */ ; \ 134 cmpl %eax,%ecx /* compare current state */ ; \ 135 je 0f /* skip if equal */ ; \ 136 leal SYSTEM_STATE(%ebx),%ecx /* get system state */ ; \ 137 movl %ecx,CURRENT_STATE(%ebx) /* set current state */ ; \ 1380: movl %esi,TIMER_TSTAMP(%ecx) /* set timestamp */ ; \ 139 movl %edi,TIMER_TSTAMP+4(%ecx) /* set timestamp */ 140 141/* 142 * update time on interrupt exit. 143 * Uses %eax,%ebx,%ecx,%edx,%esi,%edi. 144 * Restores processor state info from stack. 145 */ 146#define TIME_INT_EXIT \ 147 NANOTIME /* edx:eax nanosecs */ ; \ 148 movl %eax,%gs:CPU_INT_EVENT_TIME /* save in cpu data */ ; \ 149 movl %edx,%gs:CPU_INT_EVENT_TIME+4 /* save in cpu data */ ; \ 150 movl %eax,%esi /* save timestamp */ ; \ 151 movl %edx,%edi /* save timestamp */ ; \ 152 movl %gs:CPU_PROCESSOR,%ebx /* get current processor */ ; \ 153 movl KERNEL_TIMER(%ebx),%ecx /* point to kernel timer */ ; \ 154 subl TIMER_TSTAMP(%ecx),%eax /* compute elapsed time */ ; \ 155 sbbl TIMER_TSTAMP+4(%ecx),%edx /* compute elapsed time */ ; \ 156 TIMER_UPDATE(%ecx,%edx,%eax,0) /* update timer */ ; \ 157 movl THREAD_TIMER(%ebx),%ecx /* interrupted timer */ ; \ 158 movl %esi,TIMER_TSTAMP(%ecx) /* set timestamp */ ; \ 159 movl %edi,TIMER_TSTAMP+4(%ecx) /* set timestamp */ ; \ 160 movl %esi,%eax /* restore timestamp */ ; \ 161 movl %edi,%edx /* restore timestamp */ ; \ 162 movl CURRENT_STATE(%ebx),%ecx /* get current state */ ; \ 163 subl TIMER_TSTAMP(%ecx),%eax /* compute elapsed time */ ; \ 164 sbbl TIMER_TSTAMP+4(%ecx),%edx /* compute elapsed time */ ; \ 165 TIMER_UPDATE(%ecx,%edx,%eax,0) /* update timer */ ; \ 166 popl %ecx /* restore state */ ; \ 167 movl %ecx,CURRENT_STATE(%ebx) /* set current state */ ; \ 168 movl %esi,TIMER_TSTAMP(%ecx) /* set timestamp */ ; \ 169 movl %edi,TIMER_TSTAMP+4(%ecx) /* set timestamp */ 170 171#elif defined(__x86_64__) 172 173/* 174 * Nanotime returned in %rax. 175 * Computed from tsc based on the scale factor and an implicit 32 bit shift. 176 * This code must match what _rtc_nanotime_read does in 177 * machine_routines_asm.s. Failure to do so can 178 * result in "weird" timing results. 179 * 180 * Uses: %rsi, %rdi, %rdx, %rcx 181 */ 182#define NANOTIME \ 183 movq %gs:CPU_NANOTIME,%rdi ; \ 184 PAL_RTC_NANOTIME_READ_FAST() 185 186/* 187 * Add 64-bit delta in register reg to timer pointed to by register treg. 188 */ 189#define TIMER_UPDATE(treg,reg,offset) \ 190 addq reg,(offset)+TIMER_ALL(treg) /* add timer */ 191 192/* 193 * Add time delta to old timer and start new. 194 * Uses: %rsi, %rdi, %rdx, %rcx, %rax 195 */ 196#define TIMER_EVENT(old,new) \ 197 NANOTIME /* %rax := nanosecs */ ; \ 198 movq %rax,%rsi /* save timestamp */ ; \ 199 movq %gs:CPU_ACTIVE_THREAD,%rcx /* get thread */ ; \ 200 subq (old##_TIMER)+TIMER_TSTAMP(%rcx),%rax /* compute elapsed */; \ 201 TIMER_UPDATE(%rcx,%rax,old##_TIMER) /* update timer */ ; \ 202 leaq (new##_TIMER)(%rcx),%rcx /* point to new timer */ ; \ 203 movq %rsi,TIMER_TSTAMP(%rcx) /* set timestamp */ ; \ 204 movq %gs:CPU_PROCESSOR,%rdx /* get processor */ ; \ 205 movq %rcx,THREAD_TIMER(%rdx) /* set current timer */ ; \ 206 movq %rsi,%rax /* restore timestamp */ ; \ 207 subq (old##_STATE)+TIMER_TSTAMP(%rdx),%rax /* compute elapsed */; \ 208 TIMER_UPDATE(%rdx,%rax,old##_STATE) /* update timer */ ; \ 209 leaq (new##_STATE)(%rdx),%rcx /* point to new state */ ; \ 210 movq %rcx,CURRENT_STATE(%rdx) /* set current state */ ; \ 211 movq %rsi,TIMER_TSTAMP(%rcx) /* set timestamp */ 212 213/* 214 * Update time on user trap entry. 215 * Uses: %rsi, %rdi, %rdx, %rcx, %rax 216 */ 217#define TIME_TRAP_UENTRY TIMER_EVENT(USER,SYSTEM) 218 219/* 220 * update time on user trap exit. 221 * Uses: %rsi, %rdi, %rdx, %rcx, %rax 222 */ 223#define TIME_TRAP_UEXIT TIMER_EVENT(SYSTEM,USER) 224 225/* 226 * update time on interrupt entry. 227 * Uses: %rsi, %rdi, %rdx, %rcx, %rax 228 * Saves processor state info on stack. 229 */ 230#define TIME_INT_ENTRY \ 231 NANOTIME /* %rax := nanosecs */ ; \ 232 movq %rax,%gs:CPU_INT_EVENT_TIME /* save in cpu data */ ; \ 233 movq %rax,%rsi /* save timestamp */ ; \ 234 movq %gs:CPU_PROCESSOR,%rdx /* get processor */ ; \ 235 movq THREAD_TIMER(%rdx),%rcx /* get current timer */ ; \ 236 subq TIMER_TSTAMP(%rcx),%rax /* compute elapsed */ ; \ 237 TIMER_UPDATE(%rcx,%rax,0) /* update timer */ ; \ 238 movq KERNEL_TIMER(%rdx),%rcx /* get kernel timer */ ; \ 239 movq %rsi,TIMER_TSTAMP(%rcx) /* set timestamp */ ; \ 240 movq %rsi,%rax /* restore timestamp */ ; \ 241 movq CURRENT_STATE(%rdx),%rcx /* get current state */ ; \ 242 pushq %rcx /* save state */ ; \ 243 subq TIMER_TSTAMP(%rcx),%rax /* compute elapsed */ ; \ 244 TIMER_UPDATE(%rcx,%rax,0) /* update timer */ ; \ 245 leaq IDLE_STATE(%rdx),%rax /* get idle state */ ; \ 246 cmpq %rax,%rcx /* compare current */ ; \ 247 je 0f /* skip if equal */ ; \ 248 leaq SYSTEM_STATE(%rdx),%rcx /* get system state */ ; \ 249 movq %rcx,CURRENT_STATE(%rdx) /* set current state */ ; \ 2500: movq %rsi,TIMER_TSTAMP(%rcx) /* set timestamp */ 251 252/* 253 * update time on interrupt exit. 254 * Uses: %rsi, %rdi, %rdx, %rcx, %rax 255 * Restores processor state info from stack. 256 */ 257#define TIME_INT_EXIT \ 258 NANOTIME /* %rax := nanosecs */ ; \ 259 movq %rax,%gs:CPU_INT_EVENT_TIME /* save in cpu data */ ; \ 260 movq %rax,%rsi /* save timestamp */ ; \ 261 movq %gs:CPU_PROCESSOR,%rdx /* get processor */ ; \ 262 movq KERNEL_TIMER(%rdx),%rcx /* get kernel timer */ ; \ 263 subq TIMER_TSTAMP(%rcx),%rax /* compute elapsed */ ; \ 264 TIMER_UPDATE(%rcx,%rax,0) /* update timer */ ; \ 265 movq THREAD_TIMER(%rdx),%rcx /* interrupted timer */ ; \ 266 movq %rsi,TIMER_TSTAMP(%rcx) /* set timestamp */ ; \ 267 movq %rsi,%rax /* restore timestamp */ ; \ 268 movq CURRENT_STATE(%rdx),%rcx /* get current state */ ; \ 269 subq TIMER_TSTAMP(%rcx),%rax /* compute elapsed */ ; \ 270 TIMER_UPDATE(%rcx,%rax,0) /* update timer */ ; \ 271 popq %rcx /* restore state */ ; \ 272 movq %rcx,CURRENT_STATE(%rdx) /* set current state */ ; \ 273 movq %rsi,TIMER_TSTAMP(%rcx) /* set timestamp */ 274 275#endif 276 277/* 278 * Check for vtimers for task. 279 * task_reg is register pointing to current task 280 * thread_reg is register pointing to current thread 281 */ 282#define TASK_VTIMER_CHECK(task_reg,thread_reg) \ 283 cmpl $0,TASK_VTIMERS(task_reg) ; \ 284 jz 1f ; \ 285 orl $(AST_BSD),%gs:CPU_PENDING_AST /* Set pending AST */ ; \ 286 lock ; \ 287 orl $(AST_BSD),TH_AST(thread_reg) /* Set thread AST */ ; \ 2881: ; \ 289 290#endif /* _I386_RTCLOCK_H_ */ 291