xref: /reactos/hal/halx86/generic/systimer.S (revision 2aca4b27)
1*c2c66affSColin Finck/*
2*c2c66affSColin Finck * FILE:            hal/halx86/generic/systimer.S
3*c2c66affSColin Finck * COPYRIGHT:       See COPYING in the top level directory
4*c2c66affSColin Finck * PURPOSE:         System Timer Interrupt and Management
5*c2c66affSColin Finck * PROGRAMMER:      Alex Ionescu (alex@relsoft.net)
6*c2c66affSColin Finck */
7*c2c66affSColin Finck
8*c2c66affSColin Finck/* INCLUDES ******************************************************************/
9*c2c66affSColin Finck
10*c2c66affSColin Finck#include <asm.inc>
11*c2c66affSColin Finck
12*c2c66affSColin Finck#include <ks386.inc>
13*c2c66affSColin Finck
14*c2c66affSColin FinckEXTERN _HalpAcquireCmosSpinLock@0:PROC
15*c2c66affSColin FinckEXTERN _HalpReleaseCmosSpinLock@0:PROC
16*c2c66affSColin FinckEXTERN _DbgBreakPoint@0:PROC
17*c2c66affSColin Finck
18*c2c66affSColin Finck#define PIC1_BASE         HEX(20) /* IO base address for master PIC */
19*c2c66affSColin Finck#define PIC2_BASE         HEX(A0) /* IO base address for slave PIC */
20*c2c66affSColin Finck#define PIC1_COMMAND      PIC1_BASE
21*c2c66affSColin Finck#define PIC1_DATA         (PIC1_BASE+1)
22*c2c66affSColin Finck#define PIC2_COMMAND      PIC2_BASE
23*c2c66affSColin Finck#define PIC2_DATA         (PIC2_BASE+1)
24*c2c66affSColin Finck#define PIC_EOI           HEX(20)
25*c2c66affSColin Finck#define PIC_SPECIFIC_EOI2 HEX(62)
26*c2c66affSColin Finck
27*c2c66affSColin Finck#define CMOS_ADDR HEX(70)
28*c2c66affSColin Finck#define CMOS_DATA HEX(71)
29*c2c66affSColin Finck#define CMOS_REGISTER_A HEX(0A)
30*c2c66affSColin Finck#define CMOS_REGISTER_B HEX(0B)
31*c2c66affSColin Finck#define CMOS_REGISTER_C HEX(0C)
32*c2c66affSColin Finck#define CMOS_REGISTER_D HEX(0D)
33*c2c66affSColin Finck
34*c2c66affSColin Finck#define PIT_CH0    HEX(40)
35*c2c66affSColin Finck#define PIT_MODE   HEX(43)
36*c2c66affSColin Finck#define SYSTEM_CTRL_PORT_A HEX(92)
37*c2c66affSColin Finck
38*c2c66affSColin Finck/* FUNCTIONS *****************************************************************/
39*c2c66affSColin Finck
40*c2c66affSColin Finck.code
41*c2c66affSColin FinckPUBLIC _HalpCalibrateStallExecution@0
42*c2c66affSColin Finck_HalpCalibrateStallExecution@0:
43*c2c66affSColin Finck
44*c2c66affSColin Finck    /* Setup the stack frame */
45*c2c66affSColin Finck    push ebp
46*c2c66affSColin Finck    mov ebp, esp
47*c2c66affSColin Finck    sub esp, 12
48*c2c66affSColin Finck
49*c2c66affSColin Finck    /* Save EFLAGS and kill interrupts */
50*c2c66affSColin Finck    pushfd
51*c2c66affSColin Finck    cli
52*c2c66affSColin Finck
53*c2c66affSColin Finck    /* Get the current interrupt mask on the PICs */
54*c2c66affSColin Finck    xor eax, eax
55*c2c66affSColin Finck    in al, PIC2_DATA
56*c2c66affSColin Finck    shl eax, 8
57*c2c66affSColin Finck    in al, PIC1_DATA
58*c2c66affSColin Finck
59*c2c66affSColin Finck    /* Save it */
60*c2c66affSColin Finck    push eax
61*c2c66affSColin Finck
62*c2c66affSColin Finck    /* Now mask everything except the RTC and PIC 2 chain-interrupt */
63*c2c66affSColin Finck    mov eax, NOT (HEX(04) OR HEX(100))
64*c2c66affSColin Finck
65*c2c66affSColin Finck    /* Program the PICs */
66*c2c66affSColin Finck    out PIC1_DATA, al
67*c2c66affSColin Finck    shr eax, 8
68*c2c66affSColin Finck    out PIC2_DATA, al
69*c2c66affSColin Finck
70*c2c66affSColin Finck    /* Now get the IDT */
71*c2c66affSColin Finck    sidt [ebp-8]
72*c2c66affSColin Finck    mov ecx, [ebp-6]
73*c2c66affSColin Finck
74*c2c66affSColin Finck    /* Get the IDT entry for the RTC */
75*c2c66affSColin Finck    mov eax, HEX(38)
76*c2c66affSColin Finck    shl eax, 3
77*c2c66affSColin Finck    add ecx, eax
78*c2c66affSColin Finck
79*c2c66affSColin Finck    /* Save the original RTC ISR */
80*c2c66affSColin Finck    push [ecx]
81*c2c66affSColin Finck    push [ecx+4]
82*c2c66affSColin Finck    push ecx
83*c2c66affSColin Finck
84*c2c66affSColin Finck    /* Now load our new handler */
85*c2c66affSColin Finck    mov eax, offset OnlyOnePersonCanWriteHalCode
86*c2c66affSColin Finck    mov [ecx], ax
87*c2c66affSColin Finck    mov word ptr [ecx+2], KGDT_R0_CODE
88*c2c66affSColin Finck    mov word ptr [ecx+4], HEX(08E00)
89*c2c66affSColin Finck    shr eax, 16
90*c2c66affSColin Finck    mov [ecx+6], ax
91*c2c66affSColin Finck
92*c2c66affSColin Finck    /* Reset our counter */
93*c2c66affSColin Finck    mov dword ptr [ebp-12], 0
94*c2c66affSColin Finck
95*c2c66affSColin Finck    /* Acquire CMOS lock */
96*c2c66affSColin Finck    call _HalpAcquireCmosSpinLock@0
97*c2c66affSColin Finck
98*c2c66affSColin Finck    /* Now initialize register A on the CMOS */
99*c2c66affSColin Finck    mov ax, HEX(2D00) OR CMOS_REGISTER_A
100*c2c66affSColin Finck    out CMOS_ADDR, al
101*c2c66affSColin Finck    jmp $+2
102*c2c66affSColin Finck    mov al, ah
103*c2c66affSColin Finck    out CMOS_DATA, al
104*c2c66affSColin Finck    jmp $+2
105*c2c66affSColin Finck
106*c2c66affSColin Finck    /* Read register B */
107*c2c66affSColin Finck    mov ax, CMOS_REGISTER_B
108*c2c66affSColin Finck    out CMOS_ADDR, al
109*c2c66affSColin Finck    jmp $+2
110*c2c66affSColin Finck    in al, CMOS_DATA
111*c2c66affSColin Finck    jmp $+2
112*c2c66affSColin Finck
113*c2c66affSColin Finck    /* Don't touch the LastKnownGoodConfig hack */
114*c2c66affSColin Finck    and al, 1
115*c2c66affSColin Finck    mov ah, al
116*c2c66affSColin Finck
117*c2c66affSColin Finck    /* Enable the interrupt */
118*c2c66affSColin Finck    or ah, HEX(42)
119*c2c66affSColin Finck
120*c2c66affSColin Finck    /* Now write the register B */
121*c2c66affSColin Finck    mov al, CMOS_REGISTER_B
122*c2c66affSColin Finck    out CMOS_ADDR, al
123*c2c66affSColin Finck    jmp $+2
124*c2c66affSColin Finck    mov al, ah
125*c2c66affSColin Finck    out CMOS_DATA, al
126*c2c66affSColin Finck    jmp $+2
127*c2c66affSColin Finck
128*c2c66affSColin Finck    /* Read register C */
129*c2c66affSColin Finck    mov al, CMOS_REGISTER_C
130*c2c66affSColin Finck    out CMOS_ADDR, al
131*c2c66affSColin Finck    jmp $+2
132*c2c66affSColin Finck    in al, CMOS_DATA
133*c2c66affSColin Finck    jmp $+2
134*c2c66affSColin Finck
135*c2c66affSColin Finck    /* Read register D */
136*c2c66affSColin Finck    mov al, CMOS_REGISTER_D
137*c2c66affSColin Finck    out CMOS_ADDR, al
138*c2c66affSColin Finck    jmp $+2
139*c2c66affSColin Finck    in al, CMOS_DATA
140*c2c66affSColin Finck    jmp $+2
141*c2c66affSColin Finck
142*c2c66affSColin Finck    /* Release CMOS lock */
143*c2c66affSColin Finck    mov dword ptr [ebp-12], 0
144*c2c66affSColin Finck    call _HalpReleaseCmosSpinLock@0
145*c2c66affSColin Finck
146*c2c66affSColin Finck    /* Initialize looper */
147*c2c66affSColin Finck    xor eax, eax
148*c2c66affSColin Finck
149*c2c66affSColin Finck    /* Align to 16 bytes */
150*c2c66affSColin Finck    .align 16
151*c2c66affSColin Finck
152*c2c66affSColin Finck    /* Enable interrupts! */
153*c2c66affSColin Finck    sti
154*c2c66affSColin Finck    jmp Looper
155*c2c66affSColin Finck
156*c2c66affSColin Finck    /* Align to 16 bytes */
157*c2c66affSColin Finck    .align 16
158*c2c66affSColin Finck
159*c2c66affSColin Finck    /* Subtract one count */
160*c2c66affSColin FinckLooper:
161*c2c66affSColin Finck    sub eax, 1
162*c2c66affSColin Finck    jnz Looper
163*c2c66affSColin Finck
164*c2c66affSColin Finck    /* ASSERT: If we got here, then the RTC never fired */
165*c2c66affSColin Finck    call _DbgBreakPoint@0
166*c2c66affSColin Finck    jmp Looper
167*c2c66affSColin Finck
168*c2c66affSColin FinckOnlyOnePersonCanWriteHalCode:
169*c2c66affSColin Finck    /*********************** THIS IS THE RTC HANDLER **************************/
170*c2c66affSColin Finck
171*c2c66affSColin Finck    /* Increment the interrupt count and check if this is the first one */
172*c2c66affSColin Finck    inc dword ptr [ebp-12]
173*c2c66affSColin Finck    cmp dword ptr [ebp-12], 1
174*c2c66affSColin Finck    jnz ComputeStall
175*c2c66affSColin Finck
176*c2c66affSColin Finck    /*
177*c2c66affSColin Finck     * It is the first one -- we'll ignore it, since it fires randomly!
178*c2c66affSColin Finck     * Get rid of the old return address and push the new one in (our looper)
179*c2c66affSColin Finck     */
180*c2c66affSColin Finck    pop eax
181*c2c66affSColin Finck    push offset Looper
182*c2c66affSColin Finck
183*c2c66affSColin Finck    /* Acquire CMOS lock */
184*c2c66affSColin Finck    call _HalpAcquireCmosSpinLock@0
185*c2c66affSColin Finck
186*c2c66affSColin Finck    /* Now initialize register A on the CMOS */
187*c2c66affSColin Finck    mov ax, HEX(2D00) OR CMOS_REGISTER_A
188*c2c66affSColin Finck    out CMOS_ADDR, al
189*c2c66affSColin Finck    jmp $+2
190*c2c66affSColin Finck    mov al, ah
191*c2c66affSColin Finck    out CMOS_DATA, al
192*c2c66affSColin Finck    jmp $+2
193*c2c66affSColin Finck
194*c2c66affSColin Finck    /* Read register B */
195*c2c66affSColin Finck    mov ax, CMOS_REGISTER_B
196*c2c66affSColin Finck    out CMOS_ADDR, al
197*c2c66affSColin Finck    jmp $+2
198*c2c66affSColin Finck    in al, CMOS_DATA
199*c2c66affSColin Finck    jmp $+2
200*c2c66affSColin Finck
201*c2c66affSColin Finck    /* Don't touch the LastKnownGoodConfig hack */
202*c2c66affSColin Finck    and al, 1
203*c2c66affSColin Finck    mov ah, al
204*c2c66affSColin Finck
205*c2c66affSColin Finck    /* Enable the interrupt */
206*c2c66affSColin Finck    or ah, HEX(42)
207*c2c66affSColin Finck
208*c2c66affSColin Finck    /* Now write the register B */
209*c2c66affSColin Finck    mov al, CMOS_REGISTER_B
210*c2c66affSColin Finck    out CMOS_ADDR, al
211*c2c66affSColin Finck    jmp $+2
212*c2c66affSColin Finck    mov al, ah
213*c2c66affSColin Finck    out CMOS_DATA, al
214*c2c66affSColin Finck    jmp $+2
215*c2c66affSColin Finck
216*c2c66affSColin Finck    /* Read register C */
217*c2c66affSColin Finck    mov al, CMOS_REGISTER_C
218*c2c66affSColin Finck    out CMOS_ADDR, al
219*c2c66affSColin Finck    jmp $+2
220*c2c66affSColin Finck    in al, CMOS_DATA
221*c2c66affSColin Finck    jmp $+2
222*c2c66affSColin Finck
223*c2c66affSColin Finck    /* Read register D */
224*c2c66affSColin Finck    mov al, CMOS_REGISTER_D
225*c2c66affSColin Finck    out CMOS_ADDR, al
226*c2c66affSColin Finck    jmp $+2
227*c2c66affSColin Finck    in al, CMOS_DATA
228*c2c66affSColin Finck    jmp $+2
229*c2c66affSColin Finck
230*c2c66affSColin Finck    /* Release CMOS lock */
231*c2c66affSColin Finck    call _HalpReleaseCmosSpinLock@0
232*c2c66affSColin Finck
233*c2c66affSColin Finck    /* Dismiss the interrupt */
234*c2c66affSColin Finck    mov al, PIC_EOI
235*c2c66affSColin Finck    out PIC2_COMMAND, al
236*c2c66affSColin Finck    mov al, PIC_SPECIFIC_EOI2
237*c2c66affSColin Finck    out PIC1_COMMAND, al
238*c2c66affSColin Finck
239*c2c66affSColin Finck    /* Reset the counter and return back to the looper */
240*c2c66affSColin Finck    xor eax, eax
241*c2c66affSColin Finck    iretd
242*c2c66affSColin Finck
243*c2c66affSColin Finck    /******************* THIS IS THE 2ND RTC HANDLER **************************/
244*c2c66affSColin FinckComputeStall:
245*c2c66affSColin Finck
246*c2c66affSColin Finck    /* Do the calculation */
247*c2c66affSColin Finck    neg eax
248*c2c66affSColin Finck    xor edx, edx
249*c2c66affSColin Finck    mov ecx, 125000 /* RTC fires every 125 ms */
250*c2c66affSColin Finck    div ecx
251*c2c66affSColin Finck
252*c2c66affSColin Finck    /* Is the remainder 0? */
253*c2c66affSColin Finck    cmp edx, 0
254*c2c66affSColin Finck    jz FoundFactor
255*c2c66affSColin Finck
256*c2c66affSColin Finck    /* Otherwise fix-up the loop count */
257*c2c66affSColin Finck    inc eax
258*c2c66affSColin Finck
259*c2c66affSColin FinckFoundFactor:
260*c2c66affSColin Finck    /* Save the stall scale factor */
261*c2c66affSColin Finck    mov fs:[KPCR_STALL_SCALE_FACTOR], eax
262*c2c66affSColin Finck
263*c2c66affSColin Finck    /* Prepare for interrupt return */
264*c2c66affSColin Finck    pop eax
265*c2c66affSColin Finck    push offset AndItsNotYou
266*c2c66affSColin Finck    mov eax, HEX(13)
267*c2c66affSColin Finck
268*c2c66affSColin Finck    /* Acquire CMOS lock */
269*c2c66affSColin Finck    call _HalpAcquireCmosSpinLock@0
270*c2c66affSColin Finck
271*c2c66affSColin Finck    /* Now initialize register A on the CMOS */
272*c2c66affSColin Finck    mov ax, HEX(2D00) OR CMOS_REGISTER_A
273*c2c66affSColin Finck    out CMOS_ADDR, al
274*c2c66affSColin Finck    jmp $+2
275*c2c66affSColin Finck    mov al, ah
276*c2c66affSColin Finck    out CMOS_DATA, al
277*c2c66affSColin Finck    jmp $+2
278*c2c66affSColin Finck
279*c2c66affSColin Finck    /* Read register B */
280*c2c66affSColin Finck    mov ax, CMOS_REGISTER_B
281*c2c66affSColin Finck    out CMOS_ADDR, al
282*c2c66affSColin Finck    jmp $+2
283*c2c66affSColin Finck    in al, CMOS_DATA
284*c2c66affSColin Finck    jmp $+2
285*c2c66affSColin Finck
286*c2c66affSColin Finck    /* Don't touch the LastKnownGoodConfig hack */
287*c2c66affSColin Finck    and al, 1
288*c2c66affSColin Finck    mov ah, al
289*c2c66affSColin Finck
290*c2c66affSColin Finck    /* Disable the interrupt */
291*c2c66affSColin Finck    or ah, 2
292*c2c66affSColin Finck
293*c2c66affSColin Finck    /* Now write the register B */
294*c2c66affSColin Finck    mov al, CMOS_REGISTER_B
295*c2c66affSColin Finck    out CMOS_ADDR, al
296*c2c66affSColin Finck    jmp $+2
297*c2c66affSColin Finck    mov al, ah
298*c2c66affSColin Finck    out CMOS_DATA, al
299*c2c66affSColin Finck    jmp $+2
300*c2c66affSColin Finck
301*c2c66affSColin Finck    /* Read register C */
302*c2c66affSColin Finck    mov al, CMOS_REGISTER_C
303*c2c66affSColin Finck    out CMOS_ADDR, al
304*c2c66affSColin Finck    jmp $+2
305*c2c66affSColin Finck    in al, CMOS_DATA
306*c2c66affSColin Finck    jmp $+2
307*c2c66affSColin Finck
308*c2c66affSColin Finck    /* Release CMOS lock */
309*c2c66affSColin Finck    call _HalpReleaseCmosSpinLock@0
310*c2c66affSColin Finck
311*c2c66affSColin Finck    /* Dismiss the interrupt */
312*c2c66affSColin Finck    mov al, PIC_EOI
313*c2c66affSColin Finck    out PIC2_COMMAND, al
314*c2c66affSColin Finck    mov al, PIC_SPECIFIC_EOI2
315*c2c66affSColin Finck    out PIC1_COMMAND, al
316*c2c66affSColin Finck
317*c2c66affSColin Finck    /* Disable interrupts on return */
318*c2c66affSColin Finck    and word ptr [esp+8], NOT EFLAGS_INTERRUPT_MASK
319*c2c66affSColin Finck    iretd
320*c2c66affSColin Finck
321*c2c66affSColin Finck    /************************* WE ARE BACK FROM RTC ***************************/
322*c2c66affSColin FinckAndItsNotYou:
323*c2c66affSColin Finck
324*c2c66affSColin Finck    /* Restore the IDT */
325*c2c66affSColin Finck    pop ecx
326*c2c66affSColin Finck    pop [ecx+4]
327*c2c66affSColin Finck    pop [ecx]
328*c2c66affSColin Finck
329*c2c66affSColin Finck    /* Restore the mask */
330*c2c66affSColin Finck    pop eax
331*c2c66affSColin Finck    out PIC1_DATA, al
332*c2c66affSColin Finck    shr eax, 8
333*c2c66affSColin Finck    out PIC2_DATA, al
334*c2c66affSColin Finck
335*c2c66affSColin Finck    /* Restore EFLAGS */
336*c2c66affSColin Finck    popfd
337*c2c66affSColin Finck
338*c2c66affSColin Finck    /* Restore stack and return */
339*c2c66affSColin Finck    mov esp, ebp
340*c2c66affSColin Finck    pop ebp
341*c2c66affSColin Finck    ret
342*c2c66affSColin Finck
343*c2c66affSColin Finck
344*c2c66affSColin Finck#ifndef _MINIHAL_
345*c2c66affSColin FinckPUBLIC _KeStallExecutionProcessor@4
346*c2c66affSColin Finck_KeStallExecutionProcessor@4:
347*c2c66affSColin Finck
348*c2c66affSColin Finck    /* Get the number of microseconds required */
349*c2c66affSColin Finck    mov ecx, [esp+4]
350*c2c66affSColin Finck    jecxz Done
351*c2c66affSColin Finck
352*c2c66affSColin Finck    /* Multiply by the stall factor */
353*c2c66affSColin Finck    mov eax, fs:[KPCR_STALL_SCALE_FACTOR]
354*c2c66affSColin Finck    mul ecx
355*c2c66affSColin Finck
356*c2c66affSColin Finck    /* Jump to subtraction loop */
357*c2c66affSColin Finck    jmp SubtractLoop
358*c2c66affSColin Finck
359*c2c66affSColin Finck    /* Align to 16 bytes */
360*c2c66affSColin Finck    .align 16
361*c2c66affSColin Finck
362*c2c66affSColin Finck    /* Subtract one count */
363*c2c66affSColin FinckSubtractLoop:
364*c2c66affSColin Finck    sub eax, 1
365*c2c66affSColin Finck    jnz SubtractLoop
366*c2c66affSColin Finck
367*c2c66affSColin FinckDone:
368*c2c66affSColin Finck    /* Return */
369*c2c66affSColin Finck    ret 4
370*c2c66affSColin Finck#endif
371*c2c66affSColin Finck
372*c2c66affSColin FinckEND
373