398 lines
12 KiB
ArmAsm
398 lines
12 KiB
ArmAsm
//++
|
||
//
|
||
// Copyright (c) 1994 Microsoft Corporation
|
||
//
|
||
// Module Name:
|
||
//
|
||
// ev5ints.s
|
||
//
|
||
// Abstract:
|
||
//
|
||
// This module implements EV5-specific interrupt handlers.
|
||
// (the performance counters)
|
||
//
|
||
// Author:
|
||
//
|
||
// John Vert (jvert) 15-Nov-1994
|
||
// Steve Brooks 14-Feb-1994 (modified from ev4ints.s)
|
||
//
|
||
// Environment:
|
||
//
|
||
// Kernel mode only.
|
||
//
|
||
// Revision History:
|
||
//
|
||
//--
|
||
#include "halalpha.h"
|
||
|
||
#define PC0_SECONDARY_VECTOR 11
|
||
#define PC1_SECONDARY_VECTOR 13
|
||
#define PC2_SECONDARY_VECTOR 16 // SjBfix. This is actually PC3_VECTOR
|
||
#define PcProfileCount0 PcHalReserved+20
|
||
#define PcProfileCount1 PcProfileCount0+4
|
||
#define PcProfileCount2 PcProfileCount1+4
|
||
#define PcProfileCountReload0 PcProfileCount2+4
|
||
#define PcProfileCountReload1 PcProfileCountReload0+4
|
||
#define PcProfileCountReload2 PcProfileCountReload1+4
|
||
|
||
.struct 0
|
||
.space 8 // reserved for alignment
|
||
PrRa: .space 8 // space for return address
|
||
PrFrameLength: //
|
||
|
||
SBTTL("Performance Counter 0 Interrupt")
|
||
//++
|
||
//
|
||
// VOID
|
||
// HalpPerformanceCounter0Interrupt
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This function is executed as the result of an interrupt from the
|
||
// internal microprocessor performance counter 0. The interrupt
|
||
// may be used to signal the completion of a profile event.
|
||
// If profiling is current active, the function determines if the
|
||
// profile interval has expired and if so dispatches to the standard
|
||
// system routine to update the system profile time. If profiling
|
||
// is not active then the function performs a secondary dispatch for
|
||
// performance counter 0.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for
|
||
// the interrupt.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// TRUE is returned.
|
||
//
|
||
//--
|
||
|
||
NESTED_ENTRY(HalpPerformanceCounter0Interrupt, PrFrameLength, zero )
|
||
|
||
lda sp, -PrFrameLength(sp) // allocate a stack frame
|
||
stq ra, PrRa(sp) // save the return address
|
||
|
||
PROLOGUE_END //
|
||
|
||
call_pal rdpcr // v0 = pcr base address
|
||
|
||
ldl t0, PcProfileCount0(v0) // capture the current profile count
|
||
beq t0, 20f // if eq, profiling not active
|
||
|
||
//
|
||
// Profiling is active. Decrement the interval count and if it has
|
||
// reached zero then call the kernel profile routine.
|
||
//
|
||
|
||
subl t0, 1, t0 // decrement the interval count
|
||
bne t0, 10f // if ne, interval has not expired
|
||
|
||
//
|
||
// The profile interval has expired. Reset the profile interval count
|
||
// and process the profile interrupt.
|
||
//
|
||
|
||
ldl t0, PcProfileCountReload0(v0) // get the new tick count
|
||
stl t0, PcProfileCount0(v0) // reset the profile interval count
|
||
|
||
ldl a1, HalpProfileSource0
|
||
bis fp, zero, a0 // pass trap frame pointer
|
||
ldl t1, __imp_KeProfileInterruptWithSource
|
||
jsr ra, (t1) // process the profile interrupt
|
||
|
||
br zero, 40f // common return
|
||
|
||
//
|
||
// The profile interval has not expired. Update the decremented count.
|
||
//
|
||
|
||
10:
|
||
stl t0, PcProfileCount0(v0) // update profile interval count
|
||
br zero, 40f // common return
|
||
|
||
//
|
||
// Profiling is not active. Therefore, this interrupt was caused by
|
||
// a performance counter driver. Deliver a secondary dispatch.
|
||
//
|
||
|
||
20:
|
||
|
||
ldil a0, PC0_SECONDARY_VECTOR // get IDT vector for secondary
|
||
s4addl a0, v0, a0 // a0 = PCR + IDT index
|
||
ldl a0, PcInterruptRoutine(a0) // get service routine address
|
||
jsr ra, (a0) // call interrupt service routine
|
||
|
||
//
|
||
// Setup for return.
|
||
//
|
||
|
||
40:
|
||
ldil v0, TRUE // set return value = TRUE
|
||
ldq ra, PrRa(sp) // restore return address
|
||
lda sp, PrFrameLength(sp) // deallocate the stack frame
|
||
ret zero, (ra) // return
|
||
|
||
.end HalpPerformanceCounter0Interrupt
|
||
|
||
|
||
SBTTL("Performance Counter 1 Interrupt")
|
||
//++
|
||
//
|
||
// VOID
|
||
// HalpPerformanceCounter1Interrupt
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This function is executed as the result of an interrupt from the
|
||
// internal microprocessor performance counter 1. The interrupt
|
||
// may be used to signal the completion of a profile event.
|
||
// If profiling is current active, the function determines if the
|
||
// profile interval has expired and if so dispatches to the standard
|
||
// system routine to update the system profile time. If profiling
|
||
// is not active then the function performs a secondary dispatch for
|
||
// performance counter 1.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for
|
||
// the interrupt.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// TRUE is returned.
|
||
//
|
||
//--
|
||
|
||
NESTED_ENTRY(HalpPerformanceCounter1Interrupt, PrFrameLength, zero )
|
||
|
||
lda sp, -PrFrameLength(sp) // allocate a stack frame
|
||
stq ra, PrRa(sp) // save the return address
|
||
|
||
PROLOGUE_END //
|
||
|
||
call_pal rdpcr // v0 = pcr base address
|
||
|
||
ldl t0, PcProfileCount1(v0) // capture the current profile count
|
||
beq t0, 20f // if eq, profiling not active
|
||
|
||
//
|
||
// Profiling is active. Decrement the interval count and if it has
|
||
// reached zero then call the kernel profile routine.
|
||
//
|
||
|
||
subl t0, 1, t0 // decrement the interval count
|
||
bne t0, 10f // if ne, interval has not expired
|
||
|
||
//
|
||
// The profile interval has expired. Reset the profile interval count
|
||
// and process the profile interrupt.
|
||
//
|
||
|
||
ldl t0, PcProfileCountReload1(v0) // get the new tick count
|
||
stl t0, PcProfileCount1(v0) // reset the profile interval count
|
||
|
||
ldl a1, HalpProfileSource1
|
||
bis fp, zero, a0 // pass trap frame pointer
|
||
ldl t1, __imp_KeProfileInterruptWithSource
|
||
jsr ra, (t1) // process the profile interrupt
|
||
|
||
br zero, 40f // common return
|
||
|
||
//
|
||
// The profile interval has not expired. Update the decremented count.
|
||
//
|
||
|
||
10:
|
||
stl t0, PcProfileCount1(v0) // update profile interval count
|
||
br zero, 40f // common return
|
||
|
||
//
|
||
// Profiling is not active. Therefore, this interrupt was caused by
|
||
// a performance counter driver. Deliver a secondary dispatch.
|
||
//
|
||
|
||
20:
|
||
|
||
ldil a0, PC1_SECONDARY_VECTOR // get IDT vector for secondary
|
||
s4addl a0, v0, a0 // a0 = PCR + IDT index
|
||
ldl a0, PcInterruptRoutine(a0) // get service routine address
|
||
jsr ra, (a0) // call interrupt service routine
|
||
|
||
//
|
||
// Setup for return.
|
||
//
|
||
|
||
40:
|
||
ldil v0, TRUE // set return value = TRUE
|
||
ldq ra, PrRa(sp) // restore return address
|
||
lda sp, PrFrameLength(sp) // deallocate the stack frame
|
||
ret zero, (ra) // return
|
||
|
||
.end HalpPerformanceCounter1Interrupt
|
||
|
||
SBTTL("Performance Counter 2 Interrupt")
|
||
//++
|
||
//
|
||
// VOID
|
||
// HalpPerformanceCounter2Interrupt
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This function is executed as the result of an interrupt from the
|
||
// internal microprocessor performance counter 2. The interrupt
|
||
// may be used to signal the completion of a profile event.
|
||
// If profiling is current active, the function determines if the
|
||
// profile interval has expired and if so dispatches to the standard
|
||
// system routine to update the system profile time. If profiling
|
||
// is not active then the function performs a secondary dispatch for
|
||
// performance counter 2.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for
|
||
// the interrupt.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// TRUE is returned.
|
||
//
|
||
//--
|
||
|
||
NESTED_ENTRY(HalpPerformanceCounter2Interrupt, PrFrameLength, zero )
|
||
|
||
lda sp, -PrFrameLength(sp) // allocate a stack frame
|
||
stq ra, PrRa(sp) // save the return address
|
||
|
||
PROLOGUE_END //
|
||
|
||
call_pal rdpcr // v0 = pcr base address
|
||
|
||
ldl t0, PcProfileCount2(v0) // capture the current profile count
|
||
beq t0, 20f // if eq, profiling not active
|
||
|
||
//
|
||
// Profiling is active. Decrement the interval count and if it has
|
||
// reached zero then call the kernel profile routine.
|
||
//
|
||
|
||
subl t0, 1, t0 // decrement the interval count
|
||
bne t0, 10f // if ne, interval has not expired
|
||
|
||
//
|
||
// The profile interval has expired. Reset the profile interval count
|
||
// and process the profile interrupt.
|
||
//
|
||
|
||
ldl t0, PcProfileCountReload2(v0) // get the new tick count
|
||
stl t0, PcProfileCount2(v0) // reset the profile interval count
|
||
|
||
ldl a1, HalpProfileSource2
|
||
bis fp, zero, a0 // pass trap frame pointer
|
||
ldl t1, __imp_KeProfileInterruptWithSource
|
||
jsr ra, (t1) // process the profile interrupt
|
||
|
||
br zero, 40f // common return
|
||
|
||
//
|
||
// The profile interval has not expired. Update the decremented count.
|
||
//
|
||
|
||
10:
|
||
stl t0, PcProfileCount2(v0) // update profile interval count
|
||
br zero, 40f // common return
|
||
|
||
//
|
||
// Profiling is not active. Therefore, this interrupt was caused by
|
||
// a performance counter driver. Deliver a secondary dispatch.
|
||
//
|
||
|
||
20:
|
||
|
||
ldil a0, PC2_SECONDARY_VECTOR // get IDT vector for secondary
|
||
s4addl a0, v0, a0 // a0 = PCR + IDT index
|
||
ldl a0, PcInterruptRoutine(a0) // get service routine address
|
||
jsr ra, (a0) // call interrupt service routine
|
||
|
||
//
|
||
// Setup for return.
|
||
//
|
||
|
||
40:
|
||
ldil v0, TRUE // set return value = TRUE
|
||
ldq ra, PrRa(sp) // restore return address
|
||
lda sp, PrFrameLength(sp) // deallocate the stack frame
|
||
ret zero, (ra) // return
|
||
|
||
.end HalpPerformanceCounter2Interrupt
|
||
|
||
//++
|
||
//
|
||
// ULONGLONG
|
||
// HalpRead21164PerformanceCounter(
|
||
// VOID
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// Read the processor performance counter register
|
||
//
|
||
// Arguments:
|
||
//
|
||
// None.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// The current value of the performance counter register.
|
||
//
|
||
//--
|
||
|
||
LEAF_ENTRY(HalpRead21164PerformanceCounter)
|
||
|
||
bis zero, 1, a1 // indicate read operation
|
||
call_pal wrperfmon // read the performance counter
|
||
|
||
ret zero, (ra) // return to caller
|
||
|
||
.end HalpRead21164PerformanceCounter
|
||
|
||
|
||
//++
|
||
//
|
||
// VOID
|
||
// HalpWrite21164PerformanceCounter(
|
||
// ULONGLONG PmCtr
|
||
// ULONG CboxMux1
|
||
// ULONG CboxMux2
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// Write the processor performance counter register
|
||
//
|
||
// Arguments:
|
||
//
|
||
// PmCtr(a0) - value to be written to the performance counter
|
||
// CboxMux1(a1) - value to be written to Cbox mux 1 select (optional)
|
||
// CboxMux2(a2) - value to be written to Cbox mux 2 select (optional)
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
LEAF_ENTRY(HalpWrite21164PerformanceCounter)
|
||
|
||
bis zero, a2, a3 // move arguments up
|
||
bis zero, a1, a2 //
|
||
bis zero, zero, a1 // indicate write operation
|
||
call_pal wrperfmon // write the performance counter
|
||
|
||
ret zero, (ra)
|
||
|
||
.end HalpWrite21164PerformanceCounter
|