VOID FASTCALL KiEnterV86Mode(IN ULONG_PTR StackFrameUnaligned) { PKTHREAD Thread; PKV8086_STACK_FRAME StackFrame = (PKV8086_STACK_FRAME)(ROUND_UP(StackFrameUnaligned - 4, 16) + 4); PKTRAP_FRAME TrapFrame = &StackFrame->TrapFrame; PKV86_FRAME V86Frame = &StackFrame->V86Frame; PFX_SAVE_AREA NpxFrame = &StackFrame->NpxArea; ASSERT((ULONG_PTR)NpxFrame % 16 == 0); /* Build fake user-mode trap frame */ TrapFrame->SegCs = KGDT_R0_CODE | RPL_MASK; TrapFrame->SegEs = TrapFrame->SegDs = TrapFrame->SegFs = TrapFrame->SegGs = 0; TrapFrame->ErrCode = 0; /* Get the current thread's initial stack */ Thread = KeGetCurrentThread(); V86Frame->ThreadStack = KiGetThreadNpxArea(Thread); /* Save TEB addresses */ V86Frame->ThreadTeb = Thread->Teb; V86Frame->PcrTeb = KeGetPcr()->NtTib.Self; /* Save return EIP */ TrapFrame->Eip = (ULONG_PTR)Ki386BiosCallReturnAddress; /* Save our stack (after the frames) */ TrapFrame->Esi = StackFrameUnaligned; TrapFrame->Edi = (ULONG_PTR)_AddressOfReturnAddress() + 4; /* Sanitize EFlags and enable interrupts */ TrapFrame->EFlags = __readeflags() & 0x60DD7; TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK; /* Fill out the rest of the frame */ TrapFrame->HardwareSegSs = KGDT_R3_DATA | RPL_MASK; TrapFrame->HardwareEsp = 0x11FFE; TrapFrame->ExceptionList = EXCEPTION_CHAIN_END; TrapFrame->Dr7 = 0; /* Set some debug fields if trap debugging is enabled */ KiFillTrapFrameDebug(TrapFrame); /* Disable interrupts */ _disable(); /* Copy the thread's NPX frame */ RtlCopyMemory(NpxFrame, V86Frame->ThreadStack, sizeof(FX_SAVE_AREA)); /* Clear exception list */ KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END; /* Set new ESP0 */ KeGetPcr()->TSS->Esp0 = (ULONG_PTR)&TrapFrame->V86Es; /* Set new initial stack */ Thread->InitialStack = V86Frame; /* Set VDM TEB */ Thread->Teb = (PTEB)TRAMPOLINE_TEB; KiSetTebBase(KeGetPcr(), (PVOID)TRAMPOLINE_TEB); /* Enable interrupts */ _enable(); /* Start VDM execution */ NtVdmControl(VdmStartExecution, NULL); /* Exit to V86 mode */ KiEoiHelper(TrapFrame); }
VOID DECLSPEC_NORETURN FASTCALL HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame) { KPROCESSOR_MODE ProcessorMode; KIRQL OldIrql; ASSERT(ApicGetProcessorIrql() == APC_LEVEL); /* Enter trap */ KiEnterInterruptTrap(TrapFrame); #ifdef APIC_LAZY_IRQL if (!HalBeginSystemInterrupt(APC_LEVEL, APC_VECTOR, &OldIrql)) { /* "Spurious" interrupt, exit the interrupt */ KiEoiHelper(TrapFrame); } #else /* Save the old IRQL */ OldIrql = ApicGetCurrentIrql(); ASSERT(OldIrql < APC_LEVEL); #endif /* Raise to APC_LEVEL */ ApicRaiseIrql(APC_LEVEL); /* End the interrupt */ ApicSendEOI(); /* Kernel or user APC? */ if (KiUserTrap(TrapFrame)) ProcessorMode = UserMode; else if (TrapFrame->EFlags & EFLAGS_V86_MASK) ProcessorMode = UserMode; else ProcessorMode = KernelMode; /* Enable interrupts and call the kernel's APC interrupt handler */ _enable(); KiDeliverApc(ProcessorMode, NULL, TrapFrame); /* Disable interrupts */ _disable(); /* Restore the old IRQL */ ApicLowerIrql(OldIrql); /* Exit the interrupt */ KiEoiHelper(TrapFrame); }
VOID DECLSPEC_NORETURN FASTCALL HalpDispatchInterruptHandler(IN PKTRAP_FRAME TrapFrame) { KIRQL OldIrql; ASSERT(ApicGetProcessorIrql() == DISPATCH_LEVEL); /* Enter trap */ KiEnterInterruptTrap(TrapFrame); #ifdef APIC_LAZY_IRQL if (!HalBeginSystemInterrupt(DISPATCH_LEVEL, DISPATCH_VECTOR, &OldIrql)) { /* "Spurious" interrupt, exit the interrupt */ KiEoiHelper(TrapFrame); } #else /* Get the current IRQL */ OldIrql = ApicGetCurrentIrql(); ASSERT(OldIrql < DISPATCH_LEVEL); #endif /* Raise to DISPATCH_LEVEL */ ApicRaiseIrql(DISPATCH_LEVEL); /* End the interrupt */ ApicSendEOI(); /* Enable interrupts and call the kernel's DPC interrupt handler */ _enable(); KiDispatchInterrupt(); _disable(); /* Restore the old IRQL */ ApicLowerIrql(OldIrql); /* Exit the interrupt */ KiEoiHelper(TrapFrame); }
FORCEINLINE DECLSPEC_NORETURN VOID KiExitInterrupt(IN PKTRAP_FRAME TrapFrame, IN KIRQL OldIrql, IN BOOLEAN Spurious) { /* Check if this was a real interrupt */ if (!Spurious) { /* It was, disable interrupts and restore the IRQL */ _disable(); HalEndSystemInterrupt(OldIrql, TrapFrame); } /* Now exit the trap */ KiEoiHelper(TrapFrame); }
DECLSPEC_NORETURN VOID FASTCALL HalpTrap0DHandler(IN PKTRAP_FRAME TrapFrame) { /* Enter the trap */ KiEnterTrap(TrapFrame); /* Check if this is a V86 trap */ if (TrapFrame->EFlags & EFLAGS_V86_MASK) { /* Dispatch the opcode and exit the trap */ HalpDispatchV86Opcode(TrapFrame); KiEoiHelper(TrapFrame); } /* Strange, it isn't! This can happen during NMI */ DPRINT1("HAL: Trap0D while not in V86 mode\n"); KiDumpTrapFrame(TrapFrame); ERROR_FATAL(); while (TRUE); /* 'noreturn' function */ }
DECLSPEC_NORETURN VOID FASTCALL KiTrap07Handler(IN PKTRAP_FRAME TrapFrame) { PKTHREAD Thread, NpxThread; PFX_SAVE_AREA SaveArea, NpxSaveArea; ULONG Cr0; /* Save trap frame */ KiEnterTrap(TrapFrame); /* Try to handle NPX delay load */ while (TRUE) { /* Get the current thread */ Thread = KeGetCurrentThread(); /* Get the NPX frame */ SaveArea = KiGetThreadNpxArea(Thread); /* Check if emulation is enabled */ if (SaveArea->Cr0NpxState & CR0_EM) { /* Not implemented */ UNIMPLEMENTED; while (TRUE); } /* Save CR0 and check NPX state */ Cr0 = __readcr0(); if (Thread->NpxState != NPX_STATE_LOADED) { /* Update CR0 */ Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS); __writecr0(Cr0); /* Get the NPX thread */ NpxThread = KeGetCurrentPrcb()->NpxThread; if (NpxThread) { /* Get the NPX frame */ NpxSaveArea = KiGetThreadNpxArea(NpxThread); /* Save FPU state */ DPRINT("FIXME: Save FPU state: %p\n", NpxSaveArea); //Ke386SaveFpuState(NpxSaveArea); /* Update NPX state */ Thread->NpxState = NPX_STATE_NOT_LOADED; } /* Load FPU state */ //Ke386LoadFpuState(SaveArea); /* Update NPX state */ Thread->NpxState = NPX_STATE_LOADED; KeGetCurrentPrcb()->NpxThread = Thread; /* Enable interrupts */ _enable(); /* Check if CR0 needs to be reloaded due to context switch */ if (!SaveArea->Cr0NpxState) KiEoiHelper(TrapFrame); /* Otherwise, we need to reload CR0, disable interrupts */ _disable(); /* Reload CR0 */ Cr0 = __readcr0(); Cr0 |= SaveArea->Cr0NpxState; __writecr0(Cr0); /* Now restore interrupts and check for TS */ _enable(); if (Cr0 & CR0_TS) KiEoiHelper(TrapFrame); /* We're still here -- clear TS and try again */ __writecr0(__readcr0() &~ CR0_TS); _disable(); } else { /* This is an actual fault, not a lack of FPU state */ break; } } /* TS should not be set */ if (Cr0 & CR0_TS) { /* * If it's incorrectly set, then maybe the state is actually still valid * but we could've lock track of that due to a BIOS call. * Make sure MP is still set, which should verify the theory. */ if (Cr0 & CR0_MP) { /* Indeed, the state is actually still valid, so clear TS */ __writecr0(__readcr0() &~ CR0_TS); KiEoiHelper(TrapFrame); } /* Otherwise, something strange is going on */ KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 2, Cr0, 0, 0, TrapFrame); } /* It's not a delayed load, so process this trap as an NPX fault */ KiNpxHandler(TrapFrame, Thread, SaveArea); }