/*********************************************************************** * MulDiv (KERNEL32.@) * RETURNS * Result of multiplication and division * -1: Overflow occurred or Divisor was 0 * FIXME! move to correct file * * @implemented */ INT WINAPI MulDiv(INT nNumber, INT nNumerator, INT nDenominator) { LARGE_INTEGER Result; LONG Negative; /* Find out if this will be a negative result */ Negative = nNumber ^ nNumerator ^ nDenominator; /* Turn all the parameters into absolute values */ if (nNumber < 0) nNumber *= -1; if (nNumerator < 0) nNumerator *= -1; if (nDenominator < 0) nDenominator *= -1; /* Calculate the result */ Result.QuadPart = Int32x32To64(nNumber, nNumerator) + (nDenominator / 2); /* Now check for overflow */ if (nDenominator > Result.HighPart) { /* Divide the product to get the quotient and remainder */ Result.LowPart = RtlEnlargedUnsignedDivide(*(PULARGE_INTEGER)&Result, (ULONG)nDenominator, (PULONG)&Result.HighPart); /* Do the sign changes */ if ((LONG)Result.LowPart >= 0) { return (Negative >= 0) ? (LONG)Result.LowPart : -(LONG)Result.LowPart; } } /* Return overflow */ return - 1; }
VOID KiCalibrateTimeAdjustment ( PADJUST_INTERRUPT_TIME_CONTEXT Adjust ) /*++ Routine Description: This function calibrates the adjustment of time on all processors. Arguments: Adjust - Supplies the operation context. Return Value: None. --*/ { ULONG cl; ULONG divisor; BOOLEAN Enable; LARGE_INTEGER InterruptTime; ULARGE_INTEGER li; PERFINFO_PO_CALIBRATED_PERFCOUNTER LogEntry; LARGE_INTEGER NewTickCount; ULONG NewTickOffset; LARGE_INTEGER PerfCount; LARGE_INTEGER PerfFreq; LARGE_INTEGER SetTime; // // As each processor arrives, decrement the remaining processor count. If // this is the last processor to arrive, then compute the time change, and // signal all processor when to apply the performance counter change. // if (InterlockedDecrement((PLONG)&Adjust->KiNumber)) { Enable = KeDisableInterrupts(); // // It is possible to deadlock if one or more of the other processors // receives and processes a freeze request while this processor has // interrupts disabled. Poll for a freeze request until all processors // are known to be in this code. // do { KiPollFreezeExecution(); } while (Adjust->KiNumber != (ULONG)-1); // // Wait to perform the time set. // while (Adjust->Barrier); } else { // // Set timer expiration dpc to scan the timer queues once for any // expired timers. // KeRemoveQueueDpc(&KiTimerExpireDpc); KeInsertQueueDpc(&KiTimerExpireDpc, ULongToPtr(KiQueryLowTickCount() - TIMER_TABLE_SIZE), NULL); // // Disable interrupts and indicate that this processor is now // in final portion of this code. // Enable = KeDisableInterrupts(); InterlockedDecrement((PLONG) &Adjust->KiNumber); // // Adjust Interrupt Time. // InterruptTime.QuadPart = KeQueryInterruptTime() + Adjust->Adjustment; SetTime.QuadPart = Adjust->Adjustment; // // Get the current times // PerfCount = KeQueryPerformanceCounter(&PerfFreq); // // Compute performance counter for current time. // // Multiply SetTime * PerfCount and obtain 96-bit result in cl, // li.LowPart, li.HighPart. Then divide the 96-bit result by // 10,000,000 to get new performance counter value. // li.QuadPart = RtlEnlargedUnsignedMultiply((ULONG)SetTime.LowPart, (ULONG)PerfFreq.LowPart).QuadPart; cl = li.LowPart; li.QuadPart = li.HighPart + RtlEnlargedUnsignedMultiply((ULONG)SetTime.LowPart, (ULONG)PerfFreq.HighPart).QuadPart; li.QuadPart = li.QuadPart + RtlEnlargedUnsignedMultiply((ULONG)SetTime.HighPart, (ULONG)PerfFreq.LowPart).QuadPart; li.HighPart = li.HighPart + SetTime.HighPart * PerfFreq.HighPart; divisor = 10000000; Adjust->NewCount.HighPart = RtlEnlargedUnsignedDivide(li, divisor, &li.HighPart); li.LowPart = cl; Adjust->NewCount.LowPart = RtlEnlargedUnsignedDivide(li, divisor, NULL); Adjust->NewCount.QuadPart += PerfCount.QuadPart; // // Compute tick count and tick offset for current interrupt time. // NewTickCount = RtlExtendedLargeIntegerDivide(InterruptTime, KeMaximumIncrement, &NewTickOffset); // // Apply changes to interrupt time, tick count, tick offset, and the // performance counter. // KiTickOffset = KeMaximumIncrement - NewTickOffset; KeInterruptTimeBias += Adjust->Adjustment; SharedUserData->TickCount.High2Time = NewTickCount.HighPart; #if defined(_WIN64) SharedUserData->TickCountQuad = NewTickCount.QuadPart; #else SharedUserData->TickCount.LowPart = NewTickCount.LowPart; SharedUserData->TickCount.High1Time = NewTickCount.HighPart; #endif // // N.B. There is no global tick count variable on AMD64. // #if defined(_X86_) KeTickCount.High2Time = NewTickCount.HighPart; KeTickCount.LowPart = NewTickCount.LowPart; KeTickCount.High1Time = NewTickCount.HighPart; #endif #if defined(_AMD64_) SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart; *((volatile ULONG64 *)&SharedUserData->InterruptTime) = InterruptTime.QuadPart; #else SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart; SharedUserData->InterruptTime.LowPart = InterruptTime.LowPart; SharedUserData->InterruptTime.High1Time = InterruptTime.HighPart; #endif // // Apply the performance counter change. // Adjust->Barrier = 0; } KeGetCurrentPrcb()->TickOffset = KiTickOffset; #if defined(_AMD64_) KeGetCurrentPrcb()->MasterOffset = KiTickOffset; #endif HalCalibratePerformanceCounter((LONG volatile *)&Adjust->HalNumber, (ULONGLONG)Adjust->NewCount.QuadPart); // // Log an event that the performance counter has been calibrated // properly and indicate the new performance counter value. // if (PERFINFO_IS_GROUP_ON(PERF_POWER)) { LogEntry.PerformanceCounter = KeQueryPerformanceCounter(NULL); PerfInfoLogBytes(PERFINFO_LOG_TYPE_PO_CALIBRATED_PERFCOUNTER, &LogEntry, sizeof(LogEntry)); } KeEnableInterrupts(Enable); return; }
int WINAPI MulDiv ( int nNumber, int nNumerator, int nDenominator ) { LONG Negate; union { LARGE_INTEGER Product; struct { ULONG Quotient; ULONG Remainder; }; } u; // // Compute the size of the result. // Negate = nNumber ^ nNumerator ^ nDenominator; // // Get the absolute value of the operand values. // if (nNumber < 0) { nNumber = - nNumber; } if (nNumerator < 0) { nNumerator = - nNumerator; } if (nDenominator < 0) { nDenominator = - nDenominator; } // // Compute the 64-bit product of the multiplier and multiplicand // values and round. // u.Product.QuadPart = Int32x32To64(nNumber, nNumerator) + ((ULONG)nDenominator / 2); // // If there are any high order product bits, then the quotient has // overflowed. // if ((ULONG)nDenominator > u.Remainder) { // // Divide the 64-bit product by the 32-bit divisor forming a 32-bit // quotient and a 32-bit remainder. // u.Quotient = RtlEnlargedUnsignedDivide(*(PULARGE_INTEGER)&u.Product, (ULONG)nDenominator, &u.Remainder); // // Compute the final signed result. // if ((LONG)u.Quotient >= 0) { if (Negate >= 0) { return (LONG)u.Quotient; } else { return - (LONG)u.Quotient; } } } return - 1; }