Fix build.
[reactos.git] / hal / halx86 / generic / i386 / 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 .intel_syntax noprefix
12
13 /* GLOBALS *******************************************************************/
14
15 .globl _HalpPerfCounter
16 _HalpLastPerfCounterLow: .long 0
17 _HalpLastPerfCounterHigh: .long 0
18 _HalpPerfCounter:
19 _HalpPerfCounterLow: .long 0
20 _HalpPerfCounterHigh: .long 0
21 _HalpSystemHardwareFlags: .long 0
22
23 _UnhandledMsg:
24 .asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx!!!\n"
25
26 /* FUNCTIONS *****************************************************************/
27
28 .global _HalpCalibrateStallExecution@0
29 .func HalpCalibrateStallExecution@0
30 _HalpCalibrateStallExecution@0:
31
32 /* Setup the stack frame */
33 push ebp
34 mov ebp, esp
35 sub esp, 12
36
37 /* Save EFLAGS and kill interrupts */
38 pushf
39 cli
40
41 /* Get the current interrupt mask on the PICs */
42 xor eax, eax
43 in al, 0xA1
44 shl eax, 8
45 in al, 0x21
46
47 /* Save it */
48 push eax
49
50 /* Now mask everything except the RTC and PIC 2 chain-interrupt */
51 mov eax, ~((1 << 2) | (1 << 8))
52
53 /* Program the PICs */
54 out 0x21, al
55 shr eax, 8
56 out 0xA1, al
57
58 /* Now get the IDT */
59 sidt [ebp-8]
60 mov ecx, [ebp-6]
61
62 /* Get the IDT entry for the RTC */
63 mov eax, 0x38
64 shl eax, 3
65 add ecx, eax
66
67 /* Save the original RTC ISR */
68 push [ecx]
69 push [ecx+4]
70 push ecx
71
72 /* Now load our new handler */
73 mov eax, offset OnlyOnePersonCanWriteHalCode
74 mov [ecx], ax
75 mov word ptr [ecx+2], KGDT_R0_CODE
76 mov word ptr [ecx+4], 0x8E00
77 shr eax, 16
78 mov [ecx+6], ax
79
80 /* Reset our counter */
81 mov dword ptr [ebp-12], 0
82
83 /* Acquire CMOS lock */
84 call _HalpAcquireSystemHardwareSpinLock@0
85
86 /* Now initialize register A on the CMOS */
87 mov ax, (0x2D << 8) | 0xA
88 out 0x70, al
89 jmp $+2
90 mov al, ah
91 out 0x71, al
92 jmp $+2
93
94 /* Read register B */
95 mov ax, 0xB
96 out 0x70, al
97 jmp $+2
98 in al, 0x71
99 jmp $+2
100
101 /* Don't touch the LastKnownGoodConfig hack */
102 and al, 1
103 mov ah, al
104
105 /* Enable the interrupt */
106 or ah, 0x42
107
108 /* Now write the register B */
109 mov al, 0xB
110 out 0x70, al
111 jmp $+2
112 mov al, ah
113 out 0x71, al
114 jmp $+2
115
116 /* Read register C */
117 mov al, 0xC
118 out 0x70, al
119 jmp $+2
120 in al, 0x71
121 jmp $+2
122
123 /* Read register D */
124 mov al, 0xD
125 out 0x70, al
126 jmp $+2
127 in al, 0x71
128 jmp $+2
129
130 /* Release CMOS lock */
131 mov dword ptr [ebp-12], 0
132 call _HalpReleaseCmosSpinLock@0
133
134 /* Initialize looper */
135 xor eax, eax
136
137 /* Align to 16 bytes */
138 .align 16
139
140 /* Enable interrupts! */
141 sti
142 jmp Looper
143
144 /* Align to 16 bytes */
145 .align 16
146
147 /* Subtract one count */
148 Looper:
149 sub eax, 1
150 jnz Looper
151
152 /* ASSERT: If we got here, then the RTC never fired */
153 call _DbgBreakPoint@0
154 jmp Looper
155
156 OnlyOnePersonCanWriteHalCode:
157 /*********************** THIS IS THE RTC HANDLER **************************/
158
159 /* Increment the interrupt count and check if this is the first one */
160 inc dword ptr [ebp-12]
161 cmp dword ptr [ebp-12], 1
162 jnz ComputeStall
163
164 /*
165 * It is the first one -- we'll ignore it, since it fires randomly!
166 * Get rid of the old return address and push the new one in (our looper)
167 */
168 pop eax
169 push offset Looper
170
171 /* Acquire CMOS lock */
172 call _HalpAcquireSystemHardwareSpinLock@0
173
174 /* Now initialize register A on the CMOS */
175 mov ax, (0x2D << 8) | 0xA
176 out 0x70, al
177 jmp $+2
178 mov al, ah
179 out 0x71, al
180 jmp $+2
181
182 /* Read register B */
183 mov ax, 0xB
184 out 0x70, al
185 jmp $+2
186 in al, 0x71
187 jmp $+2
188
189 /* Don't touch the LastKnownGoodConfig hack */
190 and al, 1
191 mov ah, al
192
193 /* Enable the interrupt */
194 or ah, 0x42
195
196 /* Now write the register B */
197 mov al, 0xB
198 out 0x70, al
199 jmp $+2
200 mov al, ah
201 out 0x71, al
202 jmp $+2
203
204 /* Read register C */
205 mov al, 0xC
206 out 0x70, al
207 jmp $+2
208 in al, 0x71
209 jmp $+2
210
211 /* Read register D */
212 mov al, 0xD
213 out 0x70, al
214 jmp $+2
215 in al, 0x71
216 jmp $+2
217
218 /* Release CMOS lock */
219 call _HalpReleaseCmosSpinLock@0
220
221 /* Dismiss the interrupt */
222 mov al, 0x20
223 out 0xA0, al
224 mov al, 0x62
225 out 0x20, al
226
227 /* Reset the counter and return back to the looper */
228 xor eax, eax
229 iretd
230
231 /******************* THIS IS THE 2ND RTC HANDLER **************************/
232 ComputeStall:
233
234 /* Do the calculation */
235 neg eax
236 xor edx, edx
237 mov ecx, 125000 /* RTC fires every 125 ms */
238 div ecx
239
240 /* Is the remainder 0? */
241 cmp edx, 0
242 jz FoundFactor
243
244 /* Otherwise fix-up the loop count */
245 inc eax
246
247 FoundFactor:
248 /* Save the stall scale factor */
249 mov fs:[KPCR_STALL_SCALE_FACTOR], eax
250
251 /* Prepare for interrupt return */
252 pop eax
253 push offset AndItsNotYou
254 mov eax, 0x13
255
256 /* Acquire CMOS lock */
257 call _HalpAcquireSystemHardwareSpinLock@0
258
259 /* Now initialize register A on the CMOS */
260 mov ax, (0x2D << 8) | 0xA
261 out 0x70, al
262 jmp $+2
263 mov al, ah
264 out 0x71, al
265 jmp $+2
266
267 /* Read register B */
268 mov ax, 0xB
269 out 0x70, al
270 jmp $+2
271 in al, 0x71
272 jmp $+2
273
274 /* Don't touch the LastKnownGoodConfig hack */
275 and al, 1
276 mov ah, al
277
278 /* Disable the interrupt */
279 or ah, 0x2
280
281 /* Now write the register B */
282 mov al, 0xB
283 out 0x70, al
284 jmp $+2
285 mov al, ah
286 out 0x71, al
287 jmp $+2
288
289 /* Read register C */
290 mov al, 0xC
291 out 0x70, al
292 jmp $+2
293 in al, 0x71
294 jmp $+2
295
296 /* Release CMOS lock */
297 call _HalpReleaseCmosSpinLock@0
298
299 /* Dismiss the interrupt */
300 mov al, 0x20
301 out 0xA0, al
302 mov al, 0x62
303 out 0x20, al
304
305 /* Disable interrupts on return */
306 and word ptr [esp+8], ~EFLAGS_INTERRUPT_MASK
307 iretd
308
309 /************************* WE ARE BACK FROM RTC ***************************/
310 AndItsNotYou:
311
312 /* Restore the IDT */
313 pop ecx
314 pop [ecx+4]
315 pop [ecx]
316
317 /* Restore the mask */
318 pop eax
319 out 0x21, al
320 shr eax, 8
321 out 0xA1, al
322
323 /* Restore EFLAGS */
324 popf
325
326 /* Restore stack and return */
327 mov esp, ebp
328 pop ebp
329 ret
330 .endfunc
331
332 #ifndef _MINIHAL_
333 .globl _KeStallExecutionProcessor@4
334 .func KeStallExecutionProcessor@4
335 _KeStallExecutionProcessor@4:
336
337 /* Get the number of microseconds required */
338 mov ecx, [esp+4]
339 jecxz Done
340
341 /* Multiply by the stall factor */
342 mov eax, fs:[KPCR_STALL_SCALE_FACTOR]
343 mul ecx
344
345 /* Align to 16 bytes */
346 .align 16
347
348 /* Jump to subtraction loop */
349 jmp SubtractLoop
350
351 /* Align to 16 bytes */
352 .align 16
353
354 /* Subtract one count */
355 SubtractLoop:
356 sub eax, 1
357 jnz SubtractLoop
358
359 Done:
360 /* Return */
361 ret 4
362 .endfunc
363 #endif
364
365 .global _KeQueryPerformanceCounter@4
366 .func KeQueryPerformanceCounter@4
367 _KeQueryPerformanceCounter@4:
368
369 /* Check if we were called too early */
370 cmp dword ptr _HalpCurrentRollOver, 0
371 je NoCount
372
373 /* Save volatiles */
374 push ebx
375 push esi
376
377 LoopPreInt:
378
379 /* Disable interrupts */
380 pushf
381 cli
382
383 LoopPostInt:
384
385 /* Get the current value */
386 mov ebx, _HalpPerfCounterLow
387 mov esi, _HalpPerfCounterHigh
388
389 /* Read 8254 timer */
390 mov al, 0
391 out 0x43, al
392 jmp $+2
393 in al, 0x40
394 jmp $+2
395 movzx ecx, al
396 in al, 0x40
397 mov ch, al
398
399 /* Enable interrupts and do a short wait */
400 popf
401 nop
402 jmp $+2
403
404 /* Disable them again */
405 pushf
406 cli
407
408 /* Get the counter value again */
409 mov eax, _HalpPerfCounterLow
410 mov edx, _HalpPerfCounterHigh
411
412 /* Check if someone updated the counter */
413 cmp eax, ebx
414 jnz LoopPostInt
415 cmp edx, esi
416 jnz LoopPostInt
417
418 /* Check if the current 8254 value causes rollover */
419 neg ecx
420 add ecx, _HalpCurrentRollOver
421 jnb DoRollOver
422
423 SetSum:
424
425 /* Calculate the sum */
426 add eax, ecx
427 adc edx, 0
428
429 /* Check if we're above or below the last high value */
430 cmp edx, _HalpLastPerfCounterHigh
431 jb short BelowHigh
432 jnz short BelowLow
433
434 /* Check if we're above or below the last low value */
435 cmp eax, _HalpLastPerfCounterLow
436 jb BelowHigh
437
438 BelowLow:
439
440 /* Update the last value and bring back interrupts */
441 mov _HalpLastPerfCounterLow, eax
442 mov _HalpLastPerfCounterHigh, edx
443 popf
444
445 /* Check if caller wants frequency */
446 cmp dword ptr [esp+12], 0
447 jz ReturnNoFreq
448
449 /* Save hard-coded frequency */
450 mov ecx, dword ptr [esp+12]
451 mov dword ptr [ecx], 1193182
452 mov dword ptr [ecx+4], 0
453
454 ReturnNoFreq:
455
456 /* Restore volatiles */
457 pop esi
458 pop ebx
459 ret 4
460
461 NoCount:
462
463 /* Return empty, called too soon */
464 mov eax, 0
465 mov edx, 0
466 ret 4
467
468 DoRollOver:
469
470 /* We might have an incoming interrupt, save EFLAGS and reset rollover */
471 mov esi, [esp]
472 mov ecx, _HalpCurrentRollOver
473 popf
474
475 /* Check if interrupts were enabled and try again */
476 test esi, EFLAGS_INTERRUPT_MASK
477 jnz LoopPreInt
478
479 /* They're not, continue where we left */
480 pushf
481 jmp SetSum
482
483 BelowHigh:
484
485 /* Get the last counter values */
486 mov ebx, _HalpLastPerfCounterLow
487 mov esi, _HalpLastPerfCounterHigh
488
489 /* Check if the previous value was 0 and go back if yes */
490 mov ecx, ebx
491 or ecx, esi
492 jz BelowLow
493
494 /* Make sure that the count is still valid */
495 sub ebx, eax
496 sbb esi, edx
497 jnz InvalidCount
498 cmp ebx, _HalpCurrentRollOver
499 jg InvalidCount
500
501 /* Fixup the count with the last known value */
502 sub eax, ebx
503 sbb edx, esi
504
505 /* We might have an incoming interrupt, save EFLAGS */
506 mov ecx, [esp]
507 popf
508
509 /* Check if interrupts were enabled and try again */
510 test ecx, EFLAGS_INTERRUPT_MASK
511 jnz LoopPreInt
512
513 /* They're not, continue where we left */
514 pushf
515 jmp BelowLow
516
517 InvalidCount:
518 popf
519 xor eax, eax
520 mov _HalpLastPerfCounterLow, eax
521 mov _HalpLastPerfCounterHigh, eax
522 jmp LoopPreInt
523 .endfunc