[NTOS]: KiDispatchInterrupt (the DPC handler) in C, instead of ASM.

svn path=/trunk/; revision=49521
This commit is contained in:
Sir Richard 2010-11-08 02:37:17 +00:00
parent 77d20c89bf
commit b4593924da
2 changed files with 76 additions and 111 deletions

View file

@ -112,121 +112,18 @@
ret
.endfunc
/* DPC INTERRUPT HANDLER ******************************************************/
.globl @KiRetireDpcListInDpcStack@8
.func @KiRetireDpcListInDpcStack@8, @KiRetireDpcListInDpcStack@8
@KiRetireDpcListInDpcStack@8:
.globl _KiDispatchInterrupt@0
.func KiDispatchInterrupt@0
_KiDispatchInterrupt@0:
/* Preserve EBX */
push ebx
/* Get the PCR and disable interrupts */
mov ebx, PCR[KPCR_SELF]
cli
/* Check if we have to deliver DPCs, timers, or deferred threads */
mov eax, [ebx+KPCR_PRCB_DPC_QUEUE_DEPTH]
or eax, [ebx+KPCR_PRCB_TIMER_REQUEST]
or eax, [ebx+KPCR_PRCB_DEFERRED_READY_LIST_HEAD]
jz CheckQuantum
/* Save stack pointer and exception list, then clear it */
push ebp
push dword ptr [ebx+KPCR_EXCEPTION_LIST]
mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
/* Save the stack and switch to the DPC Stack */
mov edx, esp
mov esp, [ebx+KPCR_PRCB_DPC_STACK]
push edx
/* Deliver DPCs */
mov ecx, [ebx+KPCR_PRCB]
/* Switch stacks and retire DPCs */
mov eax, esp
mov esp, edx
push eax
call @KiRetireDpcList@4
/* Restore stack and exception list */
/* Return on original stack */
pop esp
pop dword ptr [ebx+KPCR_EXCEPTION_LIST]
pop ebp
CheckQuantum:
/* Re-enable interrupts */
sti
/* Check if we have quantum end */
cmp byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
jnz QuantumEnd
/* Check if we have a thread to swap to */
cmp byte ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
je Return
/* Make space on the stack to save registers */
sub esp, 3 * 4
mov [esp+8], esi
mov [esp+4], edi
mov [esp+0], ebp
/* Get the current thread */
mov edi, [ebx+KPCR_CURRENT_THREAD]
#ifdef CONFIG_SMP
/* Raise to synch level */
call _KeRaiseIrqlToSynchLevel@0
/* Set context swap busy */
mov byte ptr [edi+KTHREAD_SWAP_BUSY], 1
/* Acquire the PRCB Lock */
lock bts dword ptr [ebx+KPCR_PRCB_PRCB_LOCK], 0
jnb GetNext
lea ecx, [ebx+KPCR_PRCB_PRCB_LOCK]
call @KefAcquireSpinLockAtDpcLevel@4
#endif
GetNext:
/* Get the next thread and clear it */
mov esi, [ebx+KPCR_PRCB_NEXT_THREAD]
and dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
/* Set us as the current running thread */
mov [ebx+KPCR_CURRENT_THREAD], esi
mov byte ptr [esi+KTHREAD_STATE_], Running
mov byte ptr [edi+KTHREAD_WAIT_REASON], WrDispatchInt
/* Put thread in ECX and get the PRCB in EDX */
mov ecx, edi
lea edx, [ebx+KPCR_PRCB_DATA]
call @KiQueueReadyThread@8
/* Set APC_LEVEL and do the swap */
mov cl, APC_LEVEL
call @KiSwapContextInternal@0
#ifdef CONFIG_SMP
/* Lower IRQL back to dispatch */
mov cl, DISPATCH_LEVEL
call @KfLowerIrql@4
#endif
/* Restore registers */
mov ebp, [esp+0]
mov edi, [esp+4]
mov esi, [esp+8]
add esp, 3*4
Return:
/* All done */
pop ebx
ret
QuantumEnd:
/* Disable quantum end and process it */
mov byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
call _KiQuantumEnd@0
pop ebx
ret
.endfunc

View file

@ -49,6 +49,13 @@ KiSwitchThreads(
IN PKTHREAD NewThread
);
VOID
FASTCALL
KiRetireDpcListInDpcStack(
IN PKPRCB Prcb,
IN PVOID DpcStack
);
/* FUNCTIONS *****************************************************************/
VOID
@ -447,4 +454,65 @@ KiSwapContextEntry(IN PKSWITCHFRAME SwitchFrame,
KiSwitchThreads(OldThread, NewThread);
}
VOID
NTAPI
KiDispatchInterrupt(VOID)
{
PKIPCR Pcr = (PKIPCR)KeGetPcr();
PKPRCB Prcb = &Pcr->PrcbData;
PVOID OldHandler;
PKTHREAD NewThread, OldThread;
/* Disable interrupts */
_disable();
/* Check for pending timers, pending DPCs, or pending ready threads */
if ((Prcb->DpcData[0].DpcQueueDepth) ||
(Prcb->TimerRequest) ||
(Prcb->DeferredReadyListHead.Next))
{
/* Switch to safe execution context */
OldHandler = Pcr->NtTib.ExceptionList;
Pcr->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
/* Retire DPCs while under the DPC stack */
KiRetireDpcListInDpcStack(Prcb, Prcb->DpcStack);
/* Restore context */
Pcr->NtTib.ExceptionList = OldHandler;
}
/* Re-enable interrupts */
_enable();
/* Check for quantum end */
if (Prcb->QuantumEnd)
{
/* Handle quantum end */
Prcb->QuantumEnd = FALSE;
KiQuantumEnd();
}
else if (Prcb->NextThread)
{
/* Capture current thread data */
OldThread = Prcb->CurrentThread;
NewThread = Prcb->NextThread;
/* Set new thread data */
Prcb->NextThread = NULL;
Prcb->CurrentThread = NewThread;
/* The thread is now running */
NewThread->State = Running;
OldThread->WaitReason = WrDispatchInt;
/* Make the old thread ready */
KxQueueReadyThread(OldThread, Prcb);
/* Swap to the new thread. FIXME: APC Bypass */
KiSwapContext(OldThread, NewThread);
}
}
/* EOF */