/* * @implemented */ BOOLEAN NTAPI KeInsertQueueDpc(IN PKDPC Dpc, IN PVOID SystemArgument1, IN PVOID SystemArgument2) { KIRQL OldIrql; PKPRCB Prcb, CurrentPrcb; ULONG Cpu; PKDPC_DATA DpcData; BOOLEAN DpcConfigured = FALSE, DpcInserted = FALSE; ASSERT_DPC(Dpc); /* Check IRQL and Raise it to HIGH_LEVEL */ KeRaiseIrql(HIGH_LEVEL, &OldIrql); CurrentPrcb = KeGetCurrentPrcb(); /* Check if the DPC has more then the maximum number of CPUs */ if (Dpc->Number >= MAXIMUM_PROCESSORS) { /* Then substract the maximum and get that PRCB. */ Cpu = Dpc->Number - MAXIMUM_PROCESSORS; Prcb = KiProcessorBlock[Cpu]; } else { /* Use the current one */ Prcb = CurrentPrcb; Cpu = Prcb->Number; } /* ROS Sanity Check */ ASSERT(Prcb == CurrentPrcb); /* Check if this is a threaded DPC and threaded DPCs are enabled */ if ((Dpc->Type == ThreadedDpcObject) && (Prcb->ThreadDpcEnable)) { /* Then use the threaded data */ DpcData = &Prcb->DpcData[DPC_THREADED]; } else { /* Otherwise, use the regular data */ DpcData = &Prcb->DpcData[DPC_NORMAL]; } /* Acquire the DPC lock */ KiAcquireSpinLock(&DpcData->DpcLock); /* Get the DPC Data */ if (!InterlockedCompareExchangePointer(&Dpc->DpcData, DpcData, NULL)) { /* Now we can play with the DPC safely */ Dpc->SystemArgument1 = SystemArgument1; Dpc->SystemArgument2 = SystemArgument2; DpcData->DpcQueueDepth++; DpcData->DpcCount++; DpcConfigured = TRUE; /* Check if this is a high importance DPC */ if (Dpc->Importance == HighImportance) { /* Pre-empty other DPCs */ InsertHeadList(&DpcData->DpcListHead, &Dpc->DpcListEntry); } else { /* Add it at the end */ InsertTailList(&DpcData->DpcListHead, &Dpc->DpcListEntry); } /* Check if this is the DPC on the threaded list */ if (&Prcb->DpcData[DPC_THREADED] == DpcData) { /* Make sure a threaded DPC isn't already active */ if (!(Prcb->DpcThreadActive) && !(Prcb->DpcThreadRequested)) { /* FIXME: Setup Threaded DPC */ UNIMPLEMENTED_FATAL("Threaded DPC not supported\n"); } } else { /* Make sure a DPC isn't executing already */ if (!(Prcb->DpcRoutineActive) && !(Prcb->DpcInterruptRequested)) { /* Check if this is the same CPU */ if (Prcb != CurrentPrcb) { /* * Check if the DPC is of high importance or above the * maximum depth. If it is, then make sure that the CPU * isn't idle, or that it's sleeping. */ if (((Dpc->Importance == HighImportance) || (DpcData->DpcQueueDepth >= Prcb->MaximumDpcQueueDepth)) && (!(AFFINITY_MASK(Cpu) & KiIdleSummary) || (Prcb->Sleeping))) { /* Set interrupt requested */ Prcb->DpcInterruptRequested = TRUE; /* Set DPC inserted */ DpcInserted = TRUE; } } else { /* Check if the DPC is of anything but low importance */ if ((Dpc->Importance != LowImportance) || (DpcData->DpcQueueDepth >= Prcb->MaximumDpcQueueDepth) || (Prcb->DpcRequestRate < Prcb->MinimumDpcRate)) { /* Set interrupt requested */ Prcb->DpcInterruptRequested = TRUE; /* Set DPC inserted */ DpcInserted = TRUE; } } } } } /* Release the lock */ KiReleaseSpinLock(&DpcData->DpcLock); /* Check if the DPC was inserted */ if (DpcInserted) { /* Check if this was SMP */ if (Prcb != CurrentPrcb) { /* It was, request and IPI */ KiIpiSend(AFFINITY_MASK(Cpu), IPI_DPC); } else { /* It wasn't, request an interrupt from HAL */ HalRequestSoftwareInterrupt(DISPATCH_LEVEL); } } /* Lower IRQL */ KeLowerIrql(OldIrql); return DpcConfigured; }
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_FATAL(); } /* 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 */ NpxThread->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); }
DECLSPEC_NORETURN VOID FASTCALL KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame) { ULONG i, j, Iopl; BOOLEAN Privileged = FALSE; PUCHAR Instructions; UCHAR Instruction = 0; KIRQL OldIrql; /* Check for V86 GPF */ if (__builtin_expect(KiV86Trap(TrapFrame), 1)) { /* Enter V86 trap */ KiEnterV86Trap(TrapFrame); /* Must be a VDM process */ if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0)) { /* Enable interrupts */ _enable(); /* Setup illegal instruction fault */ KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION, TrapFrame->Eip, TrapFrame); } /* Go to APC level */ OldIrql = KfRaiseIrql(APC_LEVEL); _enable(); /* Handle the V86 opcode */ if (__builtin_expect(Ki386HandleOpcodeV86(TrapFrame) == 0xFF, 0)) { /* Should only happen in VDM mode */ UNIMPLEMENTED_FATAL(); } /* Bring IRQL back */ KfLowerIrql(OldIrql); _disable(); /* Do a quick V86 exit if possible */ KiExitV86Trap(TrapFrame); } /* Save trap frame */ KiEnterTrap(TrapFrame); /* Check for user-mode GPF */ if (KiUserTrap(TrapFrame)) { /* Should not be VDM */ ASSERT(KiVdmTrap(TrapFrame) == FALSE); /* Enable interrupts and check error code */ _enable(); if (!TrapFrame->ErrCode) { /* FIXME: Use SEH */ Instructions = (PUCHAR)TrapFrame->Eip; /* Scan next 15 bytes */ for (i = 0; i < 15; i++) { /* Skip prefix instructions */ for (j = 0; j < sizeof(KiTrapPrefixTable); j++) { /* Is this a prefix instruction? */ if (Instructions[i] == KiTrapPrefixTable[j]) { /* Stop looking */ break; } } /* Is this NOT any prefix instruction? */ if (j == sizeof(KiTrapPrefixTable)) { /* We can go ahead and handle the fault now */ Instruction = Instructions[i]; break; } } /* If all we found was prefixes, then this instruction is too long */ if (i == 15) { /* Setup illegal instruction fault */ KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION, TrapFrame->Eip, TrapFrame); } /* Check for privileged instructions */ DPRINT("Instruction (%d) at fault: %lx %lx %lx %lx\n", i, Instructions[i], Instructions[i + 1], Instructions[i + 2], Instructions[i + 3]); if (Instruction == 0xF4) // HLT { /* HLT is privileged */ Privileged = TRUE; } else if (Instruction == 0x0F) { /* Test if it's any of the privileged two-byte opcodes */ if (((Instructions[i + 1] == 0x00) && // LLDT or LTR (((Instructions[i + 2] & 0x38) == 0x10) || // LLDT (Instructions[i + 2] == 0x18))) || // LTR ((Instructions[i + 1] == 0x01) && // LGDT or LIDT or LMSW (((Instructions[i + 2] & 0x38) == 0x10) || // LGDT (Instructions[i + 2] == 0x18) || // LIDT (Instructions[i + 2] == 0x30))) || // LMSW (Instructions[i + 1] == 0x08) || // INVD (Instructions[i + 1] == 0x09) || // WBINVD (Instructions[i + 1] == 0x35) || // SYSEXIT (Instructions[i + 1] == 0x21) || // MOV DR, XXX (Instructions[i + 1] == 0x06) || // CLTS (Instructions[i + 1] == 0x20) || // MOV CR, XXX (Instructions[i + 1] == 0x22) || // MOV XXX, CR (Instructions[i + 1] == 0x23) || // MOV YYY, DR (Instructions[i + 1] == 0x30) || // WRMSR (Instructions[i + 1] == 0x33)) // RDPMC // INVLPG, INVLPGA, SYSRET { /* These are all privileged */ Privileged = TRUE; } } else { /* Get the IOPL and compare with the RPL mask */ Iopl = (TrapFrame->EFlags & EFLAGS_IOPL) >> 12; if ((TrapFrame->SegCs & RPL_MASK) > Iopl) { /* I/O privilege error -- check for known instructions */ if ((Instruction == 0xFA) || (Instruction == 0xFB)) // CLI or STI { /* These are privileged */ Privileged = TRUE; } else { /* Last hope: an IN/OUT instruction */ for (j = 0; j < sizeof(KiTrapIoTable); j++) { /* Is this an I/O instruction? */ if (Instruction == KiTrapIoTable[j]) { /* Then it's privileged */ Privileged = TRUE; break; } } } } } /* So now... was the instruction privileged or not? */ if (Privileged) { /* Whew! We have a privileged instruction, so dispatch the fault */ KiDispatchException0Args(STATUS_PRIVILEGED_INSTRUCTION, TrapFrame->Eip, TrapFrame); } } /* If we got here, send an access violation */ KiDispatchException2Args(STATUS_ACCESS_VIOLATION, TrapFrame->Eip, 0, 0xFFFFFFFF, TrapFrame); }
DECLSPEC_NORETURN VOID FASTCALL KiTrap06Handler(IN PKTRAP_FRAME TrapFrame) { PUCHAR Instruction; ULONG i; KIRQL OldIrql; /* Check for V86 GPF */ if (__builtin_expect(KiV86Trap(TrapFrame), 1)) { /* Enter V86 trap */ KiEnterV86Trap(TrapFrame); /* Must be a VDM process */ if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0)) { /* Enable interrupts */ _enable(); /* Setup illegal instruction fault */ KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION, TrapFrame->Eip, TrapFrame); } /* Go to APC level */ OldIrql = KfRaiseIrql(APC_LEVEL); _enable(); /* Check for BOP */ if (!VdmDispatchBop(TrapFrame)) { /* Should only happen in VDM mode */ UNIMPLEMENTED_FATAL(); } /* Bring IRQL back */ KfLowerIrql(OldIrql); _disable(); /* Do a quick V86 exit if possible */ KiExitV86Trap(TrapFrame); } /* Save trap frame */ KiEnterTrap(TrapFrame); /* Enable interrupts */ Instruction = (PUCHAR)TrapFrame->Eip; _enable(); /* Check for user trap */ if (KiUserTrap(TrapFrame)) { /* FIXME: Use SEH */ /* Scan next 4 opcodes */ for (i = 0; i < 4; i++) { /* Check for LOCK instruction */ if (Instruction[i] == 0xF0) { /* Send invalid lock sequence exception */ KiDispatchException0Args(STATUS_INVALID_LOCK_SEQUENCE, TrapFrame->Eip, TrapFrame); } } /* FIXME: SEH ends here */ } /* Kernel-mode or user-mode fault (but not LOCK) */ KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION, TrapFrame->Eip, TrapFrame); }