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