Пример #1
0
VOID
HalpEnableInterruptHandler (
    IN UCHAR    ReportFlags,
    IN ULONG    BusInterruptVector,
    IN ULONG    SystemInterruptVector,
    IN KIRQL    SystemIrql,
    IN VOID   (*HalInterruptServiceRoutine)(VOID),
    IN KINTERRUPT_MODE InterruptMode
    )
/*++

Routine Description:

    This function connects & registers an IDT vectors usage by the HAL.

Arguments:

Return Value:

--*/
{
    //
    // Remember which vector the hal is connecting so it can be reported
    // later on
    //
    HalpRegisterVector (ReportFlags, BusInterruptVector, SystemInterruptVector, SystemIrql);


    //
    // Connect the IDT and enable the vector now
    //

    KiSetHandlerAddressToIDT(SystemInterruptVector, HalInterruptServiceRoutine);
    HalEnableSystemInterrupt(SystemInterruptVector, SystemIrql, InterruptMode);
}
Пример #2
0
/*
 * @implemented
 */
VP_STATUS
NTAPI
VideoPortEnableInterrupt(IN PVOID HwDeviceExtension)
{
#ifndef _M_AMD64
    PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
    BOOLEAN InterruptValid;

    /* Get the device extension */
    DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);

    /* Fail if the driver didn't register an ISR */
    if (!DeviceExtension->DriverExtension->InitializationData.HwInterrupt)
    {
        /* No ISR, no interrupts */
        return ERROR_INVALID_FUNCTION;
    }

    /* Re-enable the interrupt and return */
    InterruptValid = HalEnableSystemInterrupt(DeviceExtension->InterruptVector,
                                              0,
                                              DeviceExtension->InterruptLevel);

    /* Make sure the interrupt was valid */
    ASSERT(InterruptValid == TRUE);

    /* Return to caller */
    return NO_ERROR;
#else
    /* FIXME: Function still present? If so what to use instead of HalEnableSystemInterrupt? */
    UNIMPLEMENTED;
    return ERROR_INVALID_FUNCTION;
#endif
}
Пример #3
0
BOOLEAN
NTAPI
KeConnectInterrupt(IN PKINTERRUPT Interrupt)
{
    PVOID CurrentHandler;

    ASSERT(Interrupt->Vector <= MAXIMUM_IDTVECTOR);
    ASSERT(Interrupt->Number < KeNumberProcessors);
    ASSERT(Interrupt->Irql <= HIGH_LEVEL);

    /* Check if its already connected */
    if (Interrupt->Connected) return TRUE;

    /* Query the current handler */
    CurrentHandler = KeQueryInterruptHandler(Interrupt->Vector);

    /* Check if the vector is already unused */
    if ((CurrentHandler >= (PVOID)KiUnexpectedRange) &&
        (CurrentHandler <= (PVOID)KiUnexpectedRangeEnd))
    {
        /* Initialize the list for chained interrupts */
        InitializeListHead(&Interrupt->InterruptListEntry);

        /* Set normal dispatch address */
        Interrupt->DispatchAddress = KiInterruptDispatch;

        /* Set the new handler */
        KeRegisterInterruptHandler(Interrupt->Vector,
                                   Interrupt->DispatchCode);

        if (!HalEnableSystemInterrupt(Interrupt->Vector,
                                      Interrupt->Irql,
                                      Interrupt->Mode))
        {
            /* Didn't work, restore old handler */
            DPRINT1("HalEnableSystemInterrupt failed\n");
            KeRegisterInterruptHandler(Interrupt->Vector, CurrentHandler);
            return FALSE;
        }

        /* Mark as connected */
        Interrupt->Connected = TRUE;
    }
    else
    {
        // later
        __debugbreak();
    }

    return TRUE;
}
Пример #4
0
BOOLEAN
KeConnectInterrupt (
    __inout PKINTERRUPT Interrupt
    )

/*++

Routine Description:

    This function connects an interrupt object to the interrupt vector
    specified by the interrupt object. If the interrupt object is already
    connected, or an attempt is made to connect to an interrupt that cannot
    be connected, then a value of FALSE is returned. Else the specified
    interrupt object is connected to the interrupt vector, the connected
    state is set to TRUE, and TRUE is returned as the function value.

Arguments:

    Interrupt - Supplies a pointer to a control object of type interrupt.

Return Value:

    If the interrupt object is already connected or an attempt is made to
    connect to an interrupt vector that cannot be connected, then a value
    of FALSE is returned. Else a value of TRUE is returned.

--*/

{
    DISPATCH_INFO DispatchInfo;
    BOOLEAN Connected;
    BOOLEAN ConnectError;
    BOOLEAN Enabled;
    KIRQL Irql;
    CCHAR Number;
    KIRQL OldIrql;
    ULONG Vector;

    //
    // If the interrupt object is already connected, the interrupt vector
    // number is invalid, an attempt is being made to connect to a vector
    // that cannot be connected, the interrupt request level is invalid, or
    // the processor number is invalid, then do not connect the interrupt
    // object. Else connect interrupt object to the specified vector and
    // establish the proper interrupt dispatcher.
    //

    Connected = FALSE;
    ConnectError = FALSE;
    Irql = Interrupt->Irql;
    Number = Interrupt->Number;
    Vector = Interrupt->Vector;
    if ( !((Irql > HIGH_LEVEL) ||
           (Number >= KeNumberProcessors) ||
           (Interrupt->SynchronizeIrql < Irql) ||
           (Interrupt->FloatingSave)    // R0 x87 usage not supported on x86
          )
       ) {

        //
        //
        // Set system affinity to the specified processor.
        //

        KeSetSystemAffinityThread((KAFFINITY)(1<<Number));

        //
        // Raise IRQL to dispatcher level and lock dispatcher database.
        //

        KiLockDispatcherDatabase(&OldIrql);

        //
        // Is interrupt object already connected?
        //

        if (!Interrupt->Connected) {

            //
            // Determine interrupt dispatch vector
            //

            KiGetVectorInfo (
                Vector,
                &DispatchInfo
                );

            //
            // If dispatch vector is not connected, then connect it
            //

            if (DispatchInfo.Type == NoConnect) {
                Connected = TRUE;
                Interrupt->Connected = TRUE;

                //
                // Connect interrupt dispatch to interrupt object dispatch code
                //

                InitializeListHead(&Interrupt->InterruptListEntry);
                KiConnectVectorAndInterruptObject (Interrupt, NormalConnect);

                //
                // Enabled system vector
                //

                Enabled = HalEnableSystemInterrupt(Vector, Irql, Interrupt->Mode);
                if (!Enabled) {
                    ConnectError = TRUE;
                }


            } else if (DispatchInfo.Type != UnknownConnect &&
                       Interrupt->ShareVector  &&
                       DispatchInfo.Interrupt->ShareVector  &&
                       DispatchInfo.Interrupt->Mode == Interrupt->Mode) {

                //
                // Vector is already connected as sharable.  New vector is sharable
                // and modes match.  Chain new vector.
                //

                Connected = TRUE;
                Interrupt->Connected = TRUE;

                ASSERT (Irql <= SYNCH_LEVEL);

                //
                // If not already using chained dispatch handler, set it up
                //

                if (DispatchInfo.Type != ChainConnect) {
                    KiConnectVectorAndInterruptObject (DispatchInfo.Interrupt, ChainConnect);
                }

                //
                // Add to tail of chained dispatch
                //

                InsertTailList(
                    &DispatchInfo.Interrupt->InterruptListEntry,
                    &Interrupt->InterruptListEntry
                    );

            }
        }

        //
        // Unlock dispatcher database and lower IRQL to its previous value.
        //

        KiUnlockDispatcherDatabase(OldIrql);

        //
        // Set system affinity back to the original value.
        //

        KeRevertToUserAffinityThread();
    }

    if (Connected  &&  ConnectError) {
#if DBG
        DbgPrint ("HalEnableSystemInterrupt failed\n");
#endif
        KeDisconnectInterrupt (Interrupt);
        Connected = FALSE;
    }

    //
    // Return whether interrupt was connected to the specified vector.
    //

    return Connected;
}
Пример #5
0
/*
 * @implemented
 */
BOOLEAN
NTAPI
KeConnectInterrupt(IN PKINTERRUPT Interrupt)
{
    BOOLEAN Connected, Error, Status;
    KIRQL Irql, OldIrql;
    UCHAR Number;
    ULONG Vector;
    DISPATCH_INFO Dispatch;

    /* Get data from interrupt */
    Number = Interrupt->Number;
    Vector = Interrupt->Vector;
    Irql = Interrupt->Irql;

    /* Validate the settings */
    if ((Irql > HIGH_LEVEL) ||
        (Number >= KeNumberProcessors) ||
        (Interrupt->SynchronizeIrql < Irql) ||
        (Interrupt->FloatingSave))
    {
        return FALSE;
    }

    /* Set defaults */
    Connected = FALSE;
    Error = FALSE;

    /* Set the system affinity and acquire the dispatcher lock */
    KeSetSystemAffinityThread(1 << Number);
    OldIrql = KiAcquireDispatcherLock();

    /* Check if it's already been connected */
    if (!Interrupt->Connected)
    {
        /* Get vector dispatching information */
        KiGetVectorDispatch(Vector, &Dispatch);

        /* Check if the vector is already connected */
        if (Dispatch.Type == NoConnect)
        {
            /* Do the connection */
            Interrupt->Connected = Connected = TRUE;

            /* Initialize the list */
            InitializeListHead(&Interrupt->InterruptListEntry);

            /* Connect and enable the interrupt */
            KiConnectVectorToInterrupt(Interrupt, NormalConnect);
            Status = HalEnableSystemInterrupt(Vector, Irql, Interrupt->Mode);
            if (!Status) Error = TRUE;
        }
        else if ((Dispatch.Type != UnknownConnect) &&
                (Interrupt->ShareVector) &&
                (Dispatch.Interrupt->ShareVector) &&
                (Dispatch.Interrupt->Mode == Interrupt->Mode))
        {
            /* The vector is shared and the interrupts are compatible */
            Interrupt->Connected = Connected = TRUE;

            /* FIXME */
            // ASSERT(Irql <= SYNCH_LEVEL);

            /* Check if this is the first chain */
            if (Dispatch.Type != ChainConnect)
            {
                /* This is not supported */
                ASSERT(Dispatch.Interrupt->Mode != Latched);

                /* Setup the chainned handler */
                KiConnectVectorToInterrupt(Dispatch.Interrupt, ChainConnect);
            }

            /* Insert into the interrupt list */
            InsertTailList(&Dispatch.Interrupt->InterruptListEntry,
                           &Interrupt->InterruptListEntry);
        }
    }

    /* Unlock the dispatcher and revert affinity */
    KiReleaseDispatcherLock(OldIrql);
    KeRevertToUserAffinityThread();

    /* Check if we failed while trying to connect */
    if ((Connected) && (Error))
    {
        DPRINT1("HalEnableSystemInterrupt failed\n");
        KeDisconnectInterrupt(Interrupt);
        Connected = FALSE;
    }

    /* Return to caller */
    return Connected;
}
Пример #6
0
BOOLEAN
HalpInitializeLegoInterrupts(
    VOID
    )

/*++

Routine Description:

    This routine initializes the structures necessary for EISA & PCI operations
    and connects the intermediate interrupt dispatchers. It also initializes 
    the ISA interrupt controller; Lego's SIO-based interrupt controller is
    compatible with Avanti and with the EISA interrupt contoller used on Jensen.

Arguments:

    None.

Return Value:

    If the second level interrupt dispatchers are connected, then a value of
    TRUE is returned. Otherwise, a value of FALSE is returned.

--*/

{
    KIRQL oldIrql;

    //
    // Initialize the EISA NMI interrupt.
    //

    HalpInitializeNMI();

    //
    // Directly connect the ISA interrupt dispatcher to the level for
    // ISA bus interrupt.
    //
    // N.B. This vector is reserved for exclusive use by the HAL (see
    //      interrupt initialization.
    //

    PCR->InterruptRoutine[PIC_VECTOR] = HalpSioDispatch;
    HalEnableSystemInterrupt(PIC_VECTOR, ISA_DEVICE_LEVEL, LevelSensitive);

    //
    // Initialize the interrupt dispatchers for PCI & Server management interrupts.
    //

    KeInitializeInterrupt( &HalpPciInterrupt,
                           HalpPciInterruptHandler,
                           (PVOID) HalpLegoPciInterruptMasterQva, // Service Context
                           (PKSPIN_LOCK)NULL,
                           PCI_VECTOR,
                           PCI_DEVICE_LEVEL,
                           PCI_DEVICE_LEVEL,
                           LevelSensitive,
                           TRUE,
                           0,
                           FALSE
                           );

    if (!KeConnectInterrupt( &HalpPciInterrupt )) {
        return(FALSE);
    }

    KeInitializeInterrupt( &HalpServerMgmtInterrupt,
                           HalpServerMgmtInterruptHandler,
                           (PVOID) HalpLegoServerMgmtQva,  // Service Context is...
                           (PKSPIN_LOCK)NULL,
                           SERVER_MGMT_VECTOR,
                           SERVER_MGMT_LEVEL,
                           SERVER_MGMT_LEVEL,
                           LevelSensitive,
                           TRUE,
                           0,
                           FALSE
                           );

    if (!KeConnectInterrupt( &HalpServerMgmtInterrupt )) {
        return(FALSE);
    }

    //
    // Intitialize interrupt controller
    //

    KeRaiseIrql(ISA_DEVICE_LEVEL, &oldIrql);

    //
    // We must initialize the SIO's PICs, for ISA interrupts.
    //

    HalpInitializeSioInterrupts();

    //
    // There's no initialization required for the Lego PCI interrupt
    // "controller," as it's the wiring of the hardware, rather than a
    // PIC like the 82c59 that directs interrupts.  We do set the IMR to
    // zero to disable all interrupts, initially.
    //

    HalpInitializePciInterrupts();

    //
    // Setup server management interrupts.
    // On return, server management interrupts will be unmasked,
    // but secondary dispatch will not be performed unless appropriate
    // boolean has been set due to enable call.
    //

    HalpInitializeServerMgmtInterrupts();

    //
    // Restore the IRQL.
    //

    KeLowerIrql(oldIrql);

    //
    // Initialize the EISA DMA mode registers to a default value.
    // Disable all of the DMA channels except channel 4 which is the
    // cascade of channels 0-3.
    //

    WRITE_PORT_UCHAR(
        &((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort.AllMask,
        0x0F
        );

    WRITE_PORT_UCHAR(
        &((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort.AllMask,
        0x0E
        );

    return(TRUE);
}
Пример #7
0
BOOLEAN
KeConnectInterrupt (
    IN PKINTERRUPT Interrupt
    )

/*++

Routine Description:

    This function connects an interrupt object to the interrupt vector
    specified by the interrupt object. If the interrupt object is already
    connected, or an attempt is made to connect to an interrupt that cannot
    be connected, then a value of FALSE is returned. Else the specified
    interrupt object is connected to the interrupt vector, the connected
    state is set to TRUE, and TRUE is returned as the function value.

Arguments:

    Interrupt - Supplies a pointer to a control object of type interrupt.

Return Value:

    If the interrupt object is already connected or an attempt is made to
    connect to an interrupt vector that cannot be connected, then a value
    of FALSE is returned. Else a value of TRUE is returned.

--*/

{

    BOOLEAN Connected;
    PKINTERRUPT Interruptx;
    KIRQL Irql;
    CHAR Number;
    KIRQL OldIrql;
    KIRQL PreviousIrql;
    ULONG Vector;

    //
    // If the interrupt object is already connected, the interrupt vector
    // number is invalid, an attempt is being made to connect to a vector
    // that cannot be connected, the interrupt request level is invalid,
    // the processor number is invalid, of the interrupt vector is less
    // than or equal to the highest level and it not equal to the specified
    // IRQL, then do not connect the interrupt object. Else connect interrupt
    // object to the specified vector and establish the proper interrupt
    // dispatcher.
    //

    Connected = FALSE;
    Irql = Interrupt->Irql;
    Number = Interrupt->Number;
    Vector = Interrupt->Vector;
    if (
        (Vector < MAXIMUM_VECTOR) &&            // will fit in interrupt table
        (Irql <= HIGH_LEVEL) &&                 // is at a reasonable priority
        (Number < KeNumberProcessors) &&        // can run on a cpu we have
        (
            (Vector > HIGH_LEVEL) ||            // and is either EISA or
            ((PCR->ReservedVectors & (1 << Vector)) == 0) // is NOT reserved
        )
    ) {

        //
        //
        // Set system affinity to the specified processor.
        //

        KeSetSystemAffinityThread((KAFFINITY)(1 << Number));

        //
        // Raise IRQL to dispatcher level and lock dispatcher database.
        //

        KiLockDispatcherDatabase(&OldIrql);

        //
        // If the specified interrupt vector is not connected, then
        // connect the interrupt vector to the interrupt dispatcher
        // and set the new interrupt mode and enable masks.
        // Else if the interrupt is
        // already chained, then add the new interrupt object at the end
        // of the chain. If the interrupt vector is not chained, then
        // start a chain with the previous interrupt object at the front
        // of the chain. The interrupt mode of all interrupt objects in
        // a chain must be the same.
        //

        if (Interrupt->Connected == FALSE) {
            if (PCR->InterruptRoutine[Vector] ==
                (PKINTERRUPT_ROUTINE)(&KxUnexpectedInterrupt.DispatchCode)) {
                Connected = TRUE;
                Interrupt->Connected = TRUE;
                if (Interrupt->FloatingSave) {
                    Interrupt->DispatchAddress = KiFloatingDispatch;

                } else {
                    if (Interrupt->Irql == Interrupt->SynchronizeIrql) {
#if defined(NT_UP)
                        Interrupt->DispatchAddress =
                                 (PKINTERRUPT_ROUTINE)Interrupt->ServiceRoutine;
#else
                        Interrupt->DispatchAddress =
                                 (PKINTERRUPT_ROUTINE)KiInterruptDispatchSame;
#endif

                    } else {
                        Interrupt->DispatchAddress =
                                 (PKINTERRUPT_ROUTINE)KiInterruptDispatchRaise;
                    }
                }

                //
                // Copy the function descriptor for the Dispatch routine
                // into DispatchCode.  This will be used by KiInterruptEx-
                // ception to dispatch the interrupt.
                //

                Interrupt->DispatchCode[0] =
                                *(PULONG)(Interrupt->DispatchAddress);
                Interrupt->DispatchCode[1] =
                                *(((PULONG)(Interrupt->DispatchAddress))+1);
                PCR->InterruptRoutine[Vector] =
                            (PKINTERRUPT_ROUTINE)Interrupt->DispatchCode;

                HalEnableSystemInterrupt(Vector, Irql, Interrupt->Mode);

            } else if (Interrupt->ShareVector) {
                Interruptx = CONTAINING_RECORD(PCR->InterruptRoutine[Vector],
                                               KINTERRUPT,
                                               DispatchCode[0]);
                if (Interruptx->ShareVector &&
                    Interrupt->Mode == Interruptx->Mode) {
                    Connected = TRUE;
                    Interrupt->Connected = TRUE;
                    KeRaiseIrql((KIRQL)(max(Irql, SYNCH_LEVEL)), &PreviousIrql);
                    if (Interruptx->DispatchAddress !=
                                    (PKINTERRUPT_ROUTINE)KiChainedDispatch) {
                        InitializeListHead(&Interruptx->InterruptListEntry);
                        Interruptx->DispatchAddress =
                                        (PKINTERRUPT_ROUTINE)KiChainedDispatch;
                        Interruptx->DispatchCode[0] =
                                        *(PULONG)KiChainedDispatch;
                        Interruptx->DispatchCode[1] =
                                        *(((PULONG)KiChainedDispatch)+1);
                    }

                    InsertTailList(&Interruptx->InterruptListEntry,
                                   &Interrupt->InterruptListEntry);
                    KeLowerIrql(PreviousIrql);
                }
            }
        }

        //
        // Unlock dispatcher database and lower IRQL to its previous value.
        //

        KiUnlockDispatcherDatabase(OldIrql);

        //
        // Set system affinity back to the original value.
        //

        KeRevertToUserAffinityThread();
    }

    //
    // Return whether interrupt was connected to the specified vector.
    //

    return Connected;
}
Пример #8
0
BOOLEAN
HalpInitializePCIInterrupts (
    VOID
    )

/*++

Routine Description:

    This routine initializes the structures necessary for ISA & PCI operations
    and connects the intermediate interrupt dispatcher. 

Arguments:

    None.

Return Value:

    If the second level interrupt dispatcher is connected, then a value of
    TRUE is returned. Otherwise, a value of FALSE is returned.

--*/

{

    KIRQL oldIrql;


    //
    // Initialize the EISA NMI interrupt.
    //

    HalpInitializeNMI();


    //
    // Directly connect the ISA interrupt dispatcher to the level for
    // ISA bus interrupt.
    //
    // N.B. This vector is reserved for exclusive use by the HAL (see
    //      interrupt initialization.
    //

#ifdef IDLE_PROCESSOR
    PCR->InterruptRoutine[PIC_VECTOR] = PreHalpSioDispatch;
#else
    PCR->InterruptRoutine[PIC_VECTOR] = HalpSioDispatch;
#endif
    HalEnableSystemInterrupt(PIC_VECTOR, ISA_DEVICE_LEVEL, LevelSensitive);


    //
    // Intitialize interrupt controller
    //

    KeRaiseIrql(ISA_DEVICE_LEVEL, &oldIrql);


    //
    // Initialize the PCI-ISA bridge interrupt controller
    //

    HalpInitializeSioInterrupts();

    //
    // Restore IRQL level.
    //

    KeLowerIrql(oldIrql);

    //
    // Initialize the DMA mode registers to a default value.
    // Disable all of the DMA channels except channel 4 which is the
    // cascade of channels 0-3.
    //

    WRITE_PORT_UCHAR(
        &((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort.AllMask,
        0x0F
        );

    WRITE_PORT_UCHAR(
        &((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort.AllMask,
        0x0E
        );

    return(TRUE);
}
Пример #9
0
VOID
NTAPI
HalpInitializeTsc(VOID)
{
    ULONG_PTR Flags;
    KIDTENTRY OldIdtEntry, *IdtPointer;
    PKPCR Pcr = KeGetPcr();
    UCHAR RegisterA, RegisterB;

    /* Check if the CPU supports RDTSC */
    if (!(KeGetCurrentPrcb()->FeatureBits & KF_RDTSC))
    {
        KeBugCheck(HAL_INITIALIZATION_FAILED);
    }

     /* Save flags and disable interrupts */
    Flags = __readeflags();
    _disable();

    /* Enable the periodic interrupt in the CMOS */
    RegisterB = HalpReadCmos(RTC_REGISTER_B);
    HalpWriteCmos(RTC_REGISTER_B, RegisterB | RTC_REG_B_PI);

    /* Modify register A to RTC_MODE to get SAMPLE_FREQENCY */
    RegisterA = HalpReadCmos(RTC_REGISTER_A);
    RegisterA = (RegisterA & 0xF0) | RTC_MODE;
    HalpWriteCmos(RTC_REGISTER_A, RegisterA);

    /* Save old IDT entry */
    IdtPointer = KiGetIdtEntry(Pcr, HalpRtcClockVector);
    OldIdtEntry = *IdtPointer;

    /* Set the calibration ISR */
    KeRegisterInterruptHandler(HalpRtcClockVector, TscCalibrationISR);

    /* Reset TSC value to 0 */
    __writemsr(MSR_RDTSC, 0);

    /* Enable the timer interupt */
    HalEnableSystemInterrupt(HalpRtcClockVector, CLOCK_LEVEL, Latched);

    /* Read register C, so that the next interrupt can happen */
    HalpReadCmos(RTC_REGISTER_C);;

    /* Wait for completion */
    _enable();
    while (TscCalibrationPhase < NUM_SAMPLES) _ReadWriteBarrier();
    _disable();

    /* Disable the periodic interrupt in the CMOS */
    HalpWriteCmos(RTC_REGISTER_B, RegisterB & ~RTC_REG_B_PI);

    /* Disable the timer interupt */
    HalDisableSystemInterrupt(HalpRtcClockVector, CLOCK_LEVEL);

    /* Restore old IDT entry */
    *IdtPointer = OldIdtEntry;

    /* Calculate an average, using simplified linear regression */
    HalpCpuClockFrequency.QuadPart = DoLinearRegression(NUM_SAMPLES - 1,
                                                        TscCalibrationArray);

    /* Restore flags */
    __writeeflags(Flags);

}
Пример #10
0
VOID
HalStartProfileInterrupt (
    KPROFILE_SOURCE ProfileSource
    )

/*++

Routine Description:

    This routine turns on the profile interrupt.

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

Arguments:

    None.

Return Value:

    None.

--*/

{
    ULONG PerformanceCounter;
    ULONG MuxControl;
    ULONG EventCount;

    //
    // Check input to see if we are turning on a source that is
    // supported.  If it is unsupported, just return.
    //

    if ((ProfileSource > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) ||
        (!HalpProfileMapping[ProfileSource].Supported)) {
        return;
    }

    //
    // Set the performance counter within the processor to begin
    // counting total cycles.
    //
    PerformanceCounter = HalpProfileMapping[ProfileSource].Counter;
    MuxControl = HalpProfileMapping[ProfileSource].MuxControl;

    if (PerformanceCounter == Ev4PerformanceCounter0) {

        HalpProfileSource0 = ProfileSource;
        EventCount = (HalpProfileMapping[ProfileSource].EventCount == Ev4CountEvents2xx12) ?
                     Ev4EventCountHigh :
                     Ev4EventCountLow;
        HalpWritePerformanceCounter( PerformanceCounter,
                                     TRUE,
                                     MuxControl,
                                     EventCount );

        PCRProfileCountReload[0] = HalpProfileMapping[ProfileSource].NumberOfTicks;
        PCRProfileCount[0] = HalpProfileMapping[ProfileSource].NumberOfTicks;

        //
        // Enable the performance counter interrupt.
        //

        HalEnableSystemInterrupt ( PC0_VECTOR,
                                   PROFILE_LEVEL,
                                   LevelSensitive );


    } else {

        HalpProfileSource1 = ProfileSource;
        EventCount = (HalpProfileMapping[ProfileSource].EventCount == Ev4CountEvents2xx12) ?
                     Ev4EventCountLow :
                     Ev4EventCountHigh;
        HalpWritePerformanceCounter( PerformanceCounter,
                                     TRUE,
                                     MuxControl,
                                     EventCount );

        PCRProfileCountReload[1] = HalpProfileMapping[ProfileSource].NumberOfTicks;
        PCRProfileCount[1] = HalpProfileMapping[ProfileSource].NumberOfTicks;

        //
        // Enable the performance counter interrupt.
        //

        HalEnableSystemInterrupt ( PC1_VECTOR,
                                   PROFILE_LEVEL,
                                   LevelSensitive );
    }

    return;
}
Пример #11
0
/*++

Routine Description:

    Note that all interrupts are blocked on entry since
    this routine is called from HalInitializeProcessor.
    Initialize this processor's local and I/O APIC units.

Arguments:

    Processor - Supplies a logical processor number

Return Value:

    None.

--*/
VOID
CbusInitializeIOApic(
IN ULONG Processor,
IN PVOID PhysicalApicLocation,
IN ULONG RedirVector,
IN ULONG RebootVector,
IN ULONG IrqPolarity
)
{
        ULONG                           ProcessorBit;
        ULONG                           ApicIDBit;
        ULONG                           ApicBusNumber;
        ULONG                           RedirectionAddress;
        REDIRECTION_T   		RedirectionEntry = { 0 };

        if (CbusIOApicCount >= MAX_CBUS_ELEMENTS) {
                return;
        }

        CbusIOApic[CbusIOApicCount] =
                (PVOID) HalpMapPhysicalMemoryWriteThrough (
	                        PhysicalApicLocation,
	                        (ULONG)ADDRESS_AND_SIZE_TO_SPAN_PAGES(
	                                PhysicalApicLocation, IO_APIC_SIZE));

        CbusApicBrandIOUnitID(Processor);

        //
        // Disable all 8259 inputs except the irq0 clock.
        // remember the irq0 clock and the irq13 DMA
        // chaining interrupts are internal to the Intel EISA
        // chipset (specifically, the ISP chip), and if the HAL
        // wants to enable them, it must be done here.
        // This is done by enabling the 8259 ISP to send them
        // to the processor(s) via the APIC.  However, the Corollary HAL
        // currently uses the local APIC timers for clocks.  The irq0
        // clock is enabled solely for the performance counter because
        // we want to use a separate clock for it, (rather than the system
        // timer which creates race conditions).
        //
        // Note that all other EISA bus device interrupts only need to
        // be enabled in the APIC for processors to see them.
        //
	CbusDisable8259s(0xFFFE);

        //
        // All redirection table entries are disabled by default when the
        // processor emerges from reset.  Later, each entry is individually
        // enabled from their respective drivers via HalEnableSystemInterrupt.

        //
        // Indicate the APIC (not the 8259s) will now handle provide
        // the interrupt vectors to the processor during an INTA cycle.
        // This is done by writing to the APMode port.  Note that at this
        // time we will also sync the APIC polarity control registers with
        // the ELCR.  Since irq0 has no polarity control, the hardware
        // uses bit0 for the APMode enable, so make sure this bit is on too.
        //

        CbusLocalApic->APMode = (UCHAR)((IrqPolarity & 0xFF) | 0x1);
        CbusLocalApic->PolarityPortHigh = (UCHAR)((IrqPolarity >> 8) & 0xFF);

        //
        // Create an interrupt gate so other processors can
        // let the boot processor know about desired I/O APIC
        // modifications (ie: enabling & disabling interrupts).
        // This is necessary since each processor can only access
        // his own I/O APIC, and only the boot processor's I/O APIC
        // is attached to the EISA bus interrupt inputs.  this only
        // needs to be done once regardless of how many I/O APICs are
        // present in the system.
        //

        if (CbusIOApicCount == 0) {
                KiSetHandlerAddressToIDT(RedirVector, IOApicUpdate);
                HalEnableSystemInterrupt(RedirVector, IPI_LEVEL, Latched);

                KiSetHandlerAddressToIDT(RebootVector, CbusRebootHandler);
                HalEnableSystemInterrupt(RebootVector, IPI_LEVEL, Latched);
        }

#define TRAP2	2

        ProcessorBit = (ULONG) KeGetPcr()->HalReserved[PCR_BIT];

        ApicIDBit = (ProcessorBit << APIC_BIT_TO_ID);

	/*
	 * support NMIs from the EISA bridge as trap 2.
	 */
        RedirectionEntry.ra.Mask = APIC_INTR_UNMASKED;
        RedirectionEntry.ra.Trigger = APIC_LEVEL;
        RedirectionEntry.ra.Dest_mode = APIC_LOGICAL_MODE;
        RedirectionEntry.ra.Vector = TRAP2;
        RedirectionEntry.ra.Destination = ApicIDBit;
	RedirectionEntry.ra.Delivery_mode = APIC_INTR_FIXED;

        //
        // support multiple I/O buses by initializiing
        // our current bus number...
        //
        ApicBusNumber = CbusIOApicCount;

        RedirectionAddress = (ULONG)CbusApicLinkVector((PBUS_HANDLER)0,
                                                (ULONG)-1, TRAP2);

	WRITE_IOAPIC_ULONG(ApicBusNumber, RedirectionAddress + 1,
				RedirectionEntry.ra.Destination);
	WRITE_IOAPIC_ULONG(ApicBusNumber, RedirectionAddress,
				RedirectionEntry.rb.dword1);

        //
        // we've initialized another I/O APIC...
        //
        CbusIOApicCount++;
}
Пример #12
0
/*++

Routine Description:

    Called by each processor to initialize his local APIC.
    The first processor to run this routine will map the
    local APICs for all processors.

    Note that all interrupts are blocked on entry since
    we are being called from HalInitializeProcessor().

Arguments:

    Processor - Supplies a logical processor number

Return Value:

    None.

--*/
VOID
CbusInitializeLocalApic(
IN ULONG Processor,
IN PVOID PhysicalApicLocation,
IN ULONG SpuriousVector
)
{
        ULONG           ProcessorBit;
        ULONG           ApicIDBit;
        REDIRECTION_T   RedirectionEntry = { 0 };

        //
        // If the APIC mapping has not been set up yet,
        // do it now.  Given the NT startup architecture,
        // this will always be done by the boot processor.
        //
        // We map in the APIC into global space instead of in
        // the PCR because all processors see it at the
        // same _physical_ address.  Note the page is mapped PWT.
        //

        //
        // Note that all idle threads will share a common
        // page directory, and the HAL PDE is inherited when
        // new processes are created.  Hence, a single
        // HalpMapMemory for the APIC is enough for all
        // processors to be able to see their APICs.
        //
        if (!CbusLocalApic) {
                CbusLocalApic = (PAPIC_REGISTERS) HalpMapPhysicalMemoryWriteThrough (
                                PhysicalApicLocation,
                                (ULONG)ADDRESS_AND_SIZE_TO_SPAN_PAGES(
                                PhysicalApicLocation, LOCAL_APIC_SIZE));
        }
        
        (PTASKPRI) KeGetPcr()->HalReserved[PCR_TASKPRI] =
                 &CbusLocalApic->ApicTaskPriority;

        //
        // Here we initialize our destination format and
        // logical destination registers so that we can get IPIs
        // from other processors.
        //
        // Specify full decode mode in the destination format register -
        // ie: each processor sets only his own bit, and a "match" requires
        // that at least one bit match.  The alternative is encoded mode,
        // in which _ALL_ encoded bits must match the sender's target for
        // this processor to see the sent IPI.
        //
        CbusLocalApic->ApicDestinationFormat = APIC_ALL_PROCESSORS;

        //
        // the logical destination register is what the redirection destination
        // entry compares against.  only the high 8 bits will be supported
        // in Intel's future APICs, although this isn't documented anywhere!
        //
        ProcessorBit = KeGetPcr()->HalReserved[PCR_BIT];

        ApicIDBit = (ProcessorBit << APIC_BIT_TO_ID);

        CbusLocalApic->ApicLogicalDestination = ApicIDBit;

        //
        // designate the spurious interrupt vector we want to see,
        // and inform this processor's APIC to enable interrupt
        // acceptance.
        //
        CbusLocalApic->ApicSpuriousVector =
                                SpuriousVector | LOCAL_APIC_ENABLE;

        //
        // as each processor comes online here, we must have ALL
        // processors resync their arbitration IDs to take into
        // account the new processor.  note that we will set:
        // arb id == APIC id == processor number.
        //
        // the strange ID setting is to satisfy Intel's need for
        // uniqueness amongst I/O and local unit ID numbering.
        //

        CbusLocalApic->LocalUnitID = ((2 * Processor + 1) << APIC_BIT_TO_ID);

        //
        // sync up our new ID with everyone else
        //

        CbusApicArbsync();

        //
        // Create the NMI routing linkage for this processor
        // It is set as level sensitive, enabled and generating NMI trap 2.
        //

        RedirectionEntry.ra.Trigger = APIC_LEVEL;
        RedirectionEntry.ra.Mask = APIC_INTR_UNMASKED;
        RedirectionEntry.ra.Delivery_mode = APIC_INTR_NMI;
        RedirectionEntry.ra.Vector = 2;
        RedirectionEntry.ra.Destination = ApicIDBit;
        CbusLocalApic->ApicLocalInt1 = RedirectionEntry;

        //
        // Create the spurious interrupt IDT entry for this processor
        //

        KiSetHandlerAddressToIDT(SpuriousVector, HalpSpuriousInterrupt);

        //
        // we must specify HIGH_LEVEL when we enable the spurious vector
        // here because it will overwrite the CbusVectorToIrql[] entry
        // for the HIGH_LEVEL (0xFF!).  the spurious vector really only
        // needs an IDT entry and doesn't need any other software tables,
        // but make the enable call for tracking purposes.
        //
        HalEnableSystemInterrupt(SpuriousVector, HIGH_LEVEL, Latched);

	//
	// start off at IRQL 0 - we are still protected by cli.
	//
        CbusLocalApic->ApicTaskPriority.rb.LowDword = 0;
}