windows-nt/Source/XPSP1/NT/base/hals/halia64/ia64/i64prfle.c

1648 lines
40 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
i64prfle.c
Abstract:
This module implements the IA64 Hal Profiling using the performance
counters within the core of the first IA64 Processor Merced, aka Itanium.
This module is appropriate for all machines based on microprocessors using
the Merced core.
With the information known at this development time, this module tries to
consider the future IA64 processor cores by encapsulating the differences
in specific micro-architecture data structures.
Furthermore, with the implementation of the new NT ACPI Processor driver, this
implementation will certainly change in the coming months.
N.B. - This module assumes that all processors in a multiprocessor
system are running the microprocessor at the same clock speed.
Author:
Thierry Fevrier 08-Feb-2000
Environment:
Kernel mode only.
Revision History:
--*/
#include "halp.h"
//
// Assumptions for the current implementation - 02/08/2000 :
// These assumptions will be re-evaluated and worked out if required.
//
// - Respect and satisfy as much possible the Profiling Sources interface
// already defined by NT and HAL.
//
// - All processors in a multiprocessor system are running the microprocessor
// at the same invariant clock speed.
//
// - All processors are configured with the same set of profiling counters.
// XXTF - 04/01/2000 - This assumption is being re-worked and will disappear.
//
// - Profiling is based on the processor monitored events and if possible
// on derived events.
//
// - A monitored event can only be enabled on one performance counter at a time.
//
//
// IA64 performance counters defintions:
// - event counters
// - EARS
// - BTBs
// - ...
//
#include "ia64prof.h"
#if defined(_MCKINLEY_)
#include "mckinley.h"
#else // Default IA64 - Merced
#include "merced.h"
#endif //
extern ULONGLONG HalpITCFrequency;
extern HALP_PROFILE_MAPPING HalpProfileMapping[];
#define HalpDisactivateProfileSource( _ProfileSource ) ((_ProfileSource) = ProfileIA64Maximum)
#define HalpIsProfileSourceActive( _ProfileSource ) ((_ProfileSource) != ProfileIA64Maximum)
#define HalpIsProfileMappingInvalid( _ProfileMapping ) (!(_ProfileMapping) || ((_ProfileMapping)->Supported == FALSE))
VOID
HalpEnableProfileCounting (
VOID
)
/*++
Routine Description:
This function enables the profile counters to increment.
This function is the counterpart of HalpDisableProfileCounting().
Arguments:
None.
Return Value:
None.
--*/
{
ULONGLONG Data, ClearStatusMask;
//
// Clear PMC0.fr - bit 0.
// Clear PMCO,1,2,3 OverFlow Bits.
//
ClearStatusMask = 0xFFFFFFFFFFFFFF0E; // XXTF - FIXFIX - Merced specific.
Data = HalpReadPerfMonCnfgReg0();
Data &= ClearStatusMask;
HalpWritePerfMonCnfgReg0(Data);
return;
} // HalpEnableProfileCounting()
VOID
HalpDisableProfileCounting (
VOID
)
/*++
Routine Description:
This function disables the profile counters to increment.
This function is the counterpart of HalpEnableProfileCounting().
Arguments:
None.
Return Value:
None.
--*/
{
ULONGLONG Data, SetFreezeMask;
SetFreezeMask = 0x1;
Data = HalpReadPerfMonCnfgReg0();
Data |= SetFreezeMask;
HalpWritePerfMonCnfgReg0(Data);
return;
} // HalpDisableProfileCounting()
VOID
HalpSetInitialProfileState(
VOID
)
/*++
Routine Description:
This function is called at HalInitSystem - phase 0 time to set
the initial state of processor and profiling os subsystem with
regards to the profiling functionality.
Arguments:
None.
Return Value:
None.
--*/
{
// HalpProfilingRunning = 0;
HalpDisableProfileCounting();
return;
} // HalpSetInitialProfileState()
VOID
HalpSetProfileCounterInterval (
IN ULONG Counter,
IN LONGLONG NextCount
)
/*++
Routine Description:
This function preloads the specified counter with a count value
of 2^IMPL_BITS - NextCount.
Arguments:
Counter - Supplies the performance counter register number.
NextCount - Supplies the value to preload in the monitor.
An external interruption will be generated after NextCount.
Return Value:
None.
Note:
IMPL_BITS is defined by PAL_PERF_MON_INFO.PAL_WIDTH.
ToDo:
IMPL_BITS is hardcoded to 32.
--*/
{
ULONGLONG Count;
#define MAXIMUM_COUNT 4294967296 // 2 ** 32 for Merced. XXTF - FIXFIX - Merced specific.
// if ( (Counter < 4) || (Counter > 7) ) return;
if (NextCount > MAXIMUM_COUNT) {
Count = 0;
} else {
Count = MAXIMUM_COUNT - NextCount;
}
HalpWritePerfMonDataReg( Counter, Count );
#undef MAXIMUM_COUNT
return;
} // HalpSetProfileCounterInterval()
VOID
HalpSetProfileCounterPrivilegeLevelMask(
IN ULONG Counter,
IN ULONG Mask
)
/*++
Routine Description:
This function set the profile counter privilege level mask.
Arguments:
Counter - Supplies the performance counter register number.
Mask - Supplies the privilege level mask to program the PMC with.
Return Value:
None.
--*/
{
ULONGLONG data, plmMask;
// if ( (Counter < 4) || (Counter > 7) ) return;
plmMask = Mask & 0xF;
data = HalpReadPerfMonCnfgReg( Counter );
data &= ~0xF;
data |= plmMask;
HalpWritePerfMonCnfgReg( Counter, data );
return;
} // HalpSetProfileCounterPrivilegeLevelMask()
VOID
HalpEnableProfileCounterOverflowInterrupt (
IN ULONG Counter
)
/*++
Routine Description:
This function enables the delivery of an overflow interrupt for
the specified profile counter.
Arguments:
Counter - Supplies the performance counter register number.
Return Value:
None.
--*/
{
ULONGLONG data, mask;
// if ( (Counter < 4) || (Counter > 7) ) return;
mask = 1<<5;
data = HalpReadPerfMonCnfgReg( Counter );
data |= mask;
HalpWritePerfMonCnfgReg( Counter, data );
return;
} // HalpEnableProfileCounterOverflowInterrupt()
VOID
HalpDisableProfileCounterOverflowInterrupt (
IN ULONG Counter
)
/*++
Routine Description:
This function disables the delivery of an overflow interrupt for
the specified profile counter.
Arguments:
Counter - Supplies the performance counter register number.
Return Value:
None.
--*/
{
ULONGLONG data, mask;
// if ( (Counter < 4) || (Counter > 7) ) return;
mask = 1<<5;
data = HalpReadPerfMonCnfgReg( Counter );
data &= ~mask;
HalpWritePerfMonCnfgReg( Counter, data );
return;
} // HalpDisableProfileCounterOverflowInterrupt()
VOID
HalpEnableProfileCounterPrivilegeMonitor(
IN ULONG Counter
)
/*++
Routine Description:
This function enables the profile counter as privileged monitor.
Arguments:
Counter - Supplies the performance counter register number.
Return Value:
None.
--*/
{
ULONGLONG data, pm;
// if ( (Counter < 4) || (Counter > 7) ) return;
pm = 1<<6;
data = HalpReadPerfMonCnfgReg( Counter );
data |= pm;
HalpWritePerfMonCnfgReg( Counter, data );
return;
} // HalpEnableProfileCounterPrivilegeMonitor()
VOID
HalpDisableProfileCounterPrivilegeMonitor(
IN ULONG Counter
)
/*++
Routine Description:
This function disables the profile counter as privileged monitor.
Arguments:
Counter - Supplies the performance counter register number.
Return Value:
None.
--*/
{
ULONGLONG data, pm;
// if ( (Counter < 4) || (Counter > 7) ) return;
pm = 1<<6;
data = HalpReadPerfMonCnfgReg( Counter );
data &= ~pm;
HalpWritePerfMonCnfgReg( Counter, data );
return;
} // HalpDisableProfileCounterPrivilegeMonitor()
VOID
HalpSetProfileCounterEvent(
IN ULONG Counter,
IN ULONG Event
)
/*++
Routine Description:
The function specifies the monitor event for the profile counter.
Arguments:
Counter - Supplies the performance counter register number.
Event - Supplies the monitor event code.
Return Value:
None.
--*/
{
ULONGLONG data, es;
// if ( (Counter < 4) || (Counter > 7) ) return;
es = (Event & 0x7F) << 8;
data = HalpReadPerfMonCnfgReg( Counter );
data &= ~(0x7F << 8);
data |= es;
HalpWritePerfMonCnfgReg( Counter, data );
return;
} // HalpSetProfileCounterEvent()
VOID
HalpSetProfileCounterUmask(
IN ULONG Counter,
IN ULONG Umask
)
/*++
Routine Description:
This function sets the event specific umask value for the profile
counter.
Arguments:
Counter - Supplies the performance counter register number.
Umask - Supplies the event specific umask value.
Return Value:
None.
--*/
{
ULONGLONG data, um;
// if ( (Counter < 4) || (Counter > 7) ) return;
um = (Umask & 0xF) << 16;
data = HalpReadPerfMonCnfgReg( Counter );
data &= ~(0xF << 16);
data |= um;
HalpWritePerfMonCnfgReg( Counter, data );
return;
} // HalpSetProfileCounterUmask()
VOID
HalpSetProfileCounterThreshold(
IN ULONG Counter,
IN ULONG Threshold
)
/*++
Routine Description:
This function sets the profile counter threshold.
Arguments:
Counter - Supplies the performance counter register number.
Threshold - Supplies the desired threshold.
This is related to multi-occurences events.
Return Value:
None.
--*/
{
ULONGLONG data, reset, th;
switch( Counter ) {
case 4:
case 5:
Threshold &= 0x7;
reset = ~(0x7 << 20);
break;
case 6:
case 7:
Threshold &= 0x3;
reset = ~(0x3 << 20);
break;
default:
return;
}
th = Threshold << 20;
data = HalpReadPerfMonCnfgReg( Counter );
data &= reset;
data |= th;
HalpWritePerfMonCnfgReg( Counter, data );
return;
} // HalpSetProfileCounterThreshold()
VOID
HalpSetProfileCounterInstructionSetMask(
IN ULONG Counter,
IN ULONG Mask
)
/*++
Routine Description:
This function sets the instruction set mask for the profile counter.
Arguments:
Counter - Supplies the performance counter register number.
Mask - Supplies the instruction set mask.
Return Value:
None.
--*/
{
ULONGLONG data, ismMask;
// if ( (Counter < 4) || (Counter > 7) ) return;
ismMask = (Mask & 0x3) << 24;
data = HalpReadPerfMonCnfgReg( Counter );
data &= ~(0x3 << 24);
data |= ismMask;
HalpWritePerfMonCnfgReg( Counter, data );
return;
} // HalpSetProfileCounterInstructionSetMask()
VOID
HalpSetProfileCounterConfiguration(
IN ULONG Counter,
IN ULONG PrivilegeMask,
IN ULONG EnableOverflowInterrupt,
IN ULONG EnablePrivilegeMonitor,
IN ULONG Event,
IN ULONG Umask,
IN ULONG Threshold,
IN ULONG InstructionSetMask
)
/*++
Function Description:
This function sets the profile counter with the specified parameters.
Arguments:
IN ULONG Counter -
IN ULONG PrivilegeMask -
IN ULONG EnableOverflowInterrupt -
IN ULONG EnablePrivilegeMonitor -
IN ULONG Event -
IN ULONG Umask -
IN ULONG Threshold -
IN ULONG InstructionSetMask -
Return Value:
VOID
Algorithm:
ToBeSpecified
In/Out Conditions:
ToBeSpecified
Globals Referenced:
ToBeSpecified
Exception Conditions:
ToBeSpecified
MP Conditions:
ToBeSpecified
Notes:
This function is a kind of combo of the different profile counter APIs.
It was created to provide speed.
ToDo List:
- Setting the threshold is not yet supported.
Modification History:
3/16/2000 TF Initial version
--*/
{
ULONGLONG data, plmMask, ismMask, es, um, th;
// if ( (Counter < 4) || (Counter > 7) ) return;
plmMask = (PrivilegeMask & 0xF);
es = (Event & 0x7F) << 8;
um = (Umask & 0xF) << 16;
// XXTF - ToBeDone - Threshold not supported yet.
ismMask = (InstructionSetMask & 0x3) << 24;
data = HalpReadPerfMonCnfgReg( Counter );
HalDebugPrint(( HAL_PROFILE, "HalpSetProfileCounterConfiguration: Counter = %ld Read = 0x%I64x\n", Counter, data ));
data &= ~( (0x3 << 24) | (0xF << 16) | (0x7F << 8) | 0xF );
data |= ( plmMask | es | um | ismMask );
data = EnableOverflowInterrupt ? (data | (1<<5)) : (data & ~(1<<5));
data = EnablePrivilegeMonitor ? (data | (1<<6)) : (data & ~(1<<6));
HalpWritePerfMonCnfgReg( Counter, data );
HalDebugPrint(( HAL_PROFILE, "HalpSetProfileCounterConfiguration: Counter = %ld Written = 0x%I64x\n", Counter, data ));
return;
} // HalpSetProfileCounterConfiguration()
NTSTATUS
HalpProgramProfileMapping(
PHALP_PROFILE_MAPPING ProfileMapping,
KPROFILE_SOURCE ProfileSource
)
/*++
Routine Description:
This function enables the profiling configuration for the event defined by the
specified Profile Mapping entry.
Arguments:
ProfileMapping - Supplies the Profile Mapping entry.
ProfileSource - Supplies the Profile Source corresponding to the Profile Mapping entry.
Return Value:
STATUS_SUCCESS -
STATUS_INVALID_PARAMETER -
STATUS_UNSUCESSFUL -
--*/
{
NTSTATUS status;
ULONG sourceMask;
if ( ! ProfileMapping ) {
return STATUS_INVALID_PARAMETER;
}
// XXTF - ToBeDone - Derived Event
sourceMask = ProfileMapping->ProfileSourceMask;
if ( (sourceMask & PMCD_MASK_4) && !HalpIsProfileSourceActive( HalpProfileSource4 ) ) {
HalpSetProfileCounterConfiguration( 4,
PMC_PLM_ALL,
PMC_ENABLE_OVERFLOW_INTERRUPT,
PMC_ENABLE_PRIVILEGE_MONITOR,
ProfileMapping->Event,
0, // Umask
0, // Threshold
PMC_ISM_ALL
);
HalpSetProfileCounterInterval( 4, ProfileMapping->Interval );
HalpProfileSource4 = ProfileSource;
return STATUS_SUCCESS;
}
if ( (sourceMask & PMCD_MASK_5) && !HalpIsProfileSourceActive( HalpProfileSource5 ) ) {
HalpSetProfileCounterConfiguration( 5,
PMC_PLM_ALL,
PMC_ENABLE_OVERFLOW_INTERRUPT,
PMC_ENABLE_PRIVILEGE_MONITOR,
ProfileMapping->Event,
0, // Umask
0, // Threshold
PMC_ISM_ALL
);
HalpSetProfileCounterInterval( 5, ProfileMapping->Interval );
HalpProfileSource5 = ProfileSource;
return STATUS_SUCCESS;
}
if ( (sourceMask & PMCD_MASK_6) && !HalpIsProfileSourceActive( HalpProfileSource6 ) ) {
HalpSetProfileCounterConfiguration( 6,
PMC_PLM_ALL,
PMC_ENABLE_OVERFLOW_INTERRUPT,
PMC_ENABLE_PRIVILEGE_MONITOR,
ProfileMapping->Event,
0, // Umask
0, // Threshold
PMC_ISM_ALL
);
HalpSetProfileCounterInterval( 6, ProfileMapping->Interval );
HalpProfileSource6 = ProfileSource;
return STATUS_SUCCESS;
}
if ( (sourceMask & PMCD_MASK_7) && !HalpIsProfileSourceActive( HalpProfileSource7 ) ) {
HalpSetProfileCounterConfiguration( 7,
PMC_PLM_ALL,
PMC_ENABLE_OVERFLOW_INTERRUPT,
PMC_ENABLE_PRIVILEGE_MONITOR,
ProfileMapping->Event,
0, // Umask
0, // Threshold
PMC_ISM_ALL
);
HalpSetProfileCounterInterval( 7, ProfileMapping->Interval );
HalpProfileSource7 = ProfileSource;
return STATUS_SUCCESS;
}
return STATUS_UNSUCCESSFUL;
} // HalpProgramProfileMapping()
ULONG_PTR
HalpSetProfileInterruptHandler(
IN ULONG_PTR ProfileInterruptHandler
)
/*++
Routine Description:
This function registers a per-processor Profiling Interrupt Handler.
Arguments:
ProfileInterruptHandler - Interrupt Handler.
Return Value:
(ULONG_PTR)STATUS_SUCCESS - Successful registration.
(ULONG_PTR)STATUS_ALREADY_COMMITTED - Cannot register an handler if profiling events are running.
(ULONG_PTR)STATUS_PORT_ALREADY_SET - An Profiling Interrupt Handler was already registred - not imposed currently.
Note:
IT IS THE RESPONSIBILITY OF THE CALLER OF THIS ROUTINE TO ENSURE
THAT NO PAGE FAULTS WILL OCCUR DURING EXECUTION OF THE PROVIDED
FUNCTION OR ACCESS TO THE PROVIDED CONTEXT.
A MINIMUM OF FUNCTION POINTER CHECKING WAS DONE IN HalSetSystemInformation PROCESSING.
--*/
{
//
// If profiling is already running, we do not allow the handler registration.
//
// This imposes that:
//
// - if the default HAL profiling is running or a profiling with a registered interrupt
// handler is running, we cannot register an interrupt handler.
// In the last case, all the profiling events have to be stopped before a possible
// registration.
//
// It should be also noticed that there is no ownership of profiling monitors implemented.
// Meaning that if profiling is started, the registred handler will get the interrupts
// generated by ALL the running monitor events if they are programmed to generate interrupts.
//
if ( HalpProfilingRunning ) {
HalDebugPrint(( HAL_PROFILE, "HalpSetProfileInterruptHandler: Profiling already running\n" ));
return((ULONG_PTR)(ULONG)(STATUS_ALREADY_COMMITTED));
}
#if 0
//
// Thierry - 03/2000. ToBeVerified.
//
// In case, no profiling was started, there is currently no restriction in registering
// another handler if one was already registered.
//
if ( HalpProfillingInterruptHandler ) {
return((ULONG_PTR)(ULONG)(STATUS_PORT_ALREADY_SET));
}
#endif // 0
HalpProfilingInterruptHandler = (ULONGLONG)ProfileInterruptHandler;
return((ULONG_PTR)(ULONG)(STATUS_SUCCESS));
} // HalpSetProfileInterruptHandler()
VOID
HalpProfileInterrupt(
IN PKINTERRUPT_ROUTINE Interrupt,
IN PKTRAP_FRAME TrapFrame
)
/*++
Routine Description:
Default PROFILE_VECTOR Interrupt Handler.
This function is executed as the result of an interrupt from the
internal microprocessor performance counters. 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 returns.
Arguments:
TrapFrame - Trap frame address.
Return Value:
None.
--*/
{
//
// Call registered per-processor Profiling Interrupt handler if it exists.
// We will return immediately before doing any default profiling interrupt handling.
//
// XXTF - ToBeVerified - This functionality has to be verified before
// final check-in.
//
if ( HalpProfilingInterruptHandler ) {
(*((PHAL_PROFILE_INTERRUPT_HANDLER)HalpProfilingInterruptHandler))( TrapFrame );
return;
}
//
// Handle interrupt if profiling is enabled.
//
if ( HalpProfilingRunning ) {
//
// Process every PMC/PMD pair overflow.
//
// XXTF - FIXFIX - Merced specific.
UCHAR pmc0, overflow;
ULONG source;
HalpProfilingInterrupts++;
pmc0 = (UCHAR)HalpReadPerfMonCnfgReg0();
ASSERTMSG( "HAL!HalpProfileInterrupt PMC0 freeze bit is not set!\n", pmc0 & 0x1 );
overflow = pmc0 & 0xF0;
ASSERTMSG( "HAL!HalpProfileInterrupt no overflow bit set!\n", overflow );
if ( overflow & (1<<4) ) {
source = HalpProfileSource4; // XXTF - IfFaster - Coud used pmc.es
ASSERTMSG( "HAL!HalpProfileInterrupt no overflow bit set!\n", source < ProfileIA64Maximum );
KeProfileInterruptWithSource( TrapFrame, source );
HalpSetProfileCounterInterval( 4, HalpProfileMapping[source].Interval );
// XXTF - IfFaster - HalpWritePerfMonDataReg( 4, HalpProfileMapping[source].Interval );
// XXTF - CodeWithReload - HalpWritePerfMonCnfgReg( 4, *PCRProfileCnfg4Reload );
}
if ( overflow & (1<<5) ) {
source = HalpProfileSource5; // XXTF - IfFaster - Coud used pmc.es
ASSERTMSG( "HAL!HalpProfileInterrupt no overflow bit set!\n", source < ProfileIA64Maximum );
KeProfileInterruptWithSource( TrapFrame, source );
HalpSetProfileCounterInterval( 5, HalpProfileMapping[source].Interval );
// XXTF - IfFaster - HalpWritePerfMonDataReg( 5, HalpProfileMapping[source].Interval );
// XXTF - CodeWithReload - HalpWritePerfMonCnfgReg( 5, *PCRProfileCnfg5Reload );
}
if ( overflow & (1<<6) ) {
source = HalpProfileSource6; // XXTF - IfFaster - Coud used pmc.es
ASSERTMSG( "HAL!HalpProfileInterrupt no overflow bit set!\n", source < ProfileIA64Maximum );
KeProfileInterruptWithSource( TrapFrame, source );
HalpSetProfileCounterInterval( 6, HalpProfileMapping[source].Interval );
// XXTF - IfFaster - HalpWritePerfMonDataReg( 6, HalpProfileMapping[source].Interval );
// XXTF - CodeWithReload - HalpWritePerfMonCnfgReg( 6, *PCRProfileCnfg6Reload );
}
if ( overflow & (1<<7) ) {
source = HalpProfileSource7; // XXTF - IfFaster - Coud used pmc.es
ASSERTMSG( "HAL!HalpProfileInterrupt no overflow bit set!\n", source < ProfileIA64Maximum );
KeProfileInterruptWithSource( TrapFrame, source );
HalpSetProfileCounterInterval( 7, HalpProfileMapping[source].Interval );
// XXTF - IfFaster - HalpWritePerfMonDataReg( 6, HalpProfileMapping[source].Interval );
// XXTF - CodeWithReload - HalpWritePerfMonCnfgReg( 7, *PCRProfileCnfg7Reload );
}
//
// Clear pmc0.fr and overflow bits.
//
HalpEnableProfileCounting();
}
else {
HalpProfilingInterruptsWithoutProfiling++;
}
return;
} // HalpProfileInterrupt()
PHALP_PROFILE_MAPPING
HalpGetProfileMapping(
IN KPROFILE_SOURCE Source
)
/*++
Routine Description:
Given a profile source, returns whether or not that source is
supported.
Arguments:
Source - Supplies the profile source
Return Value:
TRUE - Profile source is supported
FALSE - Profile source is not supported
--*/
{
if ( Source > ProfileIA64Maximum /* = (sizeof(HalpProfileMapping)/sizeof(HalpProfileMapping[0])) */ )
{
return NULL;
}
return(&HalpProfileMapping[Source]);
} // HalpGetProfileMapping()
BOOLEAN
HalQueryProfileInterval(
IN KPROFILE_SOURCE Source
)
/*++
Routine Description:
Given a profile source, returns whether or not that source is
supported.
Arguments:
Source - Supplies the profile source
Return Value:
TRUE - Profile source is supported
FALSE - Profile source is not supported
--*/
{
PHALP_PROFILE_MAPPING profileMapping;
profileMapping = HalpGetProfileMapping( Source );
if ( !profileMapping ) {
return(FALSE);
}
return( profileMapping->Supported );
} // HalQueryProfileInterval()
NTSTATUS
HalSetProfileSourceInterval(
IN KPROFILE_SOURCE ProfileSource,
IN OUT ULONG_PTR *Interval
)
/*++
Routine Description:
Sets the profile interval for a specified profile source
Arguments:
ProfileSource - Supplies the profile source
Interval - Supplies the specified profile interval
Returns the actual profile interval
- if ProfileSource is ProfileTime, Interval is in 100ns units.
Return Value:
NTSTATUS
--*/
{
ULONGLONG countEvents;
PHALP_PROFILE_MAPPING profileMapping;
profileMapping = HalpGetProfileMapping(ProfileSource);
if ( HalpIsProfileMappingInvalid( profileMapping ) ) {
return(STATUS_NOT_IMPLEMENTED);
}
HalDebugPrint(( HAL_PROFILE, "HalSetProfileSourceInterval: ProfileSource = %ld IN *Interval = 0x%Ix\n", ProfileSource, *Interval ));
if ( ProfileSource == ProfileTime ) {
//
// Convert the clock tick period (in 100ns units) into a cycle count period
//
countEvents = (ULONGLONG)(*Interval * HalpITCTicksPer100ns);
}
else {
countEvents = (ULONGLONG)*Interval;
}
HalDebugPrint(( HAL_PROFILE, "HalSetProfileSourceInterval: countEvent = 0x%I64x\n", countEvents ));
//
// Check to see if the desired Interval is reasonable, if not adjust it.
//
if ( countEvents > profileMapping->MaxInterval ) {
countEvents = profileMapping->MaxInterval;
}
else if ( countEvents < profileMapping->MinInterval ) {
countEvents = profileMapping->MinInterval;
}
profileMapping->Interval = countEvents;
HalDebugPrint(( HAL_PROFILE, "HalSetProfileSourceInterval: CurrentInterval = 0x%I64x\n", profileMapping->Interval ));
if ( ProfileSource == ProfileTime ) {
ULONGLONG tempInterval;
//
// Convert cycle count back into 100ns clock ticks
//
tempInterval = (ULONGLONG)(countEvents / HalpITCTicksPer100ns);
#if 0
if ( tempInterval < 1 ) {
tempInterval = 1;
}
#endif
*Interval = (ULONG_PTR)tempInterval;
}
else {
*Interval = (ULONG_PTR)countEvents;
}
HalDebugPrint(( HAL_PROFILE, "HalSetProfileSourceInterval: ProfileSource = %ld OUT *Interval = 0x%Ix\n", ProfileSource, *Interval ));
return STATUS_SUCCESS;
} // HalSetProfileSourceInterval()
ULONG_PTR
HalSetProfileInterval (
IN ULONG_PTR Interval
)
/*++
Routine Description:
This routine sets the ProfileTime source interrupt interval.
Arguments:
Interval - Supplies the desired profile interval in 100ns units.
Return Value:
The actual profile interval.
--*/
{
ULONG_PTR NewInterval;
NewInterval = Interval;
HalSetProfileSourceInterval(ProfileTime, &NewInterval);
return(NewInterval);
} // HalSetProfileInterval()
VOID
HalStartProfileInterrupt (
KPROFILE_SOURCE ProfileSource
)
/*++
Routine Description:
This routine turns on the profile interrupt.
N.B. This routine must be called at PROFILE_LEVEL while holding the profile lock if MP.
Arguments:
None.
Return Value:
None.
--*/
{
BOOLEAN disabledProfileCounting;
NTSTATUS status;
PHALP_PROFILE_MAPPING profileMapping;
//
// Get the Hal profile mapping entry associated with the specified source.
//
profileMapping = HalpGetProfileMapping( ProfileSource );
if ( HalpIsProfileMappingInvalid( profileMapping ) ) {
HalDebugPrint(( HAL_PROFILE, "HalStartProfileInterrupt: invalid source = %ld\n", ProfileSource ));
return;
}
//
// Disable the profile counting if enabled.
//
disabledProfileCounting = FALSE;
if ( HalpProfilingRunning && !(HalpReadPerfMonCnfgReg0() & 0x1) ) {
HalpDisableProfileCounting();
disabledProfileCounting = TRUE;
}
//
// Obtain and initialize an available PMC register that supports this event.
// We may enable more than one event.
// If the initialization failed, we return immediately.
//
// XXTF - FIXFIX - is there a way to
// * notify the caller for the failure and the reason of the failure. or
// * modify the API. or
// * define a new API.
//
status = HalpProgramProfileMapping( profileMapping, ProfileSource );
if ( !NT_SUCCESS(status) ) {
HalDebugPrint(( HAL_PROFILE, "HalStartProfileInterrupt: HalpProgramProfileMapping failed.\n" ));
if ( disabledProfileCounting ) {
HalpEnableProfileCounting();
}
return;
}
//
// Notify the profiling as active.
// before enabling the selected pmc overflow interrupt and unfreezing the counters.
//
HalpProfilingRunning++;
HalpEnableProfileCounting();
return;
} // HalStartProfileInterrupt()
VOID
HalStopProfileInterrupt (
KPROFILE_SOURCE ProfileSource
)
/*++
Routine Description:
This routine turns off the profile interrupt.
N.B. This routine must be called at PROFILE_LEVEL while holding the
profile lock.
Arguments:
ProfileSource - Supplies the Profile Source to stop.
Return Value:
None.
--*/
{
PHALP_PROFILE_MAPPING profileMapping;
//
// Get the Hal profile mapping entry associated with the specified profile source.
//
profileMapping = HalpGetProfileMapping( ProfileSource );
if ( HalpIsProfileMappingInvalid( profileMapping ) ) {
HalDebugPrint(( HAL_PROFILE, "HalStopProfileInterrupt: invalid source = %ld\n", ProfileSource ));
return;
}
//
// Validate the Profile Source as active.
//
if ( HalpProfileSource4 == ProfileSource ) {
// XXTF - FIXFIX - Derived Event - ToBeDone
HalpSetProfileCounterConfiguration( 4,
PMC_PLM_NONE,
PMC_DISABLE_OVERFLOW_INTERRUPT,
PMC_DISABLE_PRIVILEGE_MONITOR,
0, // Event
0, // Umask
0, // Threshold
PMC_ISM_NONE
);
HalpSetProfileCounterInterval( 4, 0 );
HalpDisactivateProfileSource( HalpProfileSource4 );
HalpProfilingRunning--;
}
else if ( HalpProfileSource5 == ProfileSource ) {
// XXTF - FIXFIX - Derived Event - ToBeDone
HalpSetProfileCounterConfiguration( 5,
PMC_PLM_NONE,
PMC_DISABLE_OVERFLOW_INTERRUPT,
PMC_DISABLE_PRIVILEGE_MONITOR,
0, // Event
0, // Umask
0, // Threshold
PMC_ISM_NONE
);
HalpSetProfileCounterInterval( 5, 0 );
HalpDisactivateProfileSource( HalpProfileSource5 );
HalpProfilingRunning--;
}
else if ( HalpProfileSource6 == ProfileSource ) {
// XXTF - FIXFIX - Derived Event - ToBeDone
HalpSetProfileCounterConfiguration( 6,
PMC_PLM_NONE,
PMC_DISABLE_OVERFLOW_INTERRUPT,
PMC_DISABLE_PRIVILEGE_MONITOR,
0, // Event
0, // Umask
0, // Threshold
PMC_ISM_NONE
);
HalpSetProfileCounterInterval( 6, 0 );
HalpDisactivateProfileSource( HalpProfileSource6);
HalpProfilingRunning--;
}
else if ( HalpProfileSource7 == ProfileSource ) {
// XXTF - FIXFIX - Derived Event - ToBeDone
HalpSetProfileCounterConfiguration( 7,
PMC_PLM_NONE,
PMC_DISABLE_OVERFLOW_INTERRUPT,
PMC_DISABLE_PRIVILEGE_MONITOR,
0, // Event
0, // Umask
0, // Threshold
PMC_ISM_NONE
);
HalpSetProfileCounterInterval( 7, 0 );
HalpDisactivateProfileSource( HalpProfileSource7 );
HalpProfilingRunning--;
}
return;
} // HalStopProfileInterrupt()
VOID
HalpResetProcessorDependentPerfMonCnfgRegs(
ULONGLONG DefaultValue
)
/*++
Routine Description:
This routine initializes the processor dependent performance configuration
registers.
Arguments:
DefaultValue - default value used to initialize IA64 generic PMCs.
Return Value:
None.
--*/
{
// XXTF - 02/08/2000
// For now, there is no initialization for processor dependent performance
// configuration registers.
return;
} // HalpResetProcessorDependentPerfMonCnfgRegs()
VOID
HalpResetPerfMonCnfgRegs(
VOID
)
/*++
Routine Description:
This routine initializes the IA64 architected performance configuration
registers and calls the micro-architecture specific initialization.
Arguments:
None.
Return Value:
None.
--*/
{
ULONG pmc;
ULONGLONG value;
//
// PMC Reset value:
// Reg. Field Bits
// PMC* .plm - 3: 0 - Privilege Mask - 0 (Disable Counter)
// PMC* .ev - 4 - External Visibility - 0 (Disabled)
// PMC* .oi - 5 - Overflow Interrupt - 0 (Disabled)
// PMC* .pm - 6 - Privilege Monitor - 0 (user monitor)
// PMC* .ig - 7 - Ignored
// PMC* .es - 14: 8 - Event Select - 0 (XXTF - Warning - 0x0 = Real Event)
// PMC* .ig - 15 - Ignored
// PMC* .umask - 19:16 - Unit Mask - 0 (event specific. ok for .es=0)
// PMC4,5 .threshold - 22:20 - Threshold - 0 (multi-occurence events threshold)
// PMC4,5 .ig - 23 - Ignored
// PMC6,7 .threshold - 21:20 - Threshold - 0 (multi-occurence events threshold)
// PMC6,7 .ig - 23:22 - Ignored
// PMC* .ism - 25:24 - Instruction Set Mask - 0 (IA64 & IA32 sets - 11:disables monitoring)
// PMC* .ig - 63:26 - Ignored
// -----
// PMC_RESET
#define PMC_RESET 0ui64
value = PMC_RESET;
for ( pmc = 4; pmc < 8; pmc++ ) {
HalpWritePerfMonCnfgReg( pmc, value );
}
HalpResetProcessorDependentPerfMonCnfgRegs( value );
#undef PMC_RESET
return;
} // HalpResetPerfMonCnfgRegs()
VOID
HalpInitializeProfiling (
ULONG Number
)
/*++
Routine Description:
This routine is called during initialization to initialize profiling
for each processor in the system.
Called from HalInitSystem at phase 1 on every processor.
Arguments:
Number - Supplies the processor number.
Return Value:
None.
--*/
{
//
// If BSP processor, initialize the ProfileTime Interval entries.
//
// Assumes HalpITCTicksPer100ns has been initialized.
if ( Number == 0 ) {
ULONGLONG interval;
ULONGLONG count;
PHALP_PROFILE_MAPPING profile;
profile = &HalpProfileMapping[ProfileTime];
interval = DEFAULT_PROFILE_INTERVAL;
count = (ULONGLONG)(interval * HalpITCTicksPer100ns);
profile->DefInterval = count;
interval = MAXIMUM_PROFILE_INTERVAL;
count = (ULONGLONG)(interval * HalpITCTicksPer100ns);
profile->MaxInterval = count;
interval = MINIMUM_PROFILE_INTERVAL;
count = (ULONGLONG)(interval * HalpITCTicksPer100ns);
profile->MinInterval = count;
}
//
// ToBeDone - checkpoint for default processor.PSR fields for
// performance monitoring.
//
//
// Resets the processor performance configuration registers.
//
HalpResetPerfMonCnfgRegs();
//
// Initialization of the Per processor profiling data.
//
HalpProfilingRunning = 0;
HalpDisactivateProfileSource( HalpProfileSource4 );
HalpDisactivateProfileSource( HalpProfileSource5 );
HalpDisactivateProfileSource( HalpProfileSource6 );
HalpDisactivateProfileSource( HalpProfileSource7 );
//
// XXTF 02/08/2000:
// Different performance vectors are considered:
// - Profiling (default) -> PROFILE_VECTOR
// - Tracing -> PERF_VECTOR [PMUTRACE_VECTOR]
//
// Set default Performance vector to Profiling.
//
ASSERTMSG( "HAL!HalpInitializeProfiler PROFILE_VECTOR handler != HalpProfileInterrupt\n",
PCR->InterruptRoutine[PROFILE_VECTOR] == (PKINTERRUPT_ROUTINE)HalpProfileInterrupt );
HalpWritePerfMonVectorReg( PROFILE_VECTOR );
return;
} // HalpInitializeProfiler()
NTSTATUS
HalpProfileSourceInformation (
OUT PVOID Buffer,
IN ULONG BufferLength,
OUT PULONG ReturnedLength
)
/*++
Routine Description:
Returns the HAL_PROFILE_SOURCE_INFORMATION or
HAL_PROFILE_SOURCE_INFORMATION_EX for this processor.
Arguments:
Buffer - output buffer
BufferLength - length of buffer on input
ReturnedLength - The length of data returned
Return Value:
STATUS_SUCCESS
STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize
currently needed.
--*/
{
PHALP_PROFILE_MAPPING profileMapping;
NTSTATUS status;
if ( (BufferLength != sizeof(HAL_PROFILE_SOURCE_INFORMATION)) &&
(BufferLength < sizeof(HAL_PROFILE_SOURCE_INFORMATION_EX)) )
{
status = STATUS_INFO_LENGTH_MISMATCH;
return status;
}
profileMapping = HalpGetProfileMapping(((PHAL_PROFILE_SOURCE_INFORMATION)Buffer)->Source);
//
// return a different status error if the source is not supported or
// the source is not a valid
//
if ( profileMapping == NULL ) {
status = STATUS_INVALID_PARAMETER;
return status;
}
if ( BufferLength == sizeof(HAL_PROFILE_SOURCE_INFORMATION) ) {
PHAL_PROFILE_SOURCE_INFORMATION sourceInfo;
//
// HAL_PROFILE_SOURCE_INFORMATION buffer.
//
sourceInfo = (PHAL_PROFILE_SOURCE_INFORMATION)Buffer;
sourceInfo->Supported = profileMapping->Supported;
if ( sourceInfo->Supported ) {
//
// For ProfileTime, we convert cycle count back into 100ns clock ticks.
//
if ( profileMapping->ProfileSource == ProfileTime ) {
sourceInfo->Interval = (ULONG) (profileMapping->Interval / HalpITCTicksPer100ns);
}
else {
sourceInfo->Interval = (ULONG) profileMapping->Interval;
}
}
if ( ReturnedLength ) {
*ReturnedLength = sizeof(HAL_PROFILE_SOURCE_INFORMATION);
}
}
else {
PHAL_PROFILE_SOURCE_INFORMATION_EX sourceInfoEx;
//
// HAL_PROFILE_SOURCE_INFORMATION_EX buffer.
//
sourceInfoEx = (PHAL_PROFILE_SOURCE_INFORMATION_EX)Buffer;
sourceInfoEx->Supported = profileMapping->Supported;
if ( sourceInfoEx->Supported ) {
//
// For ProfileTime, we convert cycle count back into 100ns clock ticks.
//
if ( profileMapping->ProfileSource == ProfileTime ) {
sourceInfoEx->Interval = (ULONG_PTR) (profileMapping->Interval / HalpITCTicksPer100ns);
}
else {
sourceInfoEx->Interval = (ULONG_PTR) profileMapping->Interval;
}
sourceInfoEx->DefInterval = (ULONG_PTR) profileMapping->DefInterval;
sourceInfoEx->MaxInterval = (ULONG_PTR) profileMapping->MaxInterval;
sourceInfoEx->MinInterval = (ULONG_PTR) profileMapping->MinInterval;
}
if ( ReturnedLength ) {
*ReturnedLength = sizeof(HAL_PROFILE_SOURCE_INFORMATION_EX);
}
}
return STATUS_SUCCESS;
} // HalpProfileSourceInformation()