示例#1
0
//
// Injection APC routines
//
VOID KernelApcPrepareCallback(
    PKAPC Apc,
    PKNORMAL_ROUTINE* NormalRoutine,
    PVOID* NormalContext,
    PVOID* SystemArgument1,
    PVOID* SystemArgument2
    )
{
    UNREFERENCED_PARAMETER( NormalRoutine );
    UNREFERENCED_PARAMETER( NormalContext );
    UNREFERENCED_PARAMETER( SystemArgument1 );
    UNREFERENCED_PARAMETER( SystemArgument2 );

    //DPRINT( "BlackBone: %s: Called\n", __FUNCTION__ );

    // Alert current thread
    KeTestAlertThread( UserMode );
    ExFreePoolWithTag( Apc, BB_POOL_TAG );
}
示例#2
0
// runs in kernel mode as KAPC.NormalRoutine
VOID
KernelApcNormalRoutine (
    PVOID NormalContext,
    PVOID SystemArgument1,
    PVOID SystemArgument2 )
{
    BOOLEAN Alerted = FALSE;

    UNREFERENCED_PARAMETER(NormalContext);
    UNREFERENCED_PARAMETER(SystemArgument1);
    UNREFERENCED_PARAMETER(SystemArgument2);

    // KeTestAlertThread() sets the following flag
    // KTHREAD.ApcState.UserApcPending for the 
    // current thread
    Alerted = KeTestAlertThread ( UserMode );

    DPF(("%s!%s Alerted=%s\n", __MODULE__, __FUNCTION__, 
        Alerted ? "TRUE" : "FALSE" ));
}
示例#3
0
文件: psspnd.c 项目: conioh/os-design
NTSTATUS
NtTestAlert(
    VOID
    )

/*++

Routine Description:

    This function tests the alert flag inside the current thread. If
    an alert is pending for the previous mode, then the alerted status
    is returned, pending APC's may also be delivered at this time.

Arguments:

    None

Return Value:

    STATUS_ALERTED - An alert was pending for the current thread at the
        time this function was called.

    STATUS_SUCCESS - No alert was pending for this thread.

--*/

{

    PAGED_CODE();

    if ( KeTestAlertThread(KeGetPreviousMode()) ) {
        return STATUS_ALERTED;
    } else {
        return STATUS_SUCCESS;
    }
}
示例#4
0
文件: apc.c 项目: GYGit/reactos
/*++
 * @name KiDeliverApc
 * @implemented @NT4
 *
 *     The KiDeliverApc routine is called from IRQL switching code if the
 *     thread is returning from an IRQL >= APC_LEVEL and Kernel-Mode APCs are
 *     pending.
 *
 * @param DeliveryMode
 *        Specifies the current processor mode.
 *
 * @param ExceptionFrame
 *        Pointer to the Exception Frame on non-i386 builds.
 *
 * @param TrapFrame
 *        Pointer to the Trap Frame.
 *
 * @return None.
 *
 * @remarks First, Special APCs are delivered, followed by Kernel-Mode APCs and
 *          User-Mode APCs. Note that the TrapFrame is only valid if the
 *          delivery mode is User-Mode.
 *          Upon entry, this routine executes at APC_LEVEL.
 *
 *--*/
VOID
NTAPI
KiDeliverApc(IN KPROCESSOR_MODE DeliveryMode,
             IN PKEXCEPTION_FRAME ExceptionFrame,
             IN PKTRAP_FRAME TrapFrame)
{
    PKTHREAD Thread = KeGetCurrentThread();
    PKPROCESS Process = Thread->ApcState.Process;
    PKTRAP_FRAME OldTrapFrame;
    PLIST_ENTRY ApcListEntry;
    PKAPC Apc;
    KLOCK_QUEUE_HANDLE ApcLock;
    PKKERNEL_ROUTINE KernelRoutine;
    PVOID NormalContext;
    PKNORMAL_ROUTINE NormalRoutine;
    PVOID SystemArgument1;
    PVOID SystemArgument2;
    ASSERT_IRQL_EQUAL(APC_LEVEL);

    /* Save the old trap frame and set current one */
    OldTrapFrame = Thread->TrapFrame;
    Thread->TrapFrame = TrapFrame;

    /* Clear Kernel APC Pending */
    Thread->ApcState.KernelApcPending = FALSE;

    /* Check if Special APCs are disabled */
    if (Thread->SpecialApcDisable) goto Quickie;

    /* Do the Kernel APCs first */
    while (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))
    {
        /* Lock the APC Queue */
        KiAcquireApcLockAtApcLevel(Thread, &ApcLock);

        /* Check if the list became empty now */
        if (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))
        {
            /* It is, release the lock and break out */
            KiReleaseApcLock(&ApcLock);
            break;
        }

        /* Kernel APC is not pending anymore */
        Thread->ApcState.KernelApcPending = FALSE;

        /* Get the next Entry */
        ApcListEntry = Thread->ApcState.ApcListHead[KernelMode].Flink;
        Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);

        /* Save Parameters so that it's safe to free the Object in the Kernel Routine*/
        NormalRoutine = Apc->NormalRoutine;
        KernelRoutine = Apc->KernelRoutine;
        NormalContext = Apc->NormalContext;
        SystemArgument1 = Apc->SystemArgument1;
        SystemArgument2 = Apc->SystemArgument2;

        /* Special APC */
        if (!NormalRoutine)
        {
            /* Remove the APC from the list */
            RemoveEntryList(ApcListEntry);
            Apc->Inserted = FALSE;

            /* Release the APC lock */
            KiReleaseApcLock(&ApcLock);

            /* Call the Special APC */
            KernelRoutine(Apc,
                          &NormalRoutine,
                          &NormalContext,
                          &SystemArgument1,
                          &SystemArgument2);

            /* Make sure it returned correctly */
            if (KeGetCurrentIrql() != ApcLock.OldIrql)
            {
                KeBugCheckEx(IRQL_UNEXPECTED_VALUE,
                             (KeGetCurrentIrql() << 16) |
                             (ApcLock.OldIrql << 8),
                             (ULONG_PTR)KernelRoutine,
                             (ULONG_PTR)Apc,
                             (ULONG_PTR)NormalRoutine);
            }
        }
        else
        {
            /* Normal Kernel APC, make sure it's safe to deliver */
            if ((Thread->ApcState.KernelApcInProgress) ||
                (Thread->KernelApcDisable))
            {
                /* Release lock and return */
                KiReleaseApcLock(&ApcLock);
                goto Quickie;
            }

            /* Dequeue the APC */
            RemoveEntryList(ApcListEntry);
            Apc->Inserted = FALSE;

            /* Go back to APC_LEVEL */
            KiReleaseApcLock(&ApcLock);

            /* Call the Kernel APC */
            KernelRoutine(Apc,
                          &NormalRoutine,
                          &NormalContext,
                          &SystemArgument1,
                          &SystemArgument2);

            /* Make sure it returned correctly */
            if (KeGetCurrentIrql() != ApcLock.OldIrql)
            {
                KeBugCheckEx(IRQL_UNEXPECTED_VALUE,
                             (KeGetCurrentIrql() << 16) |
                             (ApcLock.OldIrql << 8),
                             (ULONG_PTR)KernelRoutine,
                             (ULONG_PTR)Apc,
                             (ULONG_PTR)NormalRoutine);
            }

            /* Check if there still is a Normal Routine */
            if (NormalRoutine)
            {
                /* At Passive Level, an APC can be prempted by a Special APC */
                Thread->ApcState.KernelApcInProgress = TRUE;
                KeLowerIrql(PASSIVE_LEVEL);

                /* Call and Raise IRQL back to APC_LEVEL */
                NormalRoutine(NormalContext, SystemArgument1, SystemArgument2);
                KeRaiseIrql(APC_LEVEL, &ApcLock.OldIrql);
            }

            /* Set Kernel APC in progress to false and loop again */
            Thread->ApcState.KernelApcInProgress = FALSE;
        }
    }

    /* Now we do the User APCs */
    if ((DeliveryMode == UserMode) &&
        !(IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])) &&
         (Thread->ApcState.UserApcPending))
    {
        /* Lock the APC Queue */
        KiAcquireApcLockAtApcLevel(Thread, &ApcLock);

        /* It's not pending anymore */
        Thread->ApcState.UserApcPending = FALSE;

        /* Check if the list became empty now */
        if (IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))
        {
            /* It is, release the lock and break out */
            KiReleaseApcLock(&ApcLock);
            goto Quickie;
        }

        /* Get the actual APC object */
        ApcListEntry = Thread->ApcState.ApcListHead[UserMode].Flink;
        Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);

        /* Save Parameters so that it's safe to free the Object in the Kernel Routine*/
        NormalRoutine = Apc->NormalRoutine;
        KernelRoutine = Apc->KernelRoutine;
        NormalContext = Apc->NormalContext;
        SystemArgument1 = Apc->SystemArgument1;
        SystemArgument2 = Apc->SystemArgument2;

        /* Remove the APC from Queue, and release the lock */
        RemoveEntryList(ApcListEntry);
        Apc->Inserted = FALSE;
        KiReleaseApcLock(&ApcLock);

        /* Call the kernel routine */
        KernelRoutine(Apc,
                      &NormalRoutine,
                      &NormalContext,
                      &SystemArgument1,
                      &SystemArgument2);

        /* Check if there's no normal routine */
        if (!NormalRoutine)
        {
            /* Check if more User APCs are Pending */
            KeTestAlertThread(UserMode);
        }
        else
        {
            /* Set up the Trap Frame and prepare for Execution in NTDLL.DLL */
            KiInitializeUserApc(ExceptionFrame,
                                TrapFrame,
                                NormalRoutine,
                                NormalContext,
                                SystemArgument1,
                                SystemArgument2);
        }
    }

Quickie:
    /* Make sure we're still in the same process */
    if (Process != Thread->ApcState.Process)
    {
        /* Erm, we got attached or something! BAD! */
        KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
                     (ULONG_PTR)Process,
                     (ULONG_PTR)Thread->ApcState.Process,
                     Thread->ApcStateIndex,
                     KeGetCurrentPrcb()->DpcRoutineActive);
    }

    /* Restore the trap frame */
    Thread->TrapFrame = OldTrapFrame;
}
示例#5
0
NTSTATUS
KiContinueEx (
    IN PCONTEXT ContextRecord,
    IN BOOLEAN TestAlert,
    IN PKEXCEPTION_FRAME ExceptionFrame,
    IN PKTRAP_FRAME TrapFrame
    )

/*++

Routine Description:

    This function is called to copy the specified context frame to the
    specified exception and trap frames for the continue system service.

    N.B. If the previous mode is user mode, alerts are being tested, a user
         APC is available to execute, and the specified context record was
         previously placed on the stack by the user APC initialization routine,
         then bypass context record copy to the kernel frames and back again.

Arguments:

    ContextRecord - Supplies a pointer to a context record.

    TestAlert - Supplies a boolean value that determines whether a test alert
       is to be performed.

    ExceptionFrame - Supplies a pointer to an exception frame.

    TrapFrame - Supplies a pointer to a trap frame.

Return Value:

    STATUS_ACCESS_VIOLATION is returned if the context record is not readable
        from user mode.

    STATUS_DATATYPE_MISALIGNMENT is returned if the context record is not
        properly aligned.

    STATUS_SUCCESS + 1 is returned if the context frame is copied successfully
        to the specified exception and trap frames.

    STATUS_SUCCESS is returned if the context record copy was bypassed and
        another user APC is ready to be delivered.

--*/

{

    KIRQL OldIrql;
    NTSTATUS Status;
    PKTHREAD Thread;
    ULONG64 UserStack;

    //
    // Synchronize with other context operations.
    //
    // If the current IRQL is less than APC_LEVEL, then raise IRQL to APC level.
    // 

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

    //
    // If the previous mode was not kernel mode, then attempt to bypass
    // the copy of the context record. Otherwise, copy context to kernel
    // frames directly.
    // 
      
    Status = STATUS_SUCCESS + 1;
    Thread = KeGetCurrentThread();
    if (Thread->PreviousMode != KernelMode) {
        try {
            if (TestAlert != FALSE) {
                ProbeForWriteSmallStructure(ContextRecord,
                                            sizeof(CONTEXT),
                                            CONTEXT_ALIGN);

                KeTestAlertThread(UserMode);
                UserStack = (ContextRecord->Rsp  - sizeof(MACHINE_FRAME)) & ~STACK_ROUND;
                if (((UserStack - sizeof(CONTEXT)) == (ULONG64)ContextRecord) &&
                    (Thread->ApcState.UserApcPending != FALSE)) {

                    //
                    // Save the context record and exception frame addresses
                    // in the trap frame and deliver the user APC bypassing
                    // the context copy.
                    //

                    TrapFrame->ContextRecord = (ULONG64)ContextRecord;
                    TrapFrame->ExceptionFrame = (ULONG64)ExceptionFrame;
                    KiDeliverApc(UserMode, NULL, TrapFrame);
                    Status = STATUS_SUCCESS;
                    leave;
                }

            } else {
                ProbeForReadSmallStructure(ContextRecord,
                                           sizeof(CONTEXT),
                                           CONTEXT_ALIGN);
            }

            KiContinuePreviousModeUser(ContextRecord,
                                       ExceptionFrame,
                                       TrapFrame);

        } except(EXCEPTION_EXECUTE_HANDLER) {
            Status = GetExceptionCode();
        }

    } else {