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