2 * FILE: hal/halx86/generic/systimer.S
3 * COPYRIGHT: See COPYING in the top level directory
4 * PURPOSE: System Timer Interrupt and Management
5 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
8 /* INCLUDES ******************************************************************/
14 EXTERN _HalpAcquireCmosSpinLock@0:PROC
15 EXTERN _HalpReleaseCmosSpinLock@0:PROC
16 EXTERN _DbgBreakPoint@0:PROC
18 #define PIC1_BASE HEX(20) /* IO base address for master PIC */
19 #define PIC2_BASE HEX(A0) /* IO base address for slave PIC */
20 #define PIC1_COMMAND PIC1_BASE
21 #define PIC1_DATA (PIC1_BASE+1)
22 #define PIC2_COMMAND PIC2_BASE
23 #define PIC2_DATA (PIC2_BASE+1)
24 #define PIC_EOI HEX(20)
25 #define PIC_SPECIFIC_EOI2 HEX(62)
27 #define CMOS_ADDR HEX(70)
28 #define CMOS_DATA HEX(71)
29 #define CMOS_REGISTER_A HEX(0A)
30 #define CMOS_REGISTER_B HEX(0B)
31 #define CMOS_REGISTER_C HEX(0C)
32 #define CMOS_REGISTER_D HEX(0D)
34 #define PIT_CH0 HEX(40)
35 #define PIT_MODE HEX(43)
36 #define SYSTEM_CTRL_PORT_A HEX(92)
38 /* GLOBALS *******************************************************************/
41 ASSUME CS:NOTHING, DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING
43 /* FUNCTIONS *****************************************************************/
46 PUBLIC _HalpCalibrateStallExecution@0
47 _HalpCalibrateStallExecution@0:
49 /* Setup the stack frame */
54 /* Save EFLAGS and kill interrupts */
58 /* Get the current interrupt mask on the PICs */
67 /* Now mask everything except the RTC and PIC 2 chain-interrupt */
68 mov eax, NOT (HEX(04) OR HEX(100))
70 /* Program the PICs */
79 /* Get the IDT entry for the RTC */
84 /* Save the original RTC ISR */
89 /* Now load our new handler */
90 mov eax, offset OnlyOnePersonCanWriteHalCode
92 mov word ptr [ecx+2], KGDT_R0_CODE
93 mov word ptr [ecx+4], HEX(08E00)
97 /* Reset our counter */
98 mov dword ptr [ebp-12], 0
100 /* Acquire CMOS lock */
101 call _HalpAcquireCmosSpinLock@0
103 /* Now initialize register A on the CMOS */
104 mov ax, HEX(2D00) OR CMOS_REGISTER_A
111 /* Read register B */
112 mov ax, CMOS_REGISTER_B
118 /* Don't touch the LastKnownGoodConfig hack */
122 /* Enable the interrupt */
125 /* Now write the register B */
126 mov al, CMOS_REGISTER_B
133 /* Read register C */
134 mov al, CMOS_REGISTER_C
140 /* Read register D */
141 mov al, CMOS_REGISTER_D
147 /* Release CMOS lock */
148 mov dword ptr [ebp-12], 0
149 call _HalpReleaseCmosSpinLock@0
151 /* Initialize looper */
154 /* Align to 16 bytes */
157 /* Enable interrupts! */
161 /* Align to 16 bytes */
164 /* Subtract one count */
169 /* ASSERT: If we got here, then the RTC never fired */
170 call _DbgBreakPoint@0
173 OnlyOnePersonCanWriteHalCode:
174 /*********************** THIS IS THE RTC HANDLER **************************/
176 /* Increment the interrupt count and check if this is the first one */
177 inc dword ptr [ebp-12]
178 cmp dword ptr [ebp-12], 1
182 * It is the first one -- we'll ignore it, since it fires randomly!
183 * Get rid of the old return address and push the new one in (our looper)
188 /* Acquire CMOS lock */
189 call _HalpAcquireCmosSpinLock@0
191 /* Now initialize register A on the CMOS */
192 mov ax, HEX(2D00) OR CMOS_REGISTER_A
199 /* Read register B */
200 mov ax, CMOS_REGISTER_B
206 /* Don't touch the LastKnownGoodConfig hack */
210 /* Enable the interrupt */
213 /* Now write the register B */
214 mov al, CMOS_REGISTER_B
221 /* Read register C */
222 mov al, CMOS_REGISTER_C
228 /* Read register D */
229 mov al, CMOS_REGISTER_D
235 /* Release CMOS lock */
236 call _HalpReleaseCmosSpinLock@0
238 /* Dismiss the interrupt */
241 mov al, PIC_SPECIFIC_EOI2
244 /* Reset the counter and return back to the looper */
248 /******************* THIS IS THE 2ND RTC HANDLER **************************/
251 /* Do the calculation */
254 mov ecx, 125000 /* RTC fires every 125 ms */
257 /* Is the remainder 0? */
261 /* Otherwise fix-up the loop count */
265 /* Save the stall scale factor */
266 mov fs:[KPCR_STALL_SCALE_FACTOR], eax
268 /* Prepare for interrupt return */
270 push offset AndItsNotYou
273 /* Acquire CMOS lock */
274 call _HalpAcquireCmosSpinLock@0
276 /* Now initialize register A on the CMOS */
277 mov ax, HEX(2D00) OR CMOS_REGISTER_A
284 /* Read register B */
285 mov ax, CMOS_REGISTER_B
291 /* Don't touch the LastKnownGoodConfig hack */
295 /* Disable the interrupt */
298 /* Now write the register B */
299 mov al, CMOS_REGISTER_B
306 /* Read register C */
307 mov al, CMOS_REGISTER_C
313 /* Release CMOS lock */
314 call _HalpReleaseCmosSpinLock@0
316 /* Dismiss the interrupt */
319 mov al, PIC_SPECIFIC_EOI2
322 /* Disable interrupts on return */
323 and word ptr [esp+8], NOT EFLAGS_INTERRUPT_MASK
326 /************************* WE ARE BACK FROM RTC ***************************/
329 /* Restore the IDT */
334 /* Restore the mask */
343 /* Restore stack and return */
350 PUBLIC _KeStallExecutionProcessor@4
351 _KeStallExecutionProcessor@4:
353 /* Get the number of microseconds required */
357 /* Multiply by the stall factor */
358 mov eax, fs:[KPCR_STALL_SCALE_FACTOR]
361 /* Jump to subtraction loop */
364 /* Align to 16 bytes */
367 /* Subtract one count */