434 lines
12 KiB
ArmAsm
434 lines
12 KiB
ArmAsm
// .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 kuriyama@oa2.kb.nec.co.jp 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
|