+ /* Get the trap frame */
+ mov ebx, [eax+KTHREAD_TRAP_FRAME]
+
+ /* Restore the exception list */
+ mov edx, [ebx+KTRAP_FRAME_EXCEPTION_LIST]
+ mov fs:[KPCR_EXCEPTION_LIST], edx
+
+ /* Get the result, the result length and the status */
+ mov edi, [esp+4]
+ mov esi, [esp+8]
+ mov ebp, [esp+12]
+
+ /* Store the results in the callback stack */
+ mov ebx, [ecx+CBSTACK_RESULT]
+ mov [ebx], edi
+ mov ebx, [ecx+CBSTACK_RESULT_LENGTH]
+ mov [ebx], esi
+
+ /* Get the previous stack */
+ mov ebx, [ecx]
+
+ /* Disable interrupts for NPX save and stack switch */
+ cli
+
+ /* Get the initial stack and restore it */
+ mov esi, fs:[KPCR_INITIAL_STACK]
+ mov [eax+KTHREAD_INITIAL_STACK], ebx
+
+ /* Set desination and origin NPX Frames */
+ sub esi, NPX_FRAME_LENGTH
+ sub ebx, NPX_FRAME_LENGTH
+
+ /* Copy NPX Data */
+ mov edx, [esi+FN_CONTROL_WORD]
+ mov [ebx+FN_CONTROL_WORD], edx
+ mov edx, [esi+FN_STATUS_WORD]
+ mov [ebx+FN_STATUS_WORD], edx
+ mov edx, [esi+FN_TAG_WORD]
+ mov [ebx+FN_TAG_WORD], edx
+ mov edx, [esi+FN_DATA_SELECTOR]
+ mov [ebx+FN_DATA_SELECTOR], edx
+ mov edx, [esi+FN_CR0_NPX_STATE]
+ mov [ebx+FN_CR0_NPX_STATE], edx
+
+ /* Get saved trap frame and clear DR7 */
+ mov edi, [ecx+CBSTACK_TRAP_FRAME]
+ and dword ptr [edi+KTRAP_FRAME_DR7], 0
+
+ /* FIXME: Restore debug regs */
+
+ /* Get TSS */
+ mov edx, fs:[KPCR_TSS]
+
+ /* Restore stack pointer */
+ lea esp, [ecx+CBSTACK_CALLBACK_STACK]
+
+ /* Check if we were in V86 mode */
+ test dword ptr [edi+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
+ jnz V86Ret
+ sub ebx, 16
+
+V86Ret:
+ /* Restore the ESP in TSS */
+ mov [edx+KTSS_ESP0], ebx
+
+ /* Restore the trap frame */
+ mov [eax+KTHREAD_TRAP_FRAME], edi
+
+ /* Bring interrupts back */
+ sti
+
+ /* Restore the callback stack*/
+ pop [eax+KTHREAD_CALLBACK_STACK]
+
+ /* Set status and return */
+ mov eax, ebp
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ pop edx
+
+ /* Clean stack and jump back */
+ add esp, 8
+ jmp edx
+
+NoStack:
+
+ /* Return failure */
+ mov eax, STATUS_NO_CALLBACK_ACTIVE
+ ret 12
+
+.endfunc
+
+.globl _KeSwitchKernelStack@8
+.func KeSwitchKernelStack@8
+_KeSwitchKernelStack@8:
+
+ /* Save volatiles */
+ push esi
+ push edi
+
+ /* Get current thread */
+ mov edx, fs:[KPCR_CURRENT_THREAD]
+
+ /* Get new and current base */
+ mov edi, [esp+12]
+ mov ecx, [edx+KTHREAD_STACK_BASE]
+
+ /* Fixup the frame pointer */
+ sub ebp, ecx
+ add ebp, edi
+
+ /* Fixup the trap frame */
+ mov eax, [edx+KTHREAD_TRAP_FRAME]
+ sub eax, ecx
+ add eax, edi
+ mov [edx+KTHREAD_TRAP_FRAME], eax
+
+ /* Calculate stack size */
+ sub ecx, esp
+
+ /* Get desination and origin */
+ sub edi, ecx
+ mov esi, esp
+
+ /* Save stack pointer */
+ push edi
+
+ /* Copy stack */
+ rep movsb
+
+ /* Restore stack pointer */
+ pop edi
+
+ /* Save old stack base and get new limit/base */
+ mov eax, [edx+KTHREAD_STACK_BASE]
+ mov ecx, [esp+12]
+ mov esi, [esp+16]
+
+ /* Disable interrupts for stack switch */
+ cli
+
+ /* Set new base/limit */
+ mov [edx+KTHREAD_STACK_BASE], ecx
+ mov [edx+KTHREAD_STACK_LIMIT], esi
+
+ /* Set LargeStack */
+ mov byte ptr [edx+KTHREAD_LARGE_STACK], 1
+
+ /* Set new initial stack */
+ mov [edx+KTHREAD_INITIAL_STACK], ecx
+
+ /* Get trap frame */
+ mov esi, [edx+KTHREAD_TRAP_FRAME]
+
+ /* Get TSS */
+ mov edx, fs:[KPCR_TSS]
+
+ /* Check if we came from V86 mode */
+ test dword ptr [esi+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
+
+ /* Bias for NPX Area */
+ lea ecx, [ecx-NPX_FRAME_LENGTH]
+ jnz V86Switch
+ sub ecx, 16
+
+V86Switch:
+
+ /* Update ESP in TSS */
+ mov [edx+KTSS_ESP0], ecx
+
+ /* Update stack pointer */
+ mov esp, edi
+
+ /* Bring back interrupts and return */
+ sti
+ pop edi
+ pop esi
+ ret 8
+
+.endfunc