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