Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Home NTDEV

Before Posting...

Please check out the Community Guidelines in the Announcements and Administration Category.

More Info on Driver Writing and Debugging


The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.


Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/


Need Verification on My Processor Stalling Code

daniel02daniel02 Member Posts: 16

I've written some code that aims to stall all processors except the currently executing one using DPC routines. I'd appreciate it if someone could review and let me know if this is correct or if there are potential improvements/issues. Here's the code:

ULONG GetNumberOfProcessors()
{
    SYSTEM_BASIC_INFORMATION sysInfo;

    ZwQuerySystemInformation(SystemBasicInformation, &sysInfo, sizeof(sysInfo), NULL);

    return sysInfo.NumberOfProcessors;
}
volatile LONG stallCount;

void DpcRoutine(KDPC* pDpc, PVOID pContext, PVOID pArg1, PVOID pArg2)
{
    InterlockedDecrement(&stallCount);
    while (InterlockedCompareExchange(&stallCount, 0, 0) > 0)
    {
        _mm_pause(); // Busy-wait
    }
}

void StallOtherProcessors()
{
    CCHAR currentProcessor = (CCHAR)KeGetCurrentProcessorNumber();
    CCHAR cpuCount = (CCHAR)GetNumberOfProcessors();
    KDPC dpcTraps[MAXIMUM_PROCESSORS];

    // Initialize DPCs for all processors
    for (CCHAR i = 0; i < cpuCount; i++)
    {
        KeInitializeDpc(&dpcTraps[i], DpcRoutine, NULL);
        KeSetImportanceDpc(&dpcTraps[i], HighImportance);
        KeSetTargetProcessorDpc(&dpcTraps[i], i);
    }

    // Stall all processors except the current one
    stallCount = cpuCount - 1; // Exclude the current processor
    for (CCHAR i = 0; i < cpuCount; i++)
    {
        if (i != currentProcessor)
        {
            KeInsertQueueDpc(&dpcTraps[i], NULL, NULL);
        }
    }

    // Wait for all DPCs to execute, stalling the other processors
    while (InterlockedCompareExchange(&stallCount, 0, 0) > 0)
    {
        _mm_pause(); // Busy-wait
    }
}
void ResumeOtherProcessors()
{
    InterlockedExchange(&stallCount, 0); // Allow the other processors to exit the DPC routine
}

Comments

  • Tim_RobertsTim_Roberts Member - All Emails Posts: 14,832

    This is not immune to interrupts.

    Tim Roberts, [email protected]
    Software Wizard Emeritus

  • daniel02daniel02 Member Posts: 16

    @Tim_Roberts said:
    This is not immune to interrupts.

    yes that's why i do

    void myfunction(){
    KIRQL QL;
    KeRaiseIrql(DISPATCH_LEVEL,&QL);
    StallOtherProcessors();
    func();
    ResumeOtherProcessors();
    KeLowerIrql(QL);
    }
    
  • Tim_RobertsTim_Roberts Member - All Emails Posts: 14,832

    That doesn't help. DISPATCH_LEVEL is way below the IRQL of hardware interrupts.

    Tim Roberts, [email protected]
    Software Wizard Emeritus

  • daniel02daniel02 Member Posts: 16

    @Tim_Roberts said:
    That doesn't help. DISPATCH_LEVEL is way below the IRQL of hardware interrupts.

    i see so my only option is do it like this

    KIRQL QL;
    KeRaiseIrql(HIGH_LEVEL,&QL);
    _disable();
    StallOtherProcessors();
    func();
    ResumeOtherProcessors();
    _enable();
    KeLowerIrql(QL);
    

    change KeGetCurrentProcessorNumber(IRQL >= DISPATCH_LEVEL.) and ZwQuerySystemInformation(PASSIVE_LEVEL)

  • Peter_Viscarola_(OSR)Peter_Viscarola_(OSR) Administrator Posts: 9,160

    Hmmm... I don't see thepoint of both raising to IRQL HIGH_LEVEL and calling __disable()... what are you trying to accomplish by this?

    In order to have the OTHER processors not handle interrupts, the DPC routine that they execute is going to have to raise to IRQL HIGH_LEVEL.

    Also, you can replace your GetNumberOfProcessors() function with a call to KeQueryActiveProcessorCount.

    Finally, just so that SOMEbody in this thread has said it once: What you're doing looks like it's probably a bad idea. I'm not sure what your overall goal is, but the sort of "big hammer" that you're using here is rarely necessary.

    Peter

    Peter Viscarola
    OSR
    @OSRDrivers

  • Mark_RoddyMark_Roddy Member - All Emails Posts: 4,753

    You might want to look at KeIpiGenericCall as this does exactly what you are trying to do, only without the defects you are coding up :-). You still have to implement the corral in your callback routine, but that is fairly trivial.

  • Mark_RoddyMark_Roddy Member - All Emails Posts: 4,753

    I forgot to add that if you read the docs carefully, the callback guarantees that all the processor have responded to the IPI when the callback is invoked, so your corral only needs to nominate one of the callers as the active thread, generally the first one in using an interlocked expression, and then release all the waiters when it is done.

  • daniel02daniel02 Member Posts: 16
    edited July 2023

    thanks i found a code that do all that

    i was wondering how i can skip core 0 in this code ?

    _IRQL_raises_(DISPATCH_LEVEL)
    static PSTOP_PROCESSORS_DATA StopProcessors()
    {
        PSTOP_PROCESSORS_DATA Data = (PSTOP_PROCESSORS_DATA)ExAllocatePoolWithTag(NonPagedPool, sizeof(*Data), POOL_TAG);
        if (!Data) return NULL;
        RtlZeroMemory(Data, sizeof(*Data));
    
        KeRaiseIrql(DISPATCH_LEVEL, &Data->PreviousIrql);
    
        KAFFINITY ActiveProcessors = 0;
        ULONG CurrentProcessor = KeGetCurrentProcessorNumber();
        ULONG ProcessorsCount = KeQueryActiveProcessorCount(&ActiveProcessors);
        Data->NeedToBeStopped = ProcessorsCount;
    
        for (unsigned i = 0; i < ProcessorsCount; ++i) {
            if (i == CurrentProcessor) continue;
            KeInitializeDpc(&Data->Dpcs[i], (PKDEFERRED_ROUTINE)StallDpcRoutine, Data);
            KeSetTargetProcessorDpc(&Data->Dpcs[i], (CCHAR)i);
            KeSetImportanceDpc(&Data->Dpcs[i], HighImportance);
            KeInsertQueueDpc(&Data->Dpcs[i], NULL, NULL);
        }
    
        InterlockedIncrement(&Data->ProcessorsStopped);
        WaitForEquality(&Data->ProcessorsStopped, ProcessorsCount);
    
        return Data;
    }
    

    is this approch correct ?


Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. Sign in or register to get started.

Upcoming OSR Seminars
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead!
Kernel Debugging 13-17 May 2024 Live, Online
Developing Minifilters 1-5 Apr 2024 Live, Online
Internals & Software Drivers 11-15 Mar 2024 Live, Online
Writing WDF Drivers 20-24 May 2024 Live, Online