// TITLE("Interval and Profile Clock Interrupts") //++ // // Copyright (c) 1991-1993 Microsoft Corporation // // Module Name: // // x4clock.s // // Abstract: // // This module implements the code necessary to field and process the // interval and profile clock interrupts on a MIPS R4000 system. // //-- #include "halmips.h" #include "faldef.h" SBTTL("System Clock Interrupt - Processor 0") //++ // // Routine Description: // // This routine is entered as the result of an interrupt generated by // the interval timer. Its function is to acknowledge the interrupt and // transfer control to the standard system routine to update the system // time and the execution time of the current thread and process. // // Arguments: // // s8 - Supplies a pointer to a trap frame. // // Return Value: // // None. // //-- .struct 0 CiArgs: .space 4 * 4 // saved arguments .space 3 * 4 // fill CiRa: .space 4 // saved return address CiFrameLength: // NESTED_ENTRY(HalpClockInterrupt0, CiFrameLength, zero) subu sp,sp,CiFrameLength // allocate stack frame sw ra,CiRa(sp) // save return address PROLOGUE_END .set noreorder // // Clear Timer interrupt by reading // TimerIntAck register in PMP chip // only if this is PMP_V3 or later. // NOTE: There are NO PMP_V1 in existence, // therefore only checking that PMP_V2 // or NOT PMP_V2. // la t0, HalpPmpRevision lw t1, 0(t0) li t2, 2 beq t1, t2, 2f nop lw t0, HalpPmpTimerIntAck lw t0, 0(t0) 2: .set reorder move a0,s8 // set address of trap frame lw a1,HalpCurrentTimeIncrement // set current time increment lw t0,__imp_KeUpdateSystemTime // update system time jal t0 // // // At each clock interrupt the next time increment is moved to the current // time increment to "pipeline" the update of the current increment at the // correct time. If the next interval count is nonzero, then the new time // increment is moved to the next time increment and the next interval count // register is loaded with the specified interval count minus one (i.e., ms). // lw t0,KdDebuggerEnabled // get address of debugger enable lw t1,HalpNextIntervalCount // get next interval count lw t2,HalpNextTimeIncrement // get the next increment value lbu t0,0(t0) // get debugger enable flag lw t3,HalpNewTimeIncrement // get new new time increment value lw ra,CiRa(sp) // restore return address or t4,t1,t0 // set interval count or debugger? sw t2,HalpCurrentTimeIncrement // set current increment value bne zero,t4,20f // if ne, interval change or debugger addu sp,sp,CiFrameLength // deallocate stack frame j ra // return // // The interval count must be changed or the debugger is enabled. // 20: beq zero,t1,30f // if eq, not interval count change sw zero,HalpNextIntervalCount // clear next interval count .set noreorder // // Determine which version of // the PMP we have so we can // update the correct counter // in the 82374. // // NOTE: Any machine with PMP_V2 // uses Counter 0. Any machine // with PMP_V3 or better uses // Counter 2. // la a0, HalpPmpRevision lw a0, 0(a0) li a1, 2 beq a0, a1, 3f nop // // Set next interval count for // Timer 1, Counter 2 // lw a0, HalpEisaControlBase li a2, 0xB6 // Counter2, r/w LSB then MSB, Mode 3 sb a2, 0x43(a0) sb t1, 0x42(a0) srl a1, t1, 8 b 4f sb a1, 0x42(a0) 3: // // Set next interval count for // Timer 1, Counter 0 // lw a0, HalpEisaControlBase li a2, 0x36 // Counter0, r/w LSB then MSB, Mode 3 sb a2, 0x43(a0) sb t1, 0x40(a0) srl a1, t1, 8 sb a1, 0x40(a0) 4: .set reorder sw t3,HalpNextTimeIncrement // set next time increment value 30: beq zero,t0,40f // if eq, debugger not enabled jal KdPollBreakIn // check if breakin is requested beq zero,v0,40f // if eq, no breakin requested li a0,DBG_STATUS_CONTROL_C // break in and send jal DbgBreakPointWithStatus // status to debugger 40: lw ra,CiRa(sp) // restore return address addu sp,sp,CiFrameLength // deallocate stack frame j ra // return .end HalpClockInterrupt0 SBTTL("System Clock Interrupt - Processor N") //++ // // Routine Description: // // This routine is entered as the result of an interrupt generated by // the interval timer. Its function is to acknowledge the interrupt // and transfer control to the standard system routine to update the // execution time of the current thread and process. // // Arguments: // // s8 - Supplies a pointer to a trap frame. // // Return Value: // // None. // //-- LEAF_ENTRY(HalpClockInterrupt1) // // clear Timer interrupt by reading // TimerIntAck register in PMP chip // only if this is not the first // version of the PMP chip. // lw t0, HalpPmpTimerIntAckProcB lw t0, 0(t0) move a0,s8 // set address of trap frame lw t1,__imp_KeUpdateRunTime // update system runtime j t1 .end HalpClockInterrupt1 SBTTL("Profile Clock Interrupt") //++ // // Routine Description: // // This routine is entered as the result of an interrupt generated by the // profile clock. Its function is to acknowledge the profile interrupt, // compute the next compare value, update the performance counter, and // transfer control to the standard system routine to process any active // profiles. // // Arguments: // // s8 - Supplies a pointer to a trap frame. // // Return Value: // // None. // //-- LEAF_ENTRY(HalpProfileInterrupt) .set noreorder .set noat mfc0 t1,count // get current count value mfc0 t0,compare // get current comparison value addu t1,t1,8 // factor in lost cycles subu t1,t1,t0 // compute initial count value mtc0 t0,compare // dismiss interrupt mtc0 t1,count // set new count register value .set at .set reorder lw t1,KiPcr + PcPrcb(zero) // get current processor block address la t2,HalpPerformanceCounter // get performance counter address lbu t1,PbNumber(t1) // get processor number sll t1,t1,3 // compute address of performance count addu t1,t1,t2 // lw t2,LiLowPart(t1) // get low part of performance count lw t3,LiHighPart(t1) // get high part of performance count addu t2,t2,t0 // update low part of performance count sw t2,LiLowPart(t1) // store low part of performance count sltu t4,t2,t0 // generate carry into high part addu t3,t3,t4 // update high part of performance count sw t3,LiHighPart(t1) // store high part of performance count move a0,s8 // set address of trap frame lw t4,__imp_KeProfileInterrupt // process profile interrupt j t4 // .end HalpProfileInterrupt SBTTL("Read Count Register") //++ // // ULONG // HalpReadCountRegister ( // VOID // ); // // Routine Description: // // This routine reads the current value of the count register and // returns the value. // // Arguments: // // None. // // Return Value: // // Current value of the count register. // //-- LEAF_ENTRY(HalpReadCountRegister) .set noreorder .set noat mfc0 v0,count // get count register value .set at .set reorder j ra // return .end HalpReadCountRegister SBTTL("Write Compare Register And Clear") //++ // // ULONG // HalpWriteCompareRegisterAndClear ( // IN ULONG Value // ); // // Routine Description: // // This routine reads the current value of the count register, writes // the value of the compare register, clears the count register, and // returns the previous value of the count register. // // Arguments: // // Value - Supplies the value written to the compare register. // // Return Value: // // Previous value of the count register. // //-- LEAF_ENTRY(HalpWriteCompareRegisterAndClear) .set noreorder .set noat mfc0 v0,count // get count register value mtc0 a0,compare // set compare register value li t0,7 // set lost cycle count mtc0 t0,count // set count register to zero .set at .set reorder j ra // return .end HalpWriteCompareRegisterAndClear