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; }
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; }
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; }
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; }
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; }
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; }
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; }