- Add KCALLOUT_FRAME to define the kernel callback stack layout during user mode...
[reactos.git] / reactos / hal / halamd64 / generic / systimer.S
1 /*
2 * FILE: hal/halx86/generic/timer.S
3 * COPYRIGHT: See COPYING in the top level directory
4 * PURPOSE: System Timer Interrupt and Management
5 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
6 */
7
8 /* INCLUDES ******************************************************************/
9
10 #include <asm.h>
11 #include <internal/i386/asmmacro.S>
12 .intel_syntax noprefix
13
14 /* GLOBALS *******************************************************************/
15
16 _HalpLastPerfCounterLow: .long 0
17 _HalpLastPerfCounterHigh: .long 0
18 _HalpPerfCounterLow: .long 0
19 _HalpPerfCounterHigh: .long 0
20
21 _UnhandledMsg:
22 .asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx!!!\n"
23
24 /* FUNCTIONS *****************************************************************/
25
26 .globl _KeStallExecutionProcessor
27 .func KeStallExecutionProcessor
28 _KeStallExecutionProcessor:
29
30 /* Get the number of microseconds required */
31 jecxz Done
32
33 /* Multiply by the stall factor */
34 mov eax, gs:[KPCR_STALL_SCALE_FACTOR]
35 mul ecx
36
37 /* Align to 16 bytes */
38 .align 16
39
40 /* Jump to subtraction loop */
41 jmp SubtractLoop
42
43 /* Align to 16 bytes */
44 .align 16
45
46 /* Subtract one count */
47 SubtractLoop:
48 sub eax, 1
49 jnz SubtractLoop
50
51 Done:
52 /* Return */
53 ret 4
54 .endfunc
55
56 .global _KeQueryPerformanceCounter
57 .func KeQueryPerformanceCounter
58 _KeQueryPerformanceCounter:
59
60 /* Check if we were called too early */
61 cmp dword ptr _HalpCurrentRollOver, 0
62 je NoCount
63
64 /* Save volatiles */
65 push rbx
66 push rsi
67
68 LoopPreInt:
69
70 /* Disable interrupts */
71 pushf
72 cli
73
74 LoopPostInt:
75
76 /* Get the current value */
77 mov ebx, _HalpPerfCounterLow
78 mov esi, _HalpPerfCounterHigh
79
80 /* Read 8254 timer */
81 mov al, 0
82 out 0x43, al
83 jmp $+2
84 in al, 0x40
85 jmp $+2
86 movzx ecx, al
87 in al, 0x40
88 mov ch, al
89
90 /* Enable interrupts and do a short wait */
91 popf
92 nop
93 jmp $+2
94
95 /* Disable them again */
96 pushf
97 cli
98
99 /* Get the counter value again */
100 mov eax, _HalpPerfCounterLow
101 mov edx, _HalpPerfCounterHigh
102
103 /* Check if someone updated the counter */
104 cmp eax, ebx
105 jnz LoopPostInt
106 cmp edx, esi
107 jnz LoopPostInt
108
109 /* Check if the current 8254 value causes rollover */
110 neg ecx
111 add ecx, _HalpCurrentRollOver
112 jnb DoRollOver
113
114 SetSum:
115
116 /* Calculate the sum */
117 add eax, ecx
118 adc edx, 0
119
120 /* Check if we're above or below the last high value */
121 cmp edx, _HalpLastPerfCounterHigh
122 jb short BelowHigh
123 jnz short BelowLow
124
125 /* Check if we're above or below the last low value */
126 cmp eax, _HalpLastPerfCounterLow
127 jb BelowHigh
128
129 BelowLow:
130
131 /* Update the last value and bring back interrupts */
132 mov _HalpLastPerfCounterLow, eax
133 mov _HalpLastPerfCounterHigh, edx
134 popf
135
136 /* Check if caller wants frequency */
137 cmp dword ptr [esp+12], 0
138 jz ReturnNoFreq
139
140 /* Save hard-coded frequency */
141 mov ecx, dword ptr [esp+12]
142 mov dword ptr [ecx], 1193182
143 mov dword ptr [ecx+4], 0
144
145 ReturnNoFreq:
146
147 /* Restore volatiles */
148 pop rsi
149 pop rbx
150 ret 4
151
152 NoCount:
153
154 /* Return empty, called too soon */
155 mov eax, 0
156 mov edx, 0
157 ret 4
158
159 DoRollOver:
160
161 /* We might have an incoming interrupt, save EFLAGS and reset rollover */
162 mov esi, [esp]
163 mov ecx, _HalpCurrentRollOver
164 popf
165
166 /* Check if interrupts were enabled and try again */
167 test esi, EFLAGS_INTERRUPT_MASK
168 jnz LoopPreInt
169
170 /* They're not, continue where we left */
171 pushf
172 jmp SetSum
173
174 BelowHigh:
175
176 /* Get the last counter values */
177 mov ebx, _HalpLastPerfCounterLow
178 mov esi, _HalpLastPerfCounterHigh
179
180 /* Check if the previous value was 0 and go back if yes */
181 mov ecx, ebx
182 or ecx, esi
183 jz BelowLow
184
185 /* Make sure that the count is still valid */
186 sub ebx, eax
187 sbb esi, edx
188 jnz InvalidCount
189 cmp ebx, _HalpCurrentRollOver
190 jg InvalidCount
191
192 /* Fixup the count with the last known value */
193 sub eax, ebx
194 sbb edx, esi
195
196 /* We might have an incoming interrupt, save EFLAGS */
197 mov ecx, [esp]
198 popf
199
200 /* Check if interrupts were enabled and try again */
201 test ecx, EFLAGS_INTERRUPT_MASK
202 jnz LoopPreInt
203
204 /* They're not, continue where we left */
205 pushf
206 jmp BelowLow
207
208 InvalidCount:
209 popf
210 xor eax, eax
211 mov _HalpLastPerfCounterLow, eax
212 mov _HalpLastPerfCounterHigh, eax
213 jmp LoopPreInt
214 .endfunc
215
216 .globl _HalpClockInterrupt
217 .func HalpClockInterrupt
218 //TRAP_FIXUPS hci_a, hci_t, DoFixupV86, DoFixupAbios
219 _HalpClockInterrupt:
220
221 /* Enter trap */
222 // INT_PROLOG hci_a, hci_t, DoPushFakeErrorCode
223
224 /* Push vector and make stack for IRQL */
225 push 0x30
226 sub esp, 4
227
228 /* Begin the interrupt */
229 push rsp
230 push 0x30
231 push CLOCK_LEVEL
232 // call _HalBeginSystemInterrupt
233
234 /* Check if it's spurious */
235 or al, al
236 jz Spurious
237
238 /* Update the performance counter */
239 xor ebx, ebx
240 mov eax, _HalpCurrentRollOver
241 add _HalpPerfCounterLow, eax
242 adc _HalpPerfCounterHigh, ebx
243
244 /* Get the time increment and check if someone changed the clock rate */
245 mov eax, _HalpCurrentTimeIncrement
246 cmp _HalpClockSetMSRate, ebx
247 jz _KeUpdateSystemTime
248
249 /* FIXME: Someone did! */
250 int 3
251
252 Spurious:
253
254 /* Exit the interrupt */
255 add esp, 8
256 // jmp _Kei386EoiHelper
257 .endfunc
258