Exemplo n.º 1
0
/***********************************************************************
 *           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;
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
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;
}