Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

368 lines
12 KiB

// TITLE("Interval and Profile Clock Interrupts")
//++
//
// Copyright (c) 1991-1994 Microsoft Corporation
//
// Module Name:
//
// r98clock.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 "r98bdef.h"
#define ECC_ERROR_COUNT_LIMIT 1
#define CNFG_CONNECT4_MAGELLAN0 0x00800000 //it is MAGELLAN 0
#define CNFG_CONNECT4_MAGELLAN1 0x00400000 //it is MAGELLAN 1
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:
//
// a0 - 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
sw zero,KSEG1_BASE + COLUMNBS_LPHYSICAL_BASE+0x50(zero) // Columnbs TOVCT1 reg.
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.
//
la t0,HalpStartWDTFlag
lw t1,0x0(t0)
beq zero,t1,2f
la t2,HalpSetWDTCount
lw t1,0x0(t2)
sw t1,KSEG1_BASE + COLUMNBS_LPHYSICAL_BASE+0x80(zero) // Columnbs reg.
li t1,0x00000002
sw t1,KSEG1_BASE + COLUMNBS_LPHYSICAL_BASE+0x90(zero) // Columnbs reg.
sw zero,0x0(t0)
2: la t0,HalpStopWDTFlag
lw t1,0x0(t0)
beq zero,t1,3f
li t1,0x00000001
sw t1,KSEG1_BASE + COLUMNBS_LPHYSICAL_BASE+0x90(zero) // Columnbs reg.
sw zero,0x0(t0)
3: la t0,HalpSetWDTFlag
lw t1,0x0(t0)
beq zero,t1,4f
li t1,0x00000002
sw t1,KSEG1_BASE + COLUMNBS_LPHYSICAL_BASE+0x90(zero) // Columnbs reg.
sw zero,0x0(t0)
4:
//
// Check ECC 1bit error flag.
//
lw t0,HalpECC1bitDisableTime // get value of disable time
beq zero,t0,10f // if ne, check ecc 1bit
lw t1,HalpCurrentTimeIncrement // get current time increment
subu t0,t0,t1 // declement disable time
sw t0,HalpECC1bitDisableTime //
blez t0,5f // if lez, enable ecc 1bit
beq zero,zero,10f // not lez,
5: sw zero,HalpECC1bitDisableTime // clear disable time
li t0,ECC_ERROR_COUNT_LIMIT // set new flag
sw t0,HalpECC1bitDisableFlag //
la t1,KSEG1_BASE+MAGELLAN_0_PHYSICAL_BASE+MAGELLAN_ERRI_OFFSET
lw t2,HalpPhysicalNode // check connect to Magellan
and t0,t2,CNFG_CONNECT4_MAGELLAN0
bne t0,zero,7f
lw t0,0x0(t1)
and t0,ECC_1BIT_ENABLE
sw t0,0x0(t1) // enable ECC 1bit error
7:
and t0,t2,CNFG_CONNECT4_MAGELLAN1
bne t0,zero,10f
la t1,KSEG1_BASE+MAGELLAN_1_PHYSICAL_BASE+MAGELLAN_ERRI_OFFSET
lw t0,0x0(t1)
and t0,ECC_1BIT_ENABLE
sw t0,0x0(t1) // enable ECC 1bit error
//
// 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).
//
10: 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
sw t1,KSEG1_BASE + COLUMNBS_LPHYSICAL_BASE+0x40(zero) // Columnbs TMSR1 reg.
.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
break BREAKIN_BREAKPOINT // break into the 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:
//
// a0 - Supplies a pointer to a trap frame.
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(HalpClockInterrupt1)
sw zero,KSEG1_BASE + COLUMNBS_LPHYSICAL_BASE+0x50(zero) // Columnbs TOVCT1 reg.
lw t1,KiPcr + PcPrcb(zero) // get current processor block address
#if 0
la t2,HalpChangeIntervalFlg // get change flag of timer interval
lbu t1,PbNumber(t1) // get processor number
add t2,t1,t2 // check flag
lb t1,0x0(t2) // get change flag of this CPU
beq t1,zero,10f // if eq, no change timer interval
sb zero,0x0(t2) // clear change flag of timer interval
lw t1,HalpChangeIntervalCount // get next interval count
sw t1,KSEG1_BASE + COLUMNBS_LPHYSICAL_BASE+0x40(zero) // Columnbs TMSR1 reg.
10:
#endif
lw t1,KiPcr + PcPrcb(zero) // get current processor block address
lbu t4,PbNumber(t1) // get processor number
sll t4,t4,2 // compute address
la t0,HalpStartWDTFlag
addu t0,t0,t4 //
lw t1,0x0(t0)
beq zero,t1,12f
la t2,HalpSetWDTCount
addu t2,t2,t4 //
lw t1,0x0(t2)
sw t1,KSEG1_BASE + COLUMNBS_LPHYSICAL_BASE+0x80(zero) // Columnbs reg.
li t1,0x00000002
sw t1,KSEG1_BASE + COLUMNBS_LPHYSICAL_BASE+0x90(zero) // Columnbs reg.
sw zero,0x0(t0)
12: la t0,HalpStopWDTFlag
addu t0,t0,t4 //
lw t1,0x0(t0)
beq zero,t1,14f
li t1,0x00000001
sw t1,KSEG1_BASE + COLUMNBS_LPHYSICAL_BASE+0x90(zero) // Columnbs reg.
sw zero,0x0(t0)
14: la t0,HalpSetWDTFlag
addu t0,t0,t4 //
lw t1,0x0(t0)
beq zero,t1,16f
li t1,0x00000002
sw t1,KSEG1_BASE + COLUMNBS_LPHYSICAL_BASE+0x90(zero) // Columnbs reg.
sw zero,0x0(t0)
16: 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:
//
// a0 - Supplies a pointer to a trap frame.
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(HalpProfileInterrupt)
.set noreorder
.set noat
li t0,KSEG1_BASE + COLUMNBS_LPHYSICAL_BASE+0x70
sw zero 0x0(t0)
mfc0 t0,count // get current count value
addu t1,zero,3 // set initial count value
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
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