Exemple #1
0
VOID
HalpStallInterrupt (
    VOID
    )

/*++

Routine Description:

    This function serves as the stall calibration interrupt service
    routine. It is executed in response to system clock interrupts
    during the initialization of the HAL layer.

Arguments:

    None.

Return Value:

    None.

--*/

{

    //
    // If this is the very first interrupt, then wait for the second
    // interrupt before starting the timing interval. Else, if this
    // the second interrupt, then capture the starting stall count
    // and clear the count register on R4000 processors. Else, if this
    // is the third interrupt, then capture the ending stall count and
    // the ending count register on R4000 processors. Else, if this is
    // the fourth or subsequent interrupt, then simply dismiss it.
    //

    if ((HalpStallStart == 0) && (HalpStallEnd == 0)) {
        HalpStallEnd = 1;

    } else if ((HalpStallStart == 0) && (HalpStallEnd != 0)) {
        HalpStallStart = PCR->StallExecutionCount;

        HalpStallEnd = 0;

        HalpWriteCompareRegisterAndClear(0);

    } else if ((HalpStallStart != 0) && (HalpStallEnd == 0)) {
        HalpStallEnd = PCR->StallExecutionCount;

        HalpProfileCountRate = HalpWriteCompareRegisterAndClear(0);

    }


    return;
}
Exemple #2
0
VOID
HalpCountInterrupt (
    VOID
)

/*++

Routine Description:

    This function serves as the count/compare interrupt service routine
    early in the system initialization. Its only function is to field
    and acknowledge count/compare interrupts during the system boot process.

Arguments:

    None.

Return Value:

    None.

--*/

{

    //
    // Acknowledge the count/compare interrupt.
    //

    HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT);
    return;
}
Exemple #3
0
VOID
HalCalibratePerformanceCounter (
    IN volatile PLONG Number
    )

/*++

Routine Description:

    This routine resets the performance counter value for the current
    processor to zero. The reset is done such that the resulting value
    is closely synchronized with other processors in the configuration.

Arguments:

    Number - Supplies a pointer to count of the number of processors in
    the configuration.

Return Value:

    None.

--*/

{

    KSPIN_LOCK Lock;
    KIRQL OldIrql;
    PKPRCB Prcb;

    //
    // Raise IRQL to HIGH_LEVEL, decrement the number of processors, and
    // wait until the number is zero.
    //

    KeInitializeSpinLock(&Lock);
    KeRaiseIrql(HIGH_LEVEL, &OldIrql);
    if (ExInterlockedDecrementLong(Number, &Lock) != RESULT_ZERO) {
        do {

        } while (*Number !=0);
    }

    //
    // Write the compare register, clear the count register, and zero the
    // performance counter for the current processor.
    //

    HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT);
    Prcb = KeGetCurrentPrcb();
    HalpPerformanceCounter[Prcb->Number].QuadPart = 0;

    //
    // Restore IRQL to its previous value and return.
    //

    KeLowerIrql(OldIrql);
    return;
}
Exemple #4
0
VOID
HalStartProfileInterrupt (
    KPROFILE_SOURCE ProfileSource
    )

/*++

Routine Description:

    This routine computes the profile count value, writes the compare
    register, clears the count register, and updates the performance
    counter.

    N.B. This routine must be called at PROFILE_LEVEL while holding the
        profile lock.

Arguments:

    Source - Supplies the profile source.

Return Value:

    None.

--*/

{

    PKPRCB Prcb;
    ULONG PreviousCount;
    LARGE_INTEGER TempValue;

    //
    // Compute the profile count from the current profile interval.
    //

    TempValue.QuadPart = Int32x32To64(HalpProfileCountRate,
                                      HalpProfileInterval);

    TempValue.QuadPart += ROUND_VALUE;
    TempValue = RtlExtendedLargeIntegerDivide(TempValue, ONE_SECOND, NULL);

    //
    // Write the compare register and clear the count register.
    //

    PreviousCount = HalpWriteCompareRegisterAndClear(TempValue.LowPart);

    //
    // Update the performance counter by adding in the previous count value.
    //

    Prcb = KeGetCurrentPrcb();
    HalpPerformanceCounter[Prcb->Number].QuadPart += PreviousCount;
    return;
}
Exemple #5
0
VOID
HalStopProfileInterrupt (
    KPROFILE_SOURCE ProfileSource
    )

/*++

Routine Description:

    This routine sets the default count value, writes the compare
    register, clears the count register, and updates the performance
    counter.

    N.B. This routine must be called at PROFILE_LEVEL while holding the
        profile lock.

Arguments:

    Source - Provides the profile source.

Return Value:

    None.

--*/

{

    PKPRCB Prcb;
    ULONG PreviousCount;

    //
    // Write the compare register and clear the count register.
    //

    PreviousCount = HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT);

    //
    // Update the performance counter by adding in the previous count value.
    //

    Prcb = KeGetCurrentPrcb();
    HalpPerformanceCounter[Prcb->Number].QuadPart += PreviousCount;
    return;
}
Exemple #6
0
BOOLEAN
HalpInitializeInterrupts (
    VOID
    )

/*++

Routine Description:

    This function initializes interrupts for a MIPS R3000 or R4000 system.

Arguments:

    None.

Return Value:

    A value of TRUE is returned if the initialization is successfully
    completed. Otherwise a value of FALSE is returned.

--*/

{
    ULONG Index;
    PKPRCB Prcb;


    //
    // Get the address of the processor control block for the current
    // processor.
    //

    Prcb = PCR->Prcb;

    if (Prcb->Number == 0) {

        //
        // Initialize the IRQL translation tables in the PCR. These tables are
        // used by the interrupt dispatcher to determine the new IRQL and the
        // mask value that is to be loaded into the PSR. They are also used by
        // the routines that raise and lower IRQL to load a new mask value into
        // the PSR.
        //

        if (HalpIsRM200) {

            //
            // On an RM200 (Desktop) we have only 1 interrupt, which is like
            // the central Interrupt for R4x00SC machines
            //

            for (Index = 0; Index < sizeof(HalpIrqlMask_SC); Index += 1) 
                PCR->IrqlMask[Index] = HalpIrqlMask_SC[Index];

            for (Index = 0; Index < sizeof(HalpIrqlTable_SC); Index += 1) 
    
                PCR->IrqlTable[Index] = HalpIrqlTable_SC[Index];

        } else {

            //
            // if this is not a Desktop, we have to check if this is an 
            // R4x00 SC model or a R4x00 MC (multiprocessor model)
            //

            if (HalpProcessorId == MPAGENT) {
           
                //
                // this is the boot processor in an MultiProcessor Environment
                //

                for (Index = 0; Index < sizeof(HalpIrqlMask_MC); Index += 1) 
                    PCR->IrqlMask[Index] = HalpIrqlMask_MC[Index];
                for (Index = 0; Index < sizeof(HalpIrqlTable_MC); Index += 1) 
                    PCR->IrqlTable[Index] = HalpIrqlTable_MC[Index];
		
            } else {

		if ((HalpProcPc) || (HalpProcessorId == ORIONSC)) {

                    //
                    // this is an R4000PC or a R4600 model in an UniProcessor Environment
                    //

	            for (Index = 0; Index < sizeof(HalpIrqlMask_PC); Index += 1) 
        	        PCR->IrqlMask[Index] = HalpIrqlMask_PC[Index];
                    for (Index = 0; Index < sizeof(HalpIrqlTable_PC); Index += 1) 
        	        PCR->IrqlTable[Index] = HalpIrqlTable_PC[Index];
  
  	        } else {

                    //
                    // this is an R4x00SC model in an UniProcessor Environment
                    //

	            for (Index = 0; Index < sizeof(HalpIrqlMask_SC); Index += 1) 
        	        PCR->IrqlMask[Index] = HalpIrqlMask_SC[Index];
	            for (Index = 0; Index < sizeof(HalpIrqlTable_SC); Index += 1) 
        	        PCR->IrqlTable[Index] = HalpIrqlTable_SC[Index];
	        }

            }
        }

        //
        // the main system clock is always in the onboard PC core
        //

        PCR->InterruptRoutine[CLOCK2_LEVEL] = (PKINTERRUPT_ROUTINE)HalpStallInterrupt;

        //
        // If processor 0 is being initialized, then connect the count/compare
        // interrupt to the count interrupt routine to handle early count/compare
        // interrupts during phase 1 initialization. Otherwise, connect the
        // count\compare interrupt to the appropriate interrupt service routine.
        //



        //
        // force a CountCompare interrupt
        //

        HalpWriteCompareRegisterAndClear(100);

        PCR->InterruptRoutine[PROFILE_LEVEL] = HalpCountInterrupt;

        HalpProgramIntervalTimer (MAXIMUM_INCREMENT);
        HalpEnableOnboardInterrupt(CLOCK2_LEVEL,Latched); // Enable Timer1,Counter0 interrupt 

    } else {

        // 
        // MultiProcessorEnvironment Processor N
        //

        for (Index = 0; Index < sizeof(HalpIrqlMask_MC); Index += 1) 
            PCR->IrqlMask[Index] = HalpIrqlMask_MC[Index];
        for (Index = 0; Index < sizeof(HalpIrqlTable_MC); Index += 1) 
            PCR->IrqlTable[Index] = HalpIrqlTable_MC[Index];

        HalpProgramExtraTimer (MAXIMUM_INCREMENT);
        PCR->InterruptRoutine[EXTRA_CLOCK_LEVEL] = HalpClockInterrupt1;

        PCR->InterruptRoutine[PROFILE_LEVEL] = HalpProfileInterrupt;
        PCR->StallScaleFactor = HalpStallScaleFactor;
		
    }	

    return TRUE;
}
Exemple #7
0
BOOLEAN
HalpCalibrateStall (
    VOID
    )

/*++

Routine Description:

    This function calibrates the stall execution HAL service and connects
    the clock and profile interrupts to the appropriate NT service routines.

Arguments:

    None.

Return Value:

    A value of TRUE is returned if the calibration is successfully
    completed. Otherwise a value of FALSE is returned.

--*/

{

    ULONG Index;
    KIRQL OldIrql;

    //
    // Use a range of scale factors from 50ns down to 10ns assuming a
    // five instruction stall loop.
    //

    for (Index = 200; Index > 0; Index -= 10) {

        //
        // Disable all interrupts and establish calibration parameters.
        //

        KeRaiseIrql(HIGH_LEVEL, &OldIrql);

        //
        // Set the scale factor, stall count, starting stall count, and
        // ending stall count values.
        //

        PCR->StallScaleFactor = 4000 / (Index * 5);
        PCR->StallExecutionCount = 0;
        HalpStallStart = 0;
        HalpStallEnd = 0;

        //
        // Enable interrupts and stall execution.
        //

        KeLowerIrql(OldIrql);

        //
        // Stall execution for (MAXIMUM_INCREMENT / 10) * 4 us.
        //

        KeStallExecutionProcessor((MAXIMUM_INCREMENT / 10) * 4);

        //
        // If both the starting and ending stall counts have been captured,
        // then break out of loop.
        //

        if ((HalpStallStart != 0) && (HalpStallEnd != 0)) {
            break;
        }

    }

    if (Index == 0) {
	    HalDisplayString("������������������������������������������������������������ͻ\n");
    	HalDisplayString("�WARNING:     Cannot compute stall factor                    �\n");
    	HalDisplayString("�WARNING:     Using default value (250 Mhz)                  �\n");
    	HalDisplayString("������������������������������������������������������������ͼ\n");
		HalpStallScaleFactor = 0x20;
		HalpProfileCountRate = 125*1000000;
    }
	else {
    	//
    	// Compute the profile interrupt rate.
    	//

    	HalpProfileCountRate =
                	HalpProfileCountRate * ((1000 * 1000 * 10) / MAXIMUM_INCREMENT);

    	//
    	// Compute the stall execution scale factor.
    	//

    	HalpStallScaleFactor = (HalpStallEnd - HalpStallStart +
                            	((MAXIMUM_INCREMENT / 10) - 1)) / (MAXIMUM_INCREMENT / 10);

    	if (HalpStallScaleFactor <= 0) {
	        HalpStallScaleFactor = 1;
	    }
	}

    PCR->StallScaleFactor = HalpStallScaleFactor;

    //
    // Set the time increment value and connect the real clock interrupt
    // routine.
    //

    PCR->InterruptRoutine[CLOCK2_LEVEL] = (PKINTERRUPT_ROUTINE) HalpClockInterrupt;

    //
    // Write the compare register and clear the count register, and
    // connect the profile interrupt if profiling is done via count/compare interrupt.
    //

    HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT);
    PCR->InterruptRoutine[PROFILE_LEVEL] = (PKINTERRUPT_ROUTINE) HalpProfileInterrupt;
    return TRUE;
}