Ejemplo n.º 1
0
BOOLEAN
Ke386SetIoAccessMap (
    ULONG MapNumber,
    PKIO_ACCESS_MAP IoAccessMap
    )

/*++

Routine Description:

    The specified i/o access map will be set to match the
    definition specified by IoAccessMap (i.e. enable/disable
    those ports) before the call returns.  The change will take
    effect on all processors.

    Ke386SetIoAccessMap does not give any process enhanced I/O
    access, it merely defines a particular access map.

Arguments:

    MapNumber - Number of access map to set.  Map 0 is fixed.

    IoAccessMap - Pointer to bitvector (64K bits, 8K bytes) which
           defines the specified access map.  Must be in
           non-paged pool.

Return Value:

    TRUE if successful.  FALSE if failure (attempt to set a map
    which does not exist, attempt to set map 0)

--*/

{

    PKPROCESS CurrentProcess;
    KIRQL OldIrql;
    PKPRCB Prcb;
    PVOID pt;
    KAFFINITY TargetProcessors;

    //
    // Reject illegal requests
    //

    if ((MapNumber > IOPM_COUNT) || (MapNumber == IO_ACCESS_MAP_NONE)) {
        return FALSE;
    }

    //
    // Acquire the context swap lock so a context switch will not occur.
    //

    KiLockContextSwap(&OldIrql);

    //
    // Compute set of active processors other than this one, if non-empty
    // IPI them to set their maps.
    //

    Prcb = KeGetCurrentPrcb();

#if !defined(NT_UP)

    TargetProcessors = KeActiveProcessors & ~Prcb->SetMember;
    if (TargetProcessors != 0) {
        KiIpiSendPacket(TargetProcessors,
                        KiSetIoMap,
                        IoAccessMap,
                        (PVOID)MapNumber,
                        NULL);
    }

#endif

    //
    // Copy the IOPM map and load the map for the current process.
    //

    pt = &(KiPcr()->TSS->IoMaps[MapNumber-1].IoMap);
    RtlMoveMemory(pt, (PVOID)IoAccessMap, IOPM_SIZE);
    CurrentProcess = Prcb->CurrentThread->ApcState.Process;
    KiPcr()->TSS->IoMapBase = CurrentProcess->IopmOffset;

    //
    // Wait until all of the target processors have finished copying the
    // new map.
    //

#if !defined(NT_UP)

    if (TargetProcessors != 0) {
        KiIpiStallOnPacketTargets(TargetProcessors);
    }

#endif

    //
    // Restore IRQL and unlock the context swap lock.
    //

    KiUnlockContextSwap(OldIrql);
    return TRUE;
}
Ejemplo n.º 2
0
VOID
KeFlushEntireTb (
    IN BOOLEAN Invalid,
    IN BOOLEAN AllProcessors
    )

/*++

Routine Description:

    This function flushes the entire translation buffer (TB) on all
    processors that are currently running threads which are children
    of the current process or flushes the entire translation buffer
    on all processors in the host configuration.

Arguments:

    Invalid - Supplies a boolean value that specifies the reason for
        flushing the translation buffer.

    AllProcessors - Supplies a boolean value that determines which
        translation buffers are to be flushed.

Return Value:

    None.


--*/

{

    KIRQL OldIrql;
    KAFFINITY TargetProcessors;
    PKTHREAD Thread;
    BOOLEAN NeedTbFlush = FALSE;

    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    OldIrql = KeRaiseIrqlToSynchLevel();

#if !defined(NT_UP)
    TargetProcessors = KeActiveProcessors;
    TargetProcessors &= PCR->NotMember;
    if (TargetProcessors != 0) {
        KiIpiSendPacket(TargetProcessors,
                        KiFlushEntireTbTarget,
                        (PVOID)NeedTbFlush,
                        NULL,
                        NULL);
    }

    if (PsGetCurrentProcess()->Wow64Process != 0) {
        KiInvalidateForwardProgressTbBuffer(TargetProcessors);
    }
#endif

    KeFlushCurrentTb();

    //
    // Wait until all target processors have finished.
    //

#if !defined(NT_UP)

    if (TargetProcessors != 0) {
        KiIpiStallOnPacketTargets(TargetProcessors);
    }

#endif

    //
    // Wait until all target processors have finished.
    //

#if defined(NT_UP)

    KeLowerIrql(OldIrql);

#else

    if (TargetProcessors != 0) {
        KiIpiStallOnPacketTargets(TargetProcessors);
    }

    KeLowerIrql(OldIrql);

#endif

    return;
}
Ejemplo n.º 3
0
ULONG_PTR
KiIpiGenericCall (
    IN PKIPI_BROADCAST_WORKER BroadcastFunction,
    IN ULONG_PTR Context
    )

/*++

Routine Description:

    This function executes the specified function on every processor in
    the host configuration in a synchronous manner, i.e., the function
    is executed on each target in series with the execution of the source
    processor.

Arguments:

    BroadcastFunction - Supplies the address of function that is executed
        on each of the target processors.

    Context - Supplies the value of the context parameter that is passed
        to each function.

Return Value:

    The value returned by the specified function on the source processor
    is returned as the function value.

--*/

{

    KIRQL OldIrql;
    ULONG_PTR Status;
    KAFFINITY TargetProcessors;

    //
    // Raise IRQL to the higher of the current level and synchronization
    // level to avoid a possible context switch.
    //

    KeRaiseIrql((KIRQL)(max(KiSynchIrql, KeGetCurrentIrql())), &OldIrql);

    //
    // Initialize the broadcast packet, compute the set of target processors,
    // and sent the packet to the target processors for execution.
    //

#if !defined(NT_UP)

    TargetProcessors = KeActiveProcessors & ~KeGetCurrentPrcb()->SetMember;
    if (TargetProcessors != 0) {
        KiIpiSendPacket(TargetProcessors,
                        KiIpiGenericCallTarget,
                        (PVOID)BroadcastFunction,
                        (PVOID)Context,
                        NULL);
    }

#endif

    //
    // Execute function of source processor and capture return status.
    //

    Status = BroadcastFunction(Context);

    //
    // Wait until all of the target processors have finished capturing the
    // function parameters.
    //

#if !defined(NT_UP)

    if (TargetProcessors != 0) {
        KiIpiStallOnPacketTargets(TargetProcessors);
    }

#endif

    //
    // Lower IRQL to its previous level and return the function execution
    // status.
    //

    KeLowerIrql(OldIrql);
    return Status;
}
Ejemplo n.º 4
0
BOOLEAN
Ke386IoSetAccessProcess (
    PKPROCESS Process,
    ULONG MapNumber
    )
/*++

Routine Description:

    Set the i/o access map which controls user mode i/o access
    for a particular process.

Arguments:

    Process - Pointer to kernel process object describing the
    process which for which a map is to be set.

    MapNumber - Number of the map to set.  Value of map is
    defined by Ke386IoSetAccessProcess.  Setting MapNumber
    to IO_ACCESS_MAP_NONE will disallow any user mode i/o
    access from the process.

Return Value:

    TRUE if success, FALSE if failure (illegal MapNumber)

--*/

{

    USHORT MapOffset;
    KIRQL OldIrql;
    PKPRCB Prcb;
    KAFFINITY TargetProcessors;

    //
    // Reject illegal requests
    //

    if (MapNumber > IOPM_COUNT) {
        return FALSE;
    }

    MapOffset = KiComputeIopmOffset(MapNumber);

    //
    // Acquire the context swap lock so a context switch will not occur.
    //

    KiLockContextSwap(&OldIrql);

    //
    // Store new offset in process object,  compute current set of
    // active processors for process, if this cpu is one, set IOPM.
    //

    Process->IopmOffset = MapOffset;

    TargetProcessors = Process->ActiveProcessors;
    Prcb = KeGetCurrentPrcb();
    if (TargetProcessors & Prcb->SetMember) {
        KiPcr()->TSS->IoMapBase = MapOffset;
    }

    //
    // Compute set of active processors other than this one, if non-empty
    // IPI them to load their IOPMs, wait for them.
    //

#if !defined(NT_UP)

    TargetProcessors = TargetProcessors & ~Prcb->SetMember;
    if (TargetProcessors != 0) {
        KiIpiSendPacket(TargetProcessors,
                        KiLoadIopmOffset,
                        NULL,
                        NULL,
                        NULL);

        KiIpiStallOnPacketTargets(TargetProcessors);
    }

#endif

    //
    // Restore IRQL and unlock the context swap lock.
    //

    KiUnlockContextSwap(OldIrql);
    return TRUE;
}
Ejemplo n.º 5
0
VOID 
KeDetachSessionSpace(
    VOID
    )
/*++

 Routine Description:
    
    This routine removes the session space and synchronize the all threads on 
    the other processors.

 Arguments:
 
    DeleteSessionMapInfo - if TRUE, the session map info will be deleted.
        if FALSE, the session map info will not be deleted.

 Return Value:
  
    None.

 Environment:
 
    Kernel mode.

--*/
{
    KIRQL OldIrql;
    PKTHREAD Thread;
    PKPROCESS Process;
#if !defined(NT_UP)
    KAFFINITY TargetProcessors;
#endif

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

    KiLockDispatcherDatabase(&OldIrql);

    Thread = KeGetCurrentThread();
    Process = Thread->ApcState.Process;

    //
    // Lock the region Id resource.
    //
    
    KiAcquireSpinLock(&KiMasterRidLock);

    Process->SessionMapInfo = &Process->SessionRegion;
    
    KiSetRegionRegister((PVOID)MM_SESSION_SPACE_DEFAULT, 
                        KiMakeValidRegionRegister(Process->SessionMapInfo->RegionId, PAGE_SHIFT));

    //
    // Unlock the region Id resource.
    //

    KiReleaseSpinLock(&KiMasterRidLock);

#if !defined(NT_UP)

    //
    // broadcast Region Id sync
    //

    TargetProcessors = KeActiveProcessors;
    TargetProcessors &= PCR->NotMember;

    if (TargetProcessors != 0) {
        KiIpiSendPacket(TargetProcessors,
                        KiSyncSessionTarget,
                        Process,
                        NULL,
                        NULL);
    }

#endif

    //
    // Unlock the dispatcher database
    //

    KiUnlockDispatcherDatabase(OldIrql);
}    
Ejemplo n.º 6
0
BOOLEAN
KiSyncNewRegionId(
    IN PREGION_MAP_INFO ProcessRegion,
    IN PREGION_MAP_INFO SessionRegion
    )
/*++

 Routine Description:

    Generate a new region id and synchronze the region Ids on all the processors
    if necessary. If the region ids wrap then flush all processor TLB's.

 Arguments:

    ProcessRegion - Supplies a pointer to REGION_MAP_INFO for the user space.
    SessionRegion - Supplies a pointer to REGION_MAP_INFO for the session space.

 Return Value:

    FALSE -- when region id has not been recycled.

    TRUE -- when region id has been recycled.

 Notes:

    This routine called by KiSwapProcess, KeAttachSessionSpace and 
    KeCreateSessionSpace.

 Environment:

    Kernel mode.
    KiLockDispaterLock or LockQueuedDispatcherLock is held

--*/

{
    BOOLEAN RidRecycled = FALSE;
    KAFFINITY TargetProcessors;
    ULONG i;

    //
    // Invalidate the ForwardProgressTb buffer
    //

    for (i = 0; i < MAXIMUM_FWP_BUFFER_ENTRY; i += 1) {
        
        PCR->ForwardProgressBuffer[(i*2)+1] = 0;

    }
    
    KiAcquireSpinLock(&KiMasterRidLock);

    if ((ProcessRegion->SequenceNumber == KiMasterSequence) && 
        (SessionRegion->SequenceNumber == KiMasterSequence)) {
        
        goto not_recycled;

    }

    if (ProcessRegion->SequenceNumber != KiMasterSequence) {

        if (KiMasterRid + 1 > KiMaximumRid) {

            RidRecycled = TRUE;

        } else {

            KiMasterRid += 1;
            ProcessRegion->RegionId = KiMasterRid;
            ProcessRegion->SequenceNumber = KiMasterSequence;
        }
                
    }

    if ((RidRecycled == FALSE) && 
        (SessionRegion->SequenceNumber != KiMasterSequence)) {
        
        if (KiMasterRid + 1 > KiMaximumRid) {

            RidRecycled = TRUE;

        } else {

            KiMasterRid += 1;
            SessionRegion->RegionId = KiMasterRid;
            SessionRegion->SequenceNumber = KiMasterSequence;
        }
    }

    if (RidRecycled == FALSE) {
    
        goto not_recycled;

    }

    //
    //  Region Id must be recycled
    //

    KiMasterRid = START_PROCESS_RID;

    //
    // Since KiMasterSequence is 64-bit wide, it will not be recycled in your life time.
    //

    if (KiMasterSequence + 1 > MAXIMUM_SEQUENCE) {

        KiMasterSequence = START_SEQUENCE;

    } else {

        KiMasterSequence += 1;
    }
        
    //
    // update new process's ProcessRid and ProcessSequence
    //

    ProcessRegion->RegionId = KiMasterRid;
    ProcessRegion->SequenceNumber = KiMasterSequence;

    KiSetRegionRegister(MM_LOWEST_USER_ADDRESS,
                        KiMakeValidRegionRegister(ProcessRegion->RegionId, PAGE_SHIFT));

    KiMasterRid += 1;

    SessionRegion->RegionId = KiMasterRid;
    SessionRegion->SequenceNumber = KiMasterSequence;

    KiSetRegionRegister((PVOID)MM_SESSION_SPACE_DEFAULT,
                        KiMakeValidRegionRegister(SessionRegion->RegionId, PAGE_SHIFT));

    //
    // release mutex for master region id lock
    //

    KiReleaseSpinLock(&KiMasterRidLock);

#if !defined(NT_UP)

    //
    // broadcast Region Id sync
    //

    TargetProcessors = KeActiveProcessors;
    TargetProcessors &= PCR->NotMember;

    if (TargetProcessors != 0) {
        KiIpiSendPacket(TargetProcessors,
                        KiSyncNewRegionIdTarget,
                        (PVOID)TRUE,
                        NULL,
                        NULL);
    }

#endif

    KeFlushCurrentTb();


#if !defined(NT_UP)

    //
    // Wait until all target processors have finished.
    //

    if (TargetProcessors != 0) {
        KiIpiStallOnPacketTargets(TargetProcessors);
    }

#endif

    return TRUE;


not_recycled:

    KiSetRegionRegister(MM_LOWEST_USER_ADDRESS,
                        KiMakeValidRegionRegister(ProcessRegion->RegionId, PAGE_SHIFT));

    KiSetRegionRegister((PVOID)MM_SESSION_SPACE_DEFAULT,
                            KiMakeValidRegionRegister(SessionRegion->RegionId, PAGE_SHIFT));

    //
    // release mutex for master region id lock
    //

    KiReleaseSpinLock(&KiMasterRidLock);
        
    return FALSE;

}
Ejemplo n.º 7
0
VOID
KiCalibratePerformanceCounter(
    VOID
    )

/*++

Routine Description:

    This function resets and synchronizes the performance counter on all
    processors in the configuration.

Arguments:

    None.

Return Value:

    None.

--*/

{

    KIRQL OldIrql;
    LONG Count = 1;
    KAFFINITY TargetProcessors;

    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // Raise IRQl to DISPATCH_LEVEL to avoid a possible context switch.
    //

#if !defined(NT_UP)

    KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);

    //
    // Initialize the reset performance counter packet, compute the target
    // set of processors, and send the packet to the target processors, if
    // any, for execution.
    //

    TargetProcessors = KeActiveProcessors & PCR->NotMember;
    if (TargetProcessors != 0) {
        Count = (LONG)KeNumberProcessors;
        KiIpiSendPacket(TargetProcessors,
                        KiCalibratePerformanceCounterTarget,
                        &Count,
                        NULL,
                        NULL);
    }

#endif

    //
    // Reset the performance counter on current processor.
    //

    HalCalibratePerformanceCounter((volatile PLONG)&Count);

    //
    // Wait until all target processors have reset and synchronized their
    // performance counters.
    //

#if !defined(NT_UP)

    if (TargetProcessors != 0) {
        KiIpiStallOnPacketTargets();
    }

    //
    // Lower IRQL to previous level.
    //

    KeLowerIrql(OldIrql);

#endif

    return;
}
Ejemplo n.º 8
0
VOID
KeFlushEntireTb (
    IN BOOLEAN Invalid,
    IN BOOLEAN AllProcessors
    )

/*++

Routine Description:

    This function flushes the entire translation buffer (TB) on all processors
    that are currently running threads which are child of the current process
    or flushes the entire translation buffer on all processors in the host
    configuration.

Arguments:

    Invalid - Supplies a boolean value that specifies the reason for flushing
        the translation buffer.

    AllProcessors - Supplies a boolean value that determines which translation
        buffers are to be flushed.

Return Value:

    None.

--*/

{

    KIRQL OldIrql;
    PKPRCB Prcb;
    PKPROCESS Process;
    KAFFINITY TargetProcessors;

    //
    // Compute the target set of processors, disable context switching,
    // and send the flush entire parameters to the target processors,
    // if any, for execution.
    //

#if defined(NT_UP)

    OldIrql = KeRaiseIrqlToSynchLevel();

#else

    if (AllProcessors != FALSE) {
        OldIrql = KeRaiseIrqlToSynchLevel();
        Prcb = KeGetCurrentPrcb();
        TargetProcessors = KeActiveProcessors;

    } else {
        KiLockContextSwap(&OldIrql);
        Prcb = KeGetCurrentPrcb();
        Process = Prcb->CurrentThread->ApcState.Process;
        TargetProcessors = Process->ActiveProcessors;
    }

    TargetProcessors &= ~Prcb->SetMember;
    if (TargetProcessors != 0) {
        KiIpiSendPacket(TargetProcessors,
                        KiFlushTargetEntireTb,
                        NULL,
                        NULL,
                        NULL);

        IPI_INSTRUMENT_COUNT (Prcb->Number, FlushEntireTb);
    }

#endif

    //
    // Flush TB on current processor.
    //

    KeFlushCurrentTb();

    //
    // Wait until all target processors have finished and complete packet.
    //

#if defined(NT_UP)

    KeLowerIrql(OldIrql);

#else

    if (TargetProcessors != 0) {
        KiIpiStallOnPacketTargets(TargetProcessors);
    }

    if (AllProcessors != FALSE) {
        KeLowerIrql(OldIrql);

    } else {
        KiUnlockContextSwap(OldIrql);
    }

#endif

    return;
}
Ejemplo n.º 9
0
ULONG_PTR
KeIpiGenericCall (
    IN PKIPI_BROADCAST_WORKER BroadcastFunction,
    IN ULONG_PTR Context
    )

/*++

Routine Description:

    This function executes the specified function on every processor in
    the host configuration in a synchronous manner, i.e., the function
    is executed on each target in series with the execution of the source
    processor.

Arguments:

    BroadcastFunction - Supplies the address of function that is executed
        on each of the target processors.

    Context - Supplies the value of the context parameter that is passed
        to each function.

Return Value:

    The value returned by the specified function on the source processor
    is returned as the function value.

--*/

{

    volatile LONG Count;
    KIRQL OldIrql;
    ULONG_PTR Status;

#if !defined(NT_UP)

    KAFFINITY TargetProcessors;

#endif

    //
    // Raise IRQL to synchronization level and acquire the reverse stall spin
    // lock to synchronize with other reverse stall functions.
    //

    OldIrql = KeGetCurrentIrql();
    if (OldIrql < SYNCH_LEVEL) {
        KfRaiseIrql(SYNCH_LEVEL);
    }

#if !defined(NT_UP)

    Count = KeNumberProcessors;
    TargetProcessors = KeActiveProcessors & ~KeGetCurrentPrcb()->SetMember;

#endif

    KeAcquireSpinLockAtDpcLevel(&KiReverseStallIpiLock);

    //
    // Initialize the broadcast packet, compute the set of target processors,
    // and sent the packet to the target processors for execution.
    //

#if !defined(NT_UP)

    if (TargetProcessors != 0) {
        KiIpiSendPacket(TargetProcessors,
                        KiIpiGenericCallTarget,
                        (PVOID)(ULONG_PTR)BroadcastFunction,
                        (PVOID)Context,
                        (PVOID)&Count);
    }

    //
    // Wait until all processors have entered the target routine and are
    // waiting.
    //

    while (Count != 1) {
        KeYieldProcessor();
    }

#endif

    //
    // Raise IRQL to IPI_LEVEL, signal all other processors to proceed, and
    // call the specified function on the source processor.
    //

    KfRaiseIrql(IPI_LEVEL);
    Count = 0;
    Status = BroadcastFunction(Context);

    //
    // Wait until all of the target processors have finished capturing the
    // function parameters.
    //

#if !defined(NT_UP)

    if (TargetProcessors != 0) {
        KiIpiStallOnPacketTargets(TargetProcessors);
    }

#endif

    //
    // Release reverse stall spin lock, lower IRQL to its previous level,
    // and return the function execution status.
    //

    KeReleaseSpinLockFromDpcLevel(&KiReverseStallIpiLock);
    KeLowerIrql(OldIrql);
    return Status;
}