|
|
// .ident "@(#) x4clock.s 1.1 95/09/28 18:39:17 nec" // TITLE("Interval and Profile Clock Interrupts") //++ // // Copyright (c) 1991 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. // // Author: // // David N. Cutler (davec) 26-Apr-1991 // // Environment: // // Kernel mode only. // // Revision History: // // M001 Fri Feb 17 17:48:03 JST 1995 kbnes!kuriyama (A) // - Change HalpClockInterrupt0(() // for dump switch support. // // S002 Tue Feb 21 21:24:13 JST 1995 kbnes!kuriyama (A) // - use HalpNMIFlag // // S003 Wed Feb 22 11:18:59 JST 1995 kbnes!kuriyama (A) // - enter kernel debugger when NMI only checked version // // S004 Wed Feb 22 14:25:20 JST 1995 kbnes!kuriyama (A) // - enter kernel debugger when NMI free version // // S005 Sat Mar 18 20:30:05 JST 1995 kbnes!kuriyama (A) // - nmi logic change // // M006 [email protected] Wed Jun 28 14:16:29 JST 1995 // - change nmi logic // // M007 Thu Jul 20 19:31:41 JST 1995 kbnes!kisimoto // - Merge build 1057 // //--
#include "halmips.h"
#if defined(_DUO_)
#include "duodef.h"
#endif
#if defined(_JAZZ_)
#include "jazzdef.h"
#endif
// M001 +++ #if defined(_R94A_)
.extern HalpNMIFlag .extern HalpNMIInterrupt .extern HalpDumpNMIFlag //S002 #endif //_R94A_
// M001 ---
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
// M001 +++ #if defined(_R94A_)
// // check if dump swich flag set. //
la t0,HalpNMIFlag // set NMI flag address li t1,0xa0000000 // set KSEG1_BASE or t0,t0,t1 lw t1,(t0) // load NMI flag nop beq t1,zero,10f nop sw zero,(t0)
lw t0,KdDebuggerEnabled // get address of debugger enable nop lbu t0,0(t0) // get debugger enable flag nop beq zero,t0,5f // if eq, debugger not enabled nop nop beq zero,v0,40f // if eq, no breakin requested nop break BREAKIN_BREAKPOINT // break into the debugger nop 5:
// S002 +++ la t0,HalpDumpNMIFlag // set Dump NMI flag address li t1,0xa0000000 // set KSEG1_BASE or t0,t0,t1 // lw a0,(t0) // load Dump NMI flag nop // // S003 +++ sw zero,(t0) // clear Dump NMI flag nop // // S003 --- // S005 lw zero,DMA_VIRTUAL_BASE + 0x58 // clear acknowledge // M006 // S002 --- jal HalpNMIInterrupt // jump to NMI routine nop // 10: #endif // _R94A_
// M001 ---
#if defined(_DUO_)
lw t0,DMA_VIRTUAL_BASE + 0x58 // acknowledge timer interrupt
#endif
#if defined(_JAZZ_)
lw t0,DMA_VIRTUAL_BASE + 0x230 // acknowledge timer interrupt
#endif
.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 //
// // The following code is a work around for a bug in the Fusion machines // where the clock interrupt is not dismissed by reading the acknowledge // register. //
#if defined(_JAZZ_)
.set noreorder .set noat mfc0 t0,cause // read the cause register lw t1,HalpEisaControlBase // get EISA control base address sll t0,t0,31 - (CAUSE_INTPEND + CLOCK_LEVEL - 1) // isolate clock bit bgez t0,10f // if gez, no clock interrupt pending li t2,0x2 // get NMI port enable bit lb t3,0x70(t1) // save EISA NMI interrupt disable lb t4,0x461(t1) // save EISA extended NMI status sb zero,0x70(t1) // clear EISA NMI interrupt disable sb t2,0x461(t1) // set EISA NMI port enable sb zero,0x462(t1) // generate EISA NMI interrupt sb zero,0x461(t1) // clear EISA extended NMI status sb t2,0x461(t1) // lb zero,0x461(t1) // synchronize clear operatin sb t3,0x70(t1) // restore EISA NMI interupt disable sb t4,0x461(t1) // restore EISA exteneed NMI status lb zero,0x461(t1) // synchronize restore operation .set at .set reorder
10: //
#endif
// // 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: sw zero,HalpNextIntervalCount // clear next interval count beq zero,t1,30f // if eq, not interval count change subu t1,t1,1 // compute millisecond interval count
.set noreorder
#if defined(_DUO_)
sw t1,DMA_VIRTUAL_BASE + 0x1a8 // set next interval count
#endif
#if defined(_JAZZ_)
sw t1,DMA_VIRTUAL_BASE + 0x228 // set next interval count
#endif
.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)
#if defined(_DUO_)
lw t0,DMA_VIRTUAL_BASE + 0x58 // acknowledge timer interrupt move a0,s8 // set address of trap frame lw t1,__imp_KeUpdateRunTime // update system runtime j t1 //
#else // M007
j ra //
#endif
.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
#if defined(NT_UP)
la t1,HalpPerformanceCounter // get performance counter address
#else
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 //
#endif
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
|