/** * effects:Raise the interruption level to dispatch level, then * install VM Root hypervisor by call <CallbackProc> */ NTSTATUS NTAPI CmDeliverToProcessor ( CCHAR cProcessorNumber, PCALLBACK_PROC CallbackProc, PVOID CallbackParam, PNTSTATUS pCallbackStatus, BOOLEAN needRaiseIRQL ) { //Finish//SAME NTSTATUS CallbackStatus; KIRQL OldIrql; if (!CallbackProc) return STATUS_INVALID_PARAMETER; if (pCallbackStatus) *pCallbackStatus = STATUS_UNSUCCESSFUL; KeSetSystemAffinityThread ((KAFFINITY) (1 << cProcessorNumber)); if(needRaiseIRQL) OldIrql = KeRaiseIrqlToDpcLevel (); CallbackStatus = CallbackProc (CallbackParam); if(needRaiseIRQL) KeLowerIrql (OldIrql); KeRevertToUserAffinityThread (); // save the status of the callback which has run on the current core if (pCallbackStatus) *pCallbackStatus = CallbackStatus; return STATUS_SUCCESS; }
int GetKPCR(struct PmemMemoryInfo *info) { __int64 active_processors = KeQueryActiveProcessors(); int i; for (i=0; i < 32; i++) { info->KPCR[i].QuadPart = 0; }; for (i=0; i < 32; i++) { if (active_processors & ((__int64)1 << i)) { KeSetSystemAffinityThread((__int64)1 << i); #if _WIN64 || __amd64__ //64 bit uses gs and _KPCR.Self is at 0x18: info->KPCR[i].QuadPart = (uintptr_t)__readgsqword(0x18); #else //32 bit uses fs and _KPCR.SelfPcr is at 0x1c: info->KPCR[i].QuadPart = (uintptr_t)__readfsword(0x1c); #endif }; }; KeRevertToUserAffinityThread(); return 1; };
NTSTATUS GetDpcTimerInformation_x64(PDPC_TIMER_INFOR DpcTimerInfor) { ULONG CPUNumber = KeNumberProcessors; //系统变量 PUCHAR CurrentKPRCBAddress = NULL; PUCHAR CurrentTimerTableEntry = NULL; PLIST_ENTRY CurrentEntry = NULL; PLIST_ENTRY NextEntry = NULL; PULONG64 KiWaitAlways = NULL; PULONG64 KiWaitNever = NULL; int i = 0; int j = 0; int n = 0; PKTIMER Timer; typedef struct _KTIMER_TABLE_ENTRY { ULONG64 Lock; LIST_ENTRY Entry; ULARGE_INTEGER Time; } KTIMER_TABLE_ENTRY, *PKTIMER_TABLE_ENTRY; for(j=0; j<CPUNumber; j++) { KeSetSystemAffinityThread(j+1); //使当前线程运行在第一个处理器上 CurrentKPRCBAddress=(PUCHAR)__readmsr(0xC0000101) + 0x20; KeRevertToUserAffinityThread(); //恢复线程运行的处理器 CurrentTimerTableEntry=(PUCHAR)(*(ULONG64*)CurrentKPRCBAddress + 0x2200 + 0x200); FindKiWaitFunc(&KiWaitNever,&KiWaitAlways); //找KiWaitAlways 函数的地址 for(i=0; i<0x100; i++) { CurrentEntry = (PLIST_ENTRY)(CurrentTimerTableEntry + sizeof(KTIMER_TABLE_ENTRY) * i + 8); NextEntry = CurrentEntry->Blink; if( MmIsAddressValid(CurrentEntry) && MmIsAddressValid(CurrentEntry) ) { while( NextEntry != CurrentEntry ) { PKDPC RealDpc; //获得首地址 Timer = CONTAINING_RECORD(NextEntry,KTIMER,TimerListEntry); RealDpc=TransTimerDpcEx(Timer,*KiWaitNever,*KiWaitAlways); if( MmIsAddressValid(Timer)&&MmIsAddressValid(RealDpc)&&MmIsAddressValid(RealDpc->DeferredRoutine)) { if (DpcTimerInfor->ulCnt > DpcTimerInfor->ulRetCnt) { DpcTimerInfor->DpcTimer[n].Dpc = (ULONG64)RealDpc; DpcTimerInfor->DpcTimer[n].Period = Timer->Period; DpcTimerInfor->DpcTimer[n].TimeDispatch = (ULONG64)RealDpc->DeferredRoutine; DpcTimerInfor->DpcTimer[n].TimerObject = (ULONG64)Timer; n++; } DpcTimerInfor->ulRetCnt++; } NextEntry = NextEntry->Blink; } } } } }
CVirtualizedCpu::~CVirtualizedCpu() { if (NULL != m_hvStack) { KeSetSystemAffinityThread(PROCID(m_cpuCore)); (reinterpret_cast<CHyperVisor*>(m_hvStack + 1))->~CHyperVisor(); MmFreeContiguousMemory(m_hvStack); } }
VOID NTAPI PopShutdownSystem(IN POWER_ACTION SystemAction) { /* Note should notify caller of NtPowerInformation(PowerShutdownNotification) */ /* Unload symbols */ DPRINT("It's the final countdown...%lx\n", SystemAction); DbgUnLoadImageSymbols(NULL, (PVOID)-1, 0); /* Run the thread on the boot processor */ KeSetSystemAffinityThread(1); /* Now check what the caller wants */ switch (SystemAction) { /* Reset */ case PowerActionShutdownReset: /* Try platform driver first, then legacy */ //PopInvokeSystemStateHandler(PowerStateShutdownReset, NULL); PopSetSystemPowerState(PowerSystemShutdown, SystemAction); HalReturnToFirmware(HalRebootRoutine); break; case PowerActionShutdown: /* Check for group policy that says to use "it is now safe" screen */ if (PopShutdownPowerOffPolicy) { /* FIXFIX: Switch to legacy shutdown handler */ //PopPowerStateHandlers[PowerStateShutdownOff].Handler = PopShutdownHandler; } case PowerActionShutdownOff: /* Call shutdown handler */ //PopInvokeSystemStateHandler(PowerStateShutdownOff, NULL); /* ReactOS Hack */ PopSetSystemPowerState(PowerSystemShutdown, SystemAction); PopShutdownHandler(); /* If that didn't work, call the HAL */ HalReturnToFirmware(HalPowerDownRoutine); break; default: break; } /* Anything else should not happen */ KeBugCheckEx(INTERNAL_POWER_ERROR, 5, 0, 0, 0); }
void CSysCall::PerCoreAction( __in BYTE coreId ) { CCRonos::PerCoreAction(coreId); if (coreId < sizeof(m_syscalls)) { KeSetSystemAffinityThread(PROCID(coreId)); m_syscalls[coreId] = (void*)rdmsr(IA64_SYSENTER_EIP); HookSyscallMSR(sysenter); DbgPrint("Hooked. procid [%x] <=> syscall addr [%p]\n", coreId, m_syscalls[coreId]); } }
//-------------------------------------------------------------------------------------- void ClearWp(void) { // allow to execute the code only on the 1-st CPU KeSetSystemAffinityThread(0x00000001); __asm { mov eax, cr0 and eax, not 000010000h mov cr0, eax } }
CSysCall::~CSysCall() { BYTE core_id = 0; CProcessorWalker cpu_w; while (cpu_w.NextCore(&core_id, core_id)) { KeSetSystemAffinityThread(PROCID(core_id)); HookSyscallMSR(m_syscalls[core_id]); DbgPrint("Unhooked. procid [%x] <=> syscall addr [%p]\n", core_id, m_syscalls[core_id]); core_id++;//follow with next core } }
void * GetNtMajorVersion() { void * ptrNtMajorVersion; KeSetSystemAffinityThread(1); // select 1st processor _asm { mov eax, fs:[0x1C] // SelfPCR mov eax, [eax + 0x34] // _KPCR->KdVersionBlock mov eax, [eax + 0x10] // _DBGKD_GET_VERSION64->KernBase add eax, 0x120 // PE.MajorOperatingSystemVersion mov ptrNtMajorVersion, eax } KeRevertToUserAffinityThread(); return ptrNtMajorVersion; }
/* * @implemented */ BOOLEAN NTAPI KeConnectInterrupt(IN PKINTERRUPT Interrupt) { BOOLEAN Connected, Error, Status; KIRQL Irql, OldIrql; UCHAR Number; ULONG Vector; DISPATCH_INFO Dispatch; /* Get data from interrupt */ Number = Interrupt->Number; Vector = Interrupt->Vector; Irql = Interrupt->Irql; /* Validate the settings */ if ((Irql > HIGH_LEVEL) || (Number >= KeNumberProcessors) || (Interrupt->SynchronizeIrql < Irql) || (Interrupt->FloatingSave)) { return FALSE; } /* Set defaults */ Connected = FALSE; Error = FALSE; /* Set the system affinity and acquire the dispatcher lock */ KeSetSystemAffinityThread(1 << Number); OldIrql = KiAcquireDispatcherLock(); /* Check if it's already been connected */ if (!Interrupt->Connected) { /* Get vector dispatching information */ KiGetVectorDispatch(Vector, &Dispatch); /* Check if the vector is already connected */ if (Dispatch.Type == NoConnect) { /* Do the connection */ Interrupt->Connected = Connected = TRUE; /* Initialize the list */ InitializeListHead(&Interrupt->InterruptListEntry); /* Connect and enable the interrupt */ KiConnectVectorToInterrupt(Interrupt, NormalConnect); Status = HalEnableSystemInterrupt(Vector, Irql, Interrupt->Mode); if (!Status) Error = TRUE; } else if ((Dispatch.Type != UnknownConnect) && (Interrupt->ShareVector) && (Dispatch.Interrupt->ShareVector) && (Dispatch.Interrupt->Mode == Interrupt->Mode)) { /* The vector is shared and the interrupts are compatible */ Interrupt->Connected = Connected = TRUE; /* FIXME */ // ASSERT(Irql <= SYNCH_LEVEL); /* Check if this is the first chain */ if (Dispatch.Type != ChainConnect) { /* This is not supported */ ASSERT(Dispatch.Interrupt->Mode != Latched); /* Setup the chainned handler */ KiConnectVectorToInterrupt(Dispatch.Interrupt, ChainConnect); } /* Insert into the interrupt list */ InsertTailList(&Dispatch.Interrupt->InterruptListEntry, &Interrupt->InterruptListEntry); } } /* Unlock the dispatcher and revert affinity */ KiReleaseDispatcherLock(OldIrql); KeRevertToUserAffinityThread(); /* Check if we failed while trying to connect */ if ((Connected) && (Error)) { DPRINT1("HalEnableSystemInterrupt failed\n"); KeDisconnectInterrupt(Interrupt); Connected = FALSE; } /* Return to caller */ return Connected; }
NTSTATUS Ke386CallBios ( IN ULONG BiosCommand, IN OUT PCONTEXT BiosArguments ) /*++ Routine Description: This function invokes specified ROM BIOS code by executing "INT BiosCommand." Before executing the BIOS code, this function will setup VDM context, change stack pointer ...etc. If for some reason the operation fails, a status code will be returned. Otherwise, this function always returns success reguardless of the result of the BIOS call. N.B. This implementation relies on the fact that the direct I/O access operations between apps are serialized by win user. Arguments: BiosCommand - specifies which ROM BIOS function to invoke. BiosArguments - specifies a pointer to the context which will be used to invoke ROM BIOS. Return Value: NTSTATUS code to specify the failure. --*/ { NTSTATUS Status = STATUS_SUCCESS; PVDM_TIB VdmTib; PUCHAR BaseAddress = (PUCHAR)V86_CODE_ADDRESS; PTEB UserInt10Teb = (PTEB)INT_10_TEB; PKTSS Tss; PKPROCESS Process; PKTHREAD Thread; USHORT OldIopmOffset, OldIoMapBase; PVDM_PROCESS_OBJECTS VdmObjects; ULONG ContextLength; // KIRQL OldIrql; //#if DBG // PULONG IdtAddress; // ULONG RegionSize; // ULONG OldProtect; //#endif // // Map in ROM BIOS area to perform the int 10 code // if (!BiosInitialized) { RtlZeroMemory(UserInt10Teb, sizeof(TEB)); } //#if DBG // IdtAddress = 0; // RegionSize = 0x1000; // ZwProtectVirtualMemory ( NtCurrentProcess(), // &IdtAddress, // &RegionSize, // PAGE_READWRITE, // &OldProtect // ); //#endif try { // // Write "Int BiosCommand; bop" to reserved user space (0x1000). // Later control will transfer to the user space to execute // these two instructions. // *BaseAddress++ = INT_OPCODE; *BaseAddress++ = (UCHAR)BiosCommand; *(PULONG)BaseAddress = V86_BOP_OPCODE; // // Set up Vdm(v86) context to execute the int BiosCommand // instruction by copying user supplied context to VdmContext // and updating the control registers to predefined values. // // // We want to use a constant number for the int10. // // // Create a fake TEB so we can switch the thread to it while we // do an int10 // UserInt10Teb->Vdm = (PVOID)VDM_TIB_ADDRESS; VdmTib = (PVDM_TIB)VDM_TIB_ADDRESS; RtlZeroMemory(VdmTib, sizeof(VDM_TIB)); VdmTib->Size = sizeof(VDM_TIB); *pNtVDMState = 0; // // extended registers are never going to matter to // an Int10 call, so only copy the old part of the // context record. // ContextLength = FIELD_OFFSET(CONTEXT, ExtendedRegisters); RtlMoveMemory(&(VdmTib->VdmContext), BiosArguments, ContextLength); VdmTib->VdmContext.SegCs = (ULONG)BaseAddress >> 4; VdmTib->VdmContext.SegSs = (ULONG)BaseAddress >> 4; VdmTib->VdmContext.Eip = 0; VdmTib->VdmContext.Esp = 2 * PAGE_SIZE - sizeof(ULONG); VdmTib->VdmContext.EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK; VdmTib->VdmContext.ContextFlags = CONTEXT_FULL; } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } // // The vdm kernel code finds the Tib by looking at a pointer cached in // kernel memory, which was probed at Vdm creation time. Since the // creation semantics for this vdm are peculiar, we do something similar // here. // try { // // We never get here on a process that is a real vdm. If we do, // bad things will happen (pool leak, failure to execute dos and windows apps) // ASSERT(PsGetCurrentProcess()->VdmObjects == NULL); VdmObjects = ExAllocatePoolWithTag( NonPagedPool, sizeof(VDM_PROCESS_OBJECTS), ' eK' ); // // Since we are doing this on behalf of CSR not a user process, we aren't // charging quota. // if (VdmObjects == NULL) { Status = STATUS_NO_MEMORY; } else { // // We are only initializing the VdmTib pointer, because that's the only // part of the VdmObjects we use for ROM calls. We aren't set up // to simulate interrupts, or any of the other stuff that would be done // in a conventional vdm // RtlZeroMemory( VdmObjects, sizeof(VDM_PROCESS_OBJECTS)); VdmObjects->VdmTib = VdmTib; PsGetCurrentProcess()->VdmObjects = VdmObjects; } } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } if (Status == STATUS_SUCCESS) { // // Since we are going to v86 mode and accessing some I/O ports, we // need to make sure the IopmOffset is set correctly across context // swap and the I/O bit map has all the bits cleared. // N.B. This implementation assumes that there is only one full // screen DOS app and the io access between full screen DOS // app and the server code is serialized by win user. That // means even we change the IOPM, the full screen dos app won't // be able to run on this IOPM. // * In another words, IF THERE IS // * MORE THAN ONE FULL SCREEN DOS APPS, THIS CODE IS BROKEN.* // // NOTE This code works on the assumption that winuser serializes // direct I/O access operations. // // // Call the bios from the processor which booted the machine. // Thread = KeGetCurrentThread(); KeSetSystemAffinityThread(1); Tss = KeGetPcr()->TSS; // // Save away the original IOPM bit map and clear all the IOPM bits // to allow v86 int 10 code to access ALL the io ports. // // // Make sure there are at least 2 IOPM maps. // ASSERT(KeGetPcr()->GDT[KGDT_TSS / 8].LimitLow >= (0x2000 + IOPM_OFFSET - 1)); RtlMoveMemory (Ki386IopmSaveArea, (PVOID)&Tss->IoMaps[0].IoMap, PAGE_SIZE * 2 ); RtlZeroMemory ((PVOID)&Tss->IoMaps[0].IoMap, PAGE_SIZE * 2); Process = Thread->ApcState.Process; OldIopmOffset = Process->IopmOffset; OldIoMapBase = Tss->IoMapBase; Process->IopmOffset = (USHORT)(IOPM_OFFSET); // Set Process IoPmOffset before Tss->IoMapBase = (USHORT)(IOPM_OFFSET); // updating Tss IoMapBase // // Call ASM routine to switch stack to exit to v86 mode to // run Int BiosCommand. // Ki386SetupAndExitToV86Code(UserInt10Teb); // // After we return from v86 mode, the control comes here. // // Restore old IOPM // RtlMoveMemory ((PVOID)&Tss->IoMaps[0].IoMap, Ki386IopmSaveArea, PAGE_SIZE * 2 ); Process->IopmOffset = OldIopmOffset; Tss->IoMapBase = OldIoMapBase; // // Restore old affinity for current thread. // KeRevertToUserAffinityThread(); // // Copy 16 bit vdm context back to caller. // // Extended register state is not going to matter, // so copy only the old part of the context record. // ContextLength = FIELD_OFFSET(CONTEXT, ExtendedRegisters); RtlMoveMemory(BiosArguments, &(VdmTib->VdmContext), ContextLength); BiosArguments->ContextFlags = CONTEXT_FULL; // // Free the pool used for the VdmTib pointer // ExFreePool(PsGetCurrentProcess()->VdmObjects); PsGetCurrentProcess()->VdmObjects = NULL; } //#if DBG // IdtAddress = 0; // RegionSize = 0x1000; // ZwProtectVirtualMemory ( NtCurrentProcess(), // &IdtAddress, // &RegionSize, // PAGE_NOACCESS, // &OldProtect // ); //#endif return(Status); }
/* * @implemented */ NTSTATUS NTAPI Ke386CallBios(IN ULONG Int, OUT PCONTEXT Context) { PUCHAR Trampoline = (PUCHAR)TRAMPOLINE_BASE; PTEB VdmTeb = (PTEB)TRAMPOLINE_TEB; PVDM_TIB VdmTib = (PVDM_TIB)TRAMPOLINE_TIB; ULONG ContextSize = FIELD_OFFSET(CONTEXT, ExtendedRegisters); PKTHREAD Thread = KeGetCurrentThread(); PKTSS Tss = KeGetPcr()->TSS; PKPROCESS Process = Thread->ApcState.Process; PVDM_PROCESS_OBJECTS VdmProcessObjects; USHORT OldOffset, OldBase; /* Start with a clean TEB */ RtlZeroMemory(VdmTeb, sizeof(TEB)); /* Write the interrupt and bop */ *Trampoline++ = 0xCD; *Trampoline++ = (UCHAR)Int; *(PULONG)Trampoline = TRAMPOLINE_BOP; /* Setup the VDM TEB and TIB */ VdmTeb->Vdm = (PVOID)TRAMPOLINE_TIB; RtlZeroMemory(VdmTib, sizeof(VDM_TIB)); VdmTib->Size = sizeof(VDM_TIB); /* Set a blank VDM state */ *VdmState = 0; /* Copy the context */ RtlCopyMemory(&VdmTib->VdmContext, Context, ContextSize); VdmTib->VdmContext.SegCs = (ULONG_PTR)Trampoline >> 4; VdmTib->VdmContext.SegSs = (ULONG_PTR)Trampoline >> 4; VdmTib->VdmContext.Eip = 0; VdmTib->VdmContext.Esp = 2 * PAGE_SIZE - sizeof(ULONG_PTR); VdmTib->VdmContext.EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK; VdmTib->VdmContext.ContextFlags = CONTEXT_FULL; /* This can't be a real VDM process */ ASSERT(PsGetCurrentProcess()->VdmObjects == NULL); /* Allocate VDM structure */ VdmProcessObjects = ExAllocatePoolWithTag(NonPagedPool, sizeof(VDM_PROCESS_OBJECTS), ' eK'); if (!VdmProcessObjects) return STATUS_NO_MEMORY; /* Set it up */ RtlZeroMemory(VdmProcessObjects, sizeof(VDM_PROCESS_OBJECTS)); VdmProcessObjects->VdmTib = VdmTib; PsGetCurrentProcess()->VdmObjects = VdmProcessObjects; /* Set the system affinity for the current thread */ KeSetSystemAffinityThread(1); /* Make sure there's space for two IOPMs, then copy & clear the current */ ASSERT(((PKIPCR)KeGetPcr())->GDT[KGDT_TSS / 8].LimitLow >= (0x2000 + IOPM_OFFSET - 1)); RtlCopyMemory(Ki386IopmSaveArea, &Tss->IoMaps[0].IoMap, PAGE_SIZE * 2); RtlZeroMemory(&Tss->IoMaps[0].IoMap, PAGE_SIZE * 2); /* Save the old offset and base, and set the new ones */ OldOffset = Process->IopmOffset; OldBase = Tss->IoMapBase; Process->IopmOffset = (USHORT)IOPM_OFFSET; Tss->IoMapBase = (USHORT)IOPM_OFFSET; /* Switch stacks and work the magic */ Ki386SetupAndExitToV86Mode(VdmTeb); /* Restore IOPM */ RtlCopyMemory(&Tss->IoMaps[0].IoMap, Ki386IopmSaveArea, PAGE_SIZE * 2); Process->IopmOffset = OldOffset; Tss->IoMapBase = OldBase; /* Restore affinity */ KeRevertToUserAffinityThread(); /* Restore context */ RtlCopyMemory(Context, &VdmTib->VdmContext, ContextSize); Context->ContextFlags = CONTEXT_FULL; /* Free VDM objects */ ExFreePool(PsGetCurrentProcess()->VdmObjects); PsGetCurrentProcess()->VdmObjects = NULL; /* Return status */ return STATUS_SUCCESS; }
/*++ * @name ExSetTimerResolution * @exported * * The KiInsertQueueApc routine modifies the frequency at which the system * clock interrupts. * * @param DesiredTime * Specifies the amount of time that should elapse between each timer * interrupt, in 100-nanosecond units. * * This parameter is ignored if SetResolution is FALSE. * * @param SetResolution * If TRUE, the call is a request to set the clock interrupt frequency to * the value specified by DesiredTime. If FALSE, the call is a request to * restore the clock interrupt frequency to the system's default value. * * @return New timer resolution, in 100-nanosecond ticks. * * @remarks (1) The clock frequency is changed only if the DesiredTime value is * less than the current setting. * * (2) The routine just returns the current setting if the DesiredTime * value is greater than what is currently set. * * (3) If the DesiredTime value is less than the system clock can * support, the routine uses the smallest resolution the system can * support, and returns that value. * * (4) If multiple drivers have attempted to change the clock interrupt * frequency, the system will only restore the default frequency * once ALL drivers have called the routine with SetResolution set * to FALSE. * * NB. This routine synchronizes with IRP_MJ_POWER requests through the * TimeRefreshLock. * *--*/ ULONG NTAPI ExSetTimerResolution(IN ULONG DesiredTime, IN BOOLEAN SetResolution) { ULONG CurrentIncrement; /* Wait for clock interrupt frequency and power requests to synchronize */ ExAcquireTimeRefreshLock(TRUE); /* Obey remark 2*/ CurrentIncrement = KeTimeIncrement; /* Check the type of operation this is */ if (SetResolution) { /* * If this is the first kernel change, bump the timer resolution change * count, then bump the kernel change count as well. * * These two variables are tracked differently since user-mode processes * can also change the timer resolution through the NtSetTimerResolution * system call. A per-process flag in the EPROCESS then stores the per- * process change state. * */ if (!ExpKernelResolutionCount++) ExpTimerResolutionCount++; /* Obey remark 3 */ if (DesiredTime < KeMinimumIncrement) DesiredTime = KeMinimumIncrement; /* Obey remark 1 */ if (DesiredTime < KeTimeIncrement) { /* Force this thread on CPU zero, since we don't want it to drift */ KeSetSystemAffinityThread(1); /* Now call the platform driver (HAL) to make the change */ CurrentIncrement = HalSetTimeIncrement(DesiredTime); /* Put the thread back to its original affinity */ KeRevertToUserAffinityThread(); /* Finally, keep track of the new value in the kernel */ KeTimeIncrement = CurrentIncrement; } } else { /* First, make sure that a driver has actually changed the resolution */ if (ExpKernelResolutionCount) { /* Obey remark 4 */ if (--ExpKernelResolutionCount) { /* * All kernel drivers have requested the original frequency to * be restored, but there might still be user processes with an * ongoing clock interrupt frequency change, so make sure that * this isn't the case. */ if (--ExpTimerResolutionCount) { /* Force this thread on one CPU so that it doesn't drift */ KeSetSystemAffinityThread(1); /* Call the HAL to restore the frequency to its default */ CurrentIncrement = HalSetTimeIncrement(KeMaximumIncrement); /* Put the thread back to its original affinity */ KeRevertToUserAffinityThread(); /* Finally, keep track of the new value in the kernel */ KeTimeIncrement = CurrentIncrement; } } } } /* Release the clock interrupt frequency lock since changes are done */ ExReleaseTimeRefreshLock(); /* And return the current value -- which could reflect the new frequency */ return CurrentIncrement; }
BOOLEAN KeDisconnectInterrupt ( __inout PKINTERRUPT Interrupt ) /*++ Routine Description: This function disconnects an interrupt object from the interrupt vector specified by the interrupt object. If the interrupt object is not connected, then a value of FALSE is returned. Else the specified interrupt object is disconnected from the interrupt vector, the connected state is set to FALSE, and TRUE is returned as the function value. Arguments: Interrupt - Supplies a pointer to a control object of type interrupt. Return Value: If the interrupt object is not connected, then a value of FALSE is returned. Else a value of TRUE is returned. --*/ { DISPATCH_INFO DispatchInfo; BOOLEAN Connected; PKINTERRUPT Interrupty; KIRQL Irql; KIRQL OldIrql; ULONG Vector; // // Set system affinity to the specified processor. // KeSetSystemAffinityThread((KAFFINITY)(1<<Interrupt->Number)); // // Raise IRQL to dispatcher level and lock dispatcher database. // KiLockDispatcherDatabase(&OldIrql); // // If the interrupt object is connected, then disconnect it from the // specified vector. // Connected = Interrupt->Connected; if (Connected) { Irql = Interrupt->Irql; Vector = Interrupt->Vector; // // If the specified interrupt vector is not connected to the chained // interrupt dispatcher, then disconnect it by setting its dispatch // address to the unexpected interrupt routine. Else remove the // interrupt object from the interrupt chain. If there is only // one entry remaining in the list, then reestablish the dispatch // address. // // // Determine interrupt dispatch vector // KiGetVectorInfo ( Vector, &DispatchInfo ); // // Is dispatch a chained handler? // if (DispatchInfo.Type == ChainConnect) { ASSERT (Irql <= SYNCH_LEVEL); // // Is interrupt being removed from head? // if (Interrupt == DispatchInfo.Interrupt) { // // Update next interrupt object to be head // DispatchInfo.Interrupt = CONTAINING_RECORD( DispatchInfo.Interrupt->InterruptListEntry.Flink, KINTERRUPT, InterruptListEntry ); KiConnectVectorAndInterruptObject (DispatchInfo.Interrupt, ChainConnect); } // // Remove interrupt object // RemoveEntryList(&Interrupt->InterruptListEntry); // // If there's only one interrupt object left on this vector, // determine proper interrupt dispatcher // Interrupty = CONTAINING_RECORD( DispatchInfo.Interrupt->InterruptListEntry.Flink, KINTERRUPT, InterruptListEntry ); if (DispatchInfo.Interrupt == Interrupty) { KiConnectVectorAndInterruptObject (Interrupty, NormalConnect); } } else { // // Removing last interrupt object from the vector. Disable the // vector, and set it to unconnected // HalDisableSystemInterrupt(Interrupt->Vector, Irql); KiConnectVectorAndInterruptObject (Interrupt, NoConnect); } KeSweepIcache(TRUE); Interrupt->Connected = FALSE; } // // Unlock dispatcher database and lower IRQL to its previous value. // KiUnlockDispatcherDatabase(OldIrql); // // Set system affinity back to the original value. // KeRevertToUserAffinityThread(); // // Return whether interrupt was disconnected from the specified vector. // return Connected; }
BOOLEAN KeConnectInterrupt ( __inout PKINTERRUPT Interrupt ) /*++ Routine Description: This function connects an interrupt object to the interrupt vector specified by the interrupt object. If the interrupt object is already connected, or an attempt is made to connect to an interrupt that cannot be connected, then a value of FALSE is returned. Else the specified interrupt object is connected to the interrupt vector, the connected state is set to TRUE, and TRUE is returned as the function value. Arguments: Interrupt - Supplies a pointer to a control object of type interrupt. Return Value: If the interrupt object is already connected or an attempt is made to connect to an interrupt vector that cannot be connected, then a value of FALSE is returned. Else a value of TRUE is returned. --*/ { DISPATCH_INFO DispatchInfo; BOOLEAN Connected; BOOLEAN ConnectError; BOOLEAN Enabled; KIRQL Irql; CCHAR Number; KIRQL OldIrql; ULONG Vector; // // If the interrupt object is already connected, the interrupt vector // number is invalid, an attempt is being made to connect to a vector // that cannot be connected, the interrupt request level is invalid, or // the processor number is invalid, then do not connect the interrupt // object. Else connect interrupt object to the specified vector and // establish the proper interrupt dispatcher. // Connected = FALSE; ConnectError = FALSE; Irql = Interrupt->Irql; Number = Interrupt->Number; Vector = Interrupt->Vector; if ( !((Irql > HIGH_LEVEL) || (Number >= KeNumberProcessors) || (Interrupt->SynchronizeIrql < Irql) || (Interrupt->FloatingSave) // R0 x87 usage not supported on x86 ) ) { // // // Set system affinity to the specified processor. // KeSetSystemAffinityThread((KAFFINITY)(1<<Number)); // // Raise IRQL to dispatcher level and lock dispatcher database. // KiLockDispatcherDatabase(&OldIrql); // // Is interrupt object already connected? // if (!Interrupt->Connected) { // // Determine interrupt dispatch vector // KiGetVectorInfo ( Vector, &DispatchInfo ); // // If dispatch vector is not connected, then connect it // if (DispatchInfo.Type == NoConnect) { Connected = TRUE; Interrupt->Connected = TRUE; // // Connect interrupt dispatch to interrupt object dispatch code // InitializeListHead(&Interrupt->InterruptListEntry); KiConnectVectorAndInterruptObject (Interrupt, NormalConnect); // // Enabled system vector // Enabled = HalEnableSystemInterrupt(Vector, Irql, Interrupt->Mode); if (!Enabled) { ConnectError = TRUE; } } else if (DispatchInfo.Type != UnknownConnect && Interrupt->ShareVector && DispatchInfo.Interrupt->ShareVector && DispatchInfo.Interrupt->Mode == Interrupt->Mode) { // // Vector is already connected as sharable. New vector is sharable // and modes match. Chain new vector. // Connected = TRUE; Interrupt->Connected = TRUE; ASSERT (Irql <= SYNCH_LEVEL); // // If not already using chained dispatch handler, set it up // if (DispatchInfo.Type != ChainConnect) { KiConnectVectorAndInterruptObject (DispatchInfo.Interrupt, ChainConnect); } // // Add to tail of chained dispatch // InsertTailList( &DispatchInfo.Interrupt->InterruptListEntry, &Interrupt->InterruptListEntry ); } } // // Unlock dispatcher database and lower IRQL to its previous value. // KiUnlockDispatcherDatabase(OldIrql); // // Set system affinity back to the original value. // KeRevertToUserAffinityThread(); } if (Connected && ConnectError) { #if DBG DbgPrint ("HalEnableSystemInterrupt failed\n"); #endif KeDisconnectInterrupt (Interrupt); Connected = FALSE; } // // Return whether interrupt was connected to the specified vector. // return Connected; }
//-------------------------------------------------------------------------------------- NTSTATUS DriverDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) { NTSTATUS ns = STATUS_INVALID_DEVICE_REQUEST; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); ULONG InSize = 0, OutSize = 0; Irp->IoStatus.Status = ns; Irp->IoStatus.Information = 0; if (stack->MajorFunction == IRP_MJ_DEVICE_CONTROL) { // get IOCTL parameters ULONG Code = stack->Parameters.DeviceIoControl.IoControlCode; PREQUEST_BUFFER Buff = (PREQUEST_BUFFER)Irp->AssociatedIrp.SystemBuffer; InSize = stack->Parameters.DeviceIoControl.InputBufferLength; OutSize = stack->Parameters.DeviceIoControl.OutputBufferLength; DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): IRP_MJ_DEVICE_CONTROL 0x%.8x\n", Code); // check buffer length if (InSize >= sizeof(REQUEST_BUFFER) && OutSize >= sizeof(REQUEST_BUFFER)) { switch (Code) { case IOCTL_DRV_CONTROL: { switch (Buff->Code) { case DRV_CTL_NONE: { // do nothing, just return successful status ns = STATUS_SUCCESS; break; } case DRV_CTL_VIRT_MEM_READ: { if (InSize >= sizeof(REQUEST_BUFFER) + Buff->MemRead.Size) { // read virtual memory memcpy( Buff->MemRead.Data, (PVOID)Buff->MemRead.Address, Buff->MemRead.Size ); ns = STATUS_SUCCESS; } break; } case DRV_CTL_VIRT_MEM_WRITE: { if (InSize >= sizeof(REQUEST_BUFFER) + Buff->MemWrite.Size) { // write virtual memory memcpy( (PVOID)Buff->MemWrite.Address, Buff->MemWrite.Data, Buff->MemWrite.Size ); ns = STATUS_SUCCESS; } break; } case DRV_CTL_PHYS_MEM_READ: { if (InSize >= sizeof(REQUEST_BUFFER) + Buff->MemRead.Size) { // read physical memory ns = HwPhysMemRead( Buff->MemRead.Address, Buff->MemRead.Size, Buff->MemRead.Data ); } break; } case DRV_CTL_PHYS_MEM_WRITE: { if (InSize >= sizeof(REQUEST_BUFFER) + Buff->MemWrite.Size) { // write physical memory ns = HwPhysMemWrite( Buff->MemWrite.Address, Buff->MemWrite.Size, Buff->MemWrite.Data ); } break; } case DRV_CTL_PHYS_MEM_MAP: { PPHYS_MEM_REGION MemRegion = Buff->MemMap.Regions; Buff->MemMap.RegionsCount = 0; if (f_MmGetPhysicalMemoryRanges) { // get physical memory information PPHYSICAL_MEMORY_RANGE MemInfo = f_MmGetPhysicalMemoryRanges(); if (MemInfo) { NTSTATUS Status = STATUS_SUCCESS; while (MemInfo->BaseAddress.QuadPart != 0 || MemInfo->NumberOfBytes.QuadPart != 0) { if (InSize >= sizeof(REQUEST_BUFFER) + sizeof(PHYS_MEM_REGION) * (Buff->MemMap.RegionsCount + 1)) { // copy region information to IOCTL request buffer Buff->MemMap.Regions[Buff->MemMap.RegionsCount].Address = MemInfo->BaseAddress.QuadPart; Buff->MemMap.Regions[Buff->MemMap.RegionsCount].Size = MemInfo->NumberOfBytes.QuadPart; Buff->MemMap.RegionsCount += 1; } else { Status = STATUS_UNSUCCESSFUL; break; } MemInfo += 1; MemRegion += 1; } ns = Status; } else { DbgMsg(__FILE__, __LINE__, "ERROR: MmGetPhysicalMemoryRange() fails\n"); } } break; } case DRV_CTL_PORT_READ: { // read I/O port value ns = HwPortRead(Buff->PortRead.Port, Buff->PortRead.Size, &Buff->PortRead.Val); break; } case DRV_CTL_PORT_WRITE: { // write value to I/O port ns = HwPortWrite(Buff->PortWrite.Port, Buff->PortWrite.Size, Buff->PortWrite.Val); break; } case DRV_CTL_PCI_READ: { // read PCI config space register value ns = HwPciRead(Buff->PciRead.Address, Buff->PciRead.Size, &Buff->PciRead.Val); break; } case DRV_CTL_PCI_WRITE: { // write value to PCI config space egister ns = HwPciWrite(Buff->PciWrite.Address, Buff->PciWrite.Size, Buff->PciWrite.Val); break; } case DRV_CTL_SMI_INVOKE: { // invoke SMI via APMC I/O port ns = HwSmiInvoke(Buff->SmiInvoke.Code); break; } case DRV_CTL_MEM_ALLOC: { // allocate memory if ((ns = HwMemAlloc(&Buff->MemAlloc.Address, Buff->MemAlloc.Size)) == STATUS_SUCCESS) { // get physical address by virtual ns = HwGetPhysAddr(Buff->MemAlloc.Address, &Buff->MemAlloc.PhysicalAddress); } break; } case DRV_CTL_MEM_FREE: { // free allocated memory ns = HwMemFree(Buff->MemFree.Address); break; } case DRV_CTL_PHYS_ADDR: { // get physical address by virtual ns = HwGetPhysAddr(Buff->PhysAddr.Address, &Buff->PhysAddr.PhysicalAddress); break; } case DRV_CTL_MSR_GET: { // get MSR value ns = HwMsrGet(Buff->MsrGet.Register, &Buff->MsrGet.Value); break; } case DRV_CTL_MSR_SET: { // set MSR value ns = HwMsrSet(Buff->MsrSet.Register, Buff->MsrSet.Value); break; } #ifdef USE_DSE_BYPASS case DRV_CTL_RESTORE_CR4: { // get bitmask of active processors KAFFINITY ActiveProcessors = KeQueryActiveProcessors(); ULONG cr4_val = 0, cr4_current = 0; // enumerate active processors starting from 2-nd for (KAFFINITY i = 1; i < sizeof(KAFFINITY) * 8; i++) { KAFFINITY Mask = 1 << i; if (ActiveProcessors & Mask) { // bind thread to specific processor KeSetSystemAffinityThread(Mask); // read CR4 register of other CPU cr4_val = _cr4_get(); break; } } if (cr4_val != 0) { // bind thread to first processor KeSetSystemAffinityThread(0x00000001); if ((cr4_current = _cr4_get()) != cr4_val) { DbgMsg(__FILE__, __LINE__, "Restoring CR4 value from 0x%.8x to 0x%.8x\n", cr4_current, cr4_val); // restore CR4 register of current CPU _cr4_set(cr4_val); } else { DbgMsg(__FILE__, __LINE__, "CR4 is 0x%.8x\n", cr4_current); } ns = STATUS_SUCCESS; } else { DbgMsg(__FILE__, __LINE__, "ERROR: Unable to read CR4 value from 2-nd processor\n"); } break; } #endif // USE_DSE_BYPASS default: { DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Unknown control code 0x%x\n", Code); break; } } break; } default: { break; } } } if (ns == STATUS_SUCCESS) { Irp->IoStatus.Information = InSize; } } else if (stack->MajorFunction == IRP_MJ_CREATE) { DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): IRP_MJ_CREATE\n"); ns = STATUS_SUCCESS; } else if (stack->MajorFunction == IRP_MJ_CLOSE) { DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): IRP_MJ_CLOSE\n"); ns = STATUS_SUCCESS; } if (ns != STATUS_PENDING) { Irp->IoStatus.Status = ns; IoCompleteRequest(Irp, IO_NO_INCREMENT); } return ns; }
NTKERNELAPI PEX_PUSH_LOCK_CACHE_AWARE ExAllocateCacheAwarePushLock ( VOID ) /*++ Routine Description: Allocate a cache aware (cache friendly) push lock Arguments: None Return Value: None --*/ { PEX_PUSH_LOCK_CACHE_AWARE PushLockCacheAware; PEX_PUSH_LOCK_CACHE_AWARE_PADDED PaddedPushLock; ULONG i, j, MaxLine; PushLockCacheAware = ExAllocatePoolWithTag (PagedPool, sizeof (EX_PUSH_LOCK_CACHE_AWARE), 'pclP'); if (PushLockCacheAware != NULL) { // // If we are a non-numa machine then allocate the padded push locks as a single block // if (KeNumberNodes == 1) { PaddedPushLock = ExAllocatePoolWithTag (PagedPool, sizeof (EX_PUSH_LOCK_CACHE_AWARE_PADDED)* EX_PUSH_LOCK_FANNED_COUNT, 'lclP'); if (PaddedPushLock == NULL) { ExFreePool (PushLockCacheAware); return NULL; } for (i = 0; i < EX_PUSH_LOCK_FANNED_COUNT; i++) { PaddedPushLock->Single = TRUE; ExInitializePushLock (&PaddedPushLock->Lock); PushLockCacheAware->Locks[i] = &PaddedPushLock->Lock; PaddedPushLock++; } } else { // // Allocate a different block for each lock and set affinity // so the allocation comes from that node's memory. // MaxLine = KeNumberProcessors; if (MaxLine > EX_PUSH_LOCK_FANNED_COUNT) { MaxLine = EX_PUSH_LOCK_FANNED_COUNT; } for (i = 0; i < MaxLine; i++) { KeSetSystemAffinityThread (AFFINITY_MASK (i)); PaddedPushLock = ExAllocatePoolWithTag (PagedPool, sizeof (EX_PUSH_LOCK_CACHE_AWARE_PADDED), 'lclP'); if (PaddedPushLock == NULL) { for (j = 0; j < i; j++) { ExFreePool (PushLockCacheAware->Locks[j]); } KeRevertToUserAffinityThread (); ExFreePool (PushLockCacheAware); return NULL; } PaddedPushLock->Single = FALSE; ExInitializePushLock (&PaddedPushLock->Lock); PushLockCacheAware->Locks[i] = &PaddedPushLock->Lock; } KeRevertToUserAffinityThread (); } } return PushLockCacheAware; }
NTSTATUS KeDeregisterNmiCallback ( __in PVOID Handle ) /*++ Routine Description: This routine is called to remove a callback from the list of Non- Maskable-Interrupt callbacks. This routine must be called at IRQL < DISPATCH_LEVEL. List removal must be such that the list is ALWAYS valid, an NMI could occur during removal and the NMI handler must be able to safely transit the list. Arguments: Handle supplied an opaque handle to the callback object that was returned by KeRegisterNmiCallback. Return Value: Returns STATUS_SUCCESS if the object was successfully removed from the list. STATUS_INVALID_HANDLE otherwise. --*/ { PKNMI_HANDLER_CALLBACK Handler; PKNMI_HANDLER_CALLBACK *PreviousNext; KIRQL OldIrql; #if !defined(NT_UP) KAFFINITY ActiveProcessors; KAFFINITY CurrentAffinity; #endif ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); KeAcquireSpinLock(&KiNmiCallbackListLock, &OldIrql); // // Find the handler given the list of handlers. // // N.B. In the current implementation, the handle is the address // of the handler however this code is designed for a more opaque // handle. // PreviousNext = &KiNmiCallbackListHead; for (Handler = *PreviousNext; Handler; PreviousNext = &Handler->Next, Handler = Handler->Next) { if (Handler->Handle == Handle) { ASSERT(Handle == Handler); break; } } if ((Handler == NULL) || (Handler->Handle != Handle)) { KeReleaseSpinLock(&KiNmiCallbackListLock, OldIrql); return STATUS_INVALID_HANDLE; } // // Remove this handler from the list. // *PreviousNext = Handler->Next; KeReleaseSpinLock(&KiNmiCallbackListLock, OldIrql); // // Cycle through each processor in the system to ensure that any // NMI which has begun execution on another processor has completed // execution before releasing the memory for the NMI callback object. // #if !defined(NT_UP) ActiveProcessors = KeActiveProcessors; for (CurrentAffinity = 1; ActiveProcessors; CurrentAffinity <<= 1) { if (ActiveProcessors & CurrentAffinity) { ActiveProcessors &= ~CurrentAffinity; KeSetSystemAffinityThread(CurrentAffinity); } } KeRevertToUserAffinityThread(); #endif ExFreePoolWithTag(Handler, 'IMNK'); return STATUS_SUCCESS; }
BOOLEAN KeDisconnectInterrupt ( IN PKINTERRUPT Interrupt ) /*++ Routine Description: This function disconnects an interrupt object from the interrupt vector specified by the interrupt object. If the interrupt object is not connected, then a value of FALSE is returned. Else the specified interrupt object is disconnected from the interrupt vector, the connected state is set to FALSE, and TRUE is returned as the function value. Arguments: Interrupt - Supplies a pointer to a control object of type interrupt. Return Value: If the interrupt object is not connected, then a value of FALSE is returned. Else a value of TRUE is returned. --*/ { BOOLEAN Connected; PKINTERRUPT Interruptx; PKINTERRUPT Interrupty; KIRQL Irql; KIRQL OldIrql; KIRQL PreviousIrql; ULONG Vector; // // Set system affinity to the specified processor. // KeSetSystemAffinityThread((KAFFINITY)(1 << Interrupt->Number)); // // Raise IRQL to dispatcher level and lock dispatcher database. // KiLockDispatcherDatabase(&OldIrql); // // If the interrupt object is connected, then disconnect it from the // specified vector. // Connected = Interrupt->Connected; if (Connected != FALSE) { Irql = Interrupt->Irql; Vector = Interrupt->Vector; // // If the specified interrupt vector is not connected to the chained // interrupt dispatcher, then disconnect it by setting its dispatch // address to the unexpected interrupt routine. Else remove the // interrupt object from the interrupt chain. If there is only // one entry remaining in the list, then reestablish the dispatch // address. // Interruptx = CONTAINING_RECORD(PCR->InterruptRoutine[Vector], KINTERRUPT, DispatchCode[0]); if (Interruptx->DispatchAddress == (PKINTERRUPT_ROUTINE)KiChainedDispatch) { KeRaiseIrql((KIRQL)(max(Irql, SYNCH_LEVEL)), &PreviousIrql); if (Interrupt == Interruptx) { Interruptx = CONTAINING_RECORD(Interruptx->InterruptListEntry.Flink, KINTERRUPT, InterruptListEntry); Interruptx->DispatchAddress = (PKINTERRUPT_ROUTINE)KiChainedDispatch; Interruptx->DispatchCode[0] = *(PULONG)KiChainedDispatch; Interruptx->DispatchCode[1] = *(((PULONG)KiChainedDispatch)+1); PCR->InterruptRoutine[Vector] = (PKINTERRUPT_ROUTINE)Interruptx->DispatchCode; } RemoveEntryList(&Interrupt->InterruptListEntry); Interrupty = CONTAINING_RECORD(Interruptx->InterruptListEntry.Flink, KINTERRUPT, InterruptListEntry); if (Interruptx == Interrupty) { if (Interrupt->FloatingSave) { Interrupt->DispatchAddress = KiFloatingDispatch; } else { if (Interrupt->Irql == Interrupt->SynchronizeIrql) { #if defined(NT_UP) Interrupt->DispatchAddress = (PKINTERRUPT_ROUTINE)Interrupt->ServiceRoutine; #else Interrupt->DispatchAddress = (PKINTERRUPT_ROUTINE)KiInterruptDispatchSame; #endif } else { Interrupt->DispatchAddress = (PKINTERRUPT_ROUTINE)KiInterruptDispatchRaise; } } // // Copy the function descriptor for the Dispatch routine // into DispatchCode. This will be used by KiInterruptEx- // ception to dispatch the interrupt. // Interrupty->DispatchCode[0] = *(PULONG)(Interrupty->DispatchAddress); Interrupty->DispatchCode[1] = *(((PULONG)(Interrupty->DispatchAddress))+1); PCR->InterruptRoutine[Vector] = (PKINTERRUPT_ROUTINE)Interrupty->DispatchCode; } KeLowerIrql(PreviousIrql); } else { HalDisableSystemInterrupt(Vector, Irql); PCR->InterruptRoutine[Vector] = (PKINTERRUPT_ROUTINE)(&KxUnexpectedInterrupt.DispatchCode); } #ifdef NOTDEF KeSweepIcache(TRUE); #endif Interrupt->Connected = FALSE; } // // Unlock dispatcher database and lower IRQL to its previous value. // KiUnlockDispatcherDatabase(OldIrql); // // Set system affinity back to the original value. // KeRevertToUserAffinityThread(); // // Return whether interrupt was disconnected from the specified vector. // return Connected; }
BOOLEAN KeConnectInterrupt ( IN PKINTERRUPT Interrupt ) /*++ Routine Description: This function connects an interrupt object to the interrupt vector specified by the interrupt object. If the interrupt object is already connected, or an attempt is made to connect to an interrupt that cannot be connected, then a value of FALSE is returned. Else the specified interrupt object is connected to the interrupt vector, the connected state is set to TRUE, and TRUE is returned as the function value. Arguments: Interrupt - Supplies a pointer to a control object of type interrupt. Return Value: If the interrupt object is already connected or an attempt is made to connect to an interrupt vector that cannot be connected, then a value of FALSE is returned. Else a value of TRUE is returned. --*/ { BOOLEAN Connected; PKINTERRUPT Interruptx; KIRQL Irql; CHAR Number; KIRQL OldIrql; KIRQL PreviousIrql; ULONG Vector; // // If the interrupt object is already connected, the interrupt vector // number is invalid, an attempt is being made to connect to a vector // that cannot be connected, the interrupt request level is invalid, // the processor number is invalid, of the interrupt vector is less // than or equal to the highest level and it not equal to the specified // IRQL, then do not connect the interrupt object. Else connect interrupt // object to the specified vector and establish the proper interrupt // dispatcher. // Connected = FALSE; Irql = Interrupt->Irql; Number = Interrupt->Number; Vector = Interrupt->Vector; if ( (Vector < MAXIMUM_VECTOR) && // will fit in interrupt table (Irql <= HIGH_LEVEL) && // is at a reasonable priority (Number < KeNumberProcessors) && // can run on a cpu we have ( (Vector > HIGH_LEVEL) || // and is either EISA or ((PCR->ReservedVectors & (1 << Vector)) == 0) // is NOT reserved ) ) { // // // Set system affinity to the specified processor. // KeSetSystemAffinityThread((KAFFINITY)(1 << Number)); // // Raise IRQL to dispatcher level and lock dispatcher database. // KiLockDispatcherDatabase(&OldIrql); // // If the specified interrupt vector is not connected, then // connect the interrupt vector to the interrupt dispatcher // and set the new interrupt mode and enable masks. // Else if the interrupt is // already chained, then add the new interrupt object at the end // of the chain. If the interrupt vector is not chained, then // start a chain with the previous interrupt object at the front // of the chain. The interrupt mode of all interrupt objects in // a chain must be the same. // if (Interrupt->Connected == FALSE) { if (PCR->InterruptRoutine[Vector] == (PKINTERRUPT_ROUTINE)(&KxUnexpectedInterrupt.DispatchCode)) { Connected = TRUE; Interrupt->Connected = TRUE; if (Interrupt->FloatingSave) { Interrupt->DispatchAddress = KiFloatingDispatch; } else { if (Interrupt->Irql == Interrupt->SynchronizeIrql) { #if defined(NT_UP) Interrupt->DispatchAddress = (PKINTERRUPT_ROUTINE)Interrupt->ServiceRoutine; #else Interrupt->DispatchAddress = (PKINTERRUPT_ROUTINE)KiInterruptDispatchSame; #endif } else { Interrupt->DispatchAddress = (PKINTERRUPT_ROUTINE)KiInterruptDispatchRaise; } } // // Copy the function descriptor for the Dispatch routine // into DispatchCode. This will be used by KiInterruptEx- // ception to dispatch the interrupt. // Interrupt->DispatchCode[0] = *(PULONG)(Interrupt->DispatchAddress); Interrupt->DispatchCode[1] = *(((PULONG)(Interrupt->DispatchAddress))+1); PCR->InterruptRoutine[Vector] = (PKINTERRUPT_ROUTINE)Interrupt->DispatchCode; HalEnableSystemInterrupt(Vector, Irql, Interrupt->Mode); } else if (Interrupt->ShareVector) { Interruptx = CONTAINING_RECORD(PCR->InterruptRoutine[Vector], KINTERRUPT, DispatchCode[0]); if (Interruptx->ShareVector && Interrupt->Mode == Interruptx->Mode) { Connected = TRUE; Interrupt->Connected = TRUE; KeRaiseIrql((KIRQL)(max(Irql, SYNCH_LEVEL)), &PreviousIrql); if (Interruptx->DispatchAddress != (PKINTERRUPT_ROUTINE)KiChainedDispatch) { InitializeListHead(&Interruptx->InterruptListEntry); Interruptx->DispatchAddress = (PKINTERRUPT_ROUTINE)KiChainedDispatch; Interruptx->DispatchCode[0] = *(PULONG)KiChainedDispatch; Interruptx->DispatchCode[1] = *(((PULONG)KiChainedDispatch)+1); } InsertTailList(&Interruptx->InterruptListEntry, &Interrupt->InterruptListEntry); KeLowerIrql(PreviousIrql); } } } // // Unlock dispatcher database and lower IRQL to its previous value. // KiUnlockDispatcherDatabase(OldIrql); // // Set system affinity back to the original value. // KeRevertToUserAffinityThread(); } // // Return whether interrupt was connected to the specified vector. // return Connected; }
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING pRegistryPath) { NTSTATUS Status; PDEVICE_OBJECT DeviceObject; PEPROCESS Process; PETHREAD Thread; PKAPC_STATE ApcState; PVOID KdVersionBlock,NtdllBase; PULONG ptr,Functions,Names; PUSHORT Ordinals; PLDR_DATA_TABLE_ENTRY MmLoadedUserImageList,ModuleEntry; ULONG i; PIMAGE_DOS_HEADER pIDH; PIMAGE_NT_HEADERS pINH; PIMAGE_EXPORT_DIRECTORY pIED; UNICODE_STRING uniDeviceName; UNICODE_STRING uniLinkName; RtlInitUnicodeString(&uniDeviceName,DEVICE_NAME); RtlInitUnicodeString(&uniLinkName,LINK_NAME); for (i=0;i<IRP_MJ_MAXIMUM_FUNCTION;i++) { DriverObject->MajorFunction[i] = DefaultPassThrough; } DriverObject->DriverUnload = UnloadDriver; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverDispatch; //创建设备对象 Status = IoCreateDevice(DriverObject,0,&uniDeviceName,FILE_DEVICE_UNKNOWN,0,FALSE,&DeviceObject); if (!NT_SUCCESS(Status)) { return Status; } Status = IoCreateSymbolicLink(&uniLinkName,&uniDeviceName); if (!NT_SUCCESS(Status)) { IoDeleteDevice(DeviceObject); return Status; } //使当前线程运行在第一个处理器上 KeSetSystemAffinityThread(1); KdVersionBlock=(PVOID)__readfsdword(0x34); //得到KdVersionBlock KeRevertToUserAffinityThread();//恢复线程运行的处理器 MmLoadedUserImageList=*(PLDR_DATA_TABLE_ENTRY*)((PUCHAR)KdVersionBlock+0x228); // Get the MmLoadUserImageList /* kd> !pcr KPCR for Processor 0 at 83f3ec00: kd> dt _kpcr 83f3ec00 +0x034 KdVersionBlock : 0x83f3dc00 Void kd> dd 0x83f3dc00+0x228 83f3de28 83f5de38 00000000 83e5dfa8 00000000 83f3de38 00000000 00000000 83f7d8c0 00000000 83f3de48 83f7d560 00000000 83f5d84c 00000000 kd> dd 83f5de38 83f5de38 8706b1e8 877cb660 00000000 00000000 83f5de48 00000000 00000000 00040107 00000000 83f5de58 865d0690 865d0690 c0403188 0007ff7e kd> dt _LDR_DATA_TABLE_ENTRY 8706b1e8 nt!_LDR_DATA_TABLE_ENTRY +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x8713b4e0 - 0x83f5de38 ] +0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0x0 - 0x0 ] +0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0x0 - 0x0 ] +0x018 DllBase : 0x77ce0000 Void +0x01c EntryPoint : (null) +0x020 SizeOfImage : 0x13c000 +0x024 FullDllName : _UNICODE_STRING "\Windows\System32\ntdll.dll" +0x02c BaseDllName : _UNICODE_STRING "" +0x034 Flags : 0 +0x038 LoadCount : 1 +0x03a TlsIndex : 0 +0x03c HashLinks : _LIST_ENTRY [ 0x0 - 0x1490d9 ] +0x03c SectionPointer : (null) +0x040 CheckSum : 0x1490d9 +0x044 TimeDateStamp : 0 +0x044 LoadedImports : (null) +0x048 EntryPointActivationContext : (null) +0x04c PatchInformation : (null) +0x050 ForwarderLinks : _LIST_ENTRY [ 0x0 - 0x0 ] +0x058 ServiceTagLinks : _LIST_ENTRY [ 0x0 - 0x57005c ] +0x060 StaticLinks : _LIST_ENTRY [ 0x6e0069 - 0x6f0064 ] +0x068 ContextInformation : 0x00730077 Void +0x06c OriginalBase : 0x53005c +0x070 LoadTime : _LARGE_INTEGER 0x650074`00730079 */ DbgPrint("KdVersionBlock address: %#x",KdVersionBlock); DbgPrint("MmLoadedUserImageList address: %#x",MmLoadedUserImageList); ModuleEntry=(PLDR_DATA_TABLE_ENTRY)MmLoadedUserImageList->InLoadOrderLinks.Flink; //第一模块 NtdllBase=ModuleEntry->DllBase; //ntdll基地址 DbgPrint("ntdll base address: %#x",NtdllBase); pIDH=(PIMAGE_DOS_HEADER)NtdllBase; pINH=(PIMAGE_NT_HEADERS)((PUCHAR)NtdllBase+pIDH->e_lfanew); pIED=(PIMAGE_EXPORT_DIRECTORY)((PUCHAR)NtdllBase+pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); Functions=(PULONG)((PUCHAR)NtdllBase+pIED->AddressOfFunctions); Names=(PULONG)((PUCHAR)NtdllBase+pIED->AddressOfNames); Ordinals=(PUSHORT)((PUCHAR)NtdllBase+pIED->AddressOfNameOrdinals); //搜索LdrLoadDll for(i=0;i<pIED->NumberOfNames;i++) { if(!strcmp((char*)NtdllBase+Names[i],"LdrLoadDll")) { LdrLoadDll=(PLDR_LOAD_DLL)((PUCHAR)NtdllBase+Functions[Ordinals[i]]); break; } } DbgPrint("LdrLoadDll address: %#x",LdrLoadDll); Process=PsGetCurrentProcess(); Thread=PsGetCurrentThread(); ptr=(PULONG)Thread; //确定ApcState在EThread中的偏移 for(i=0;i<512;i++) { if(ptr[i]==(ULONG)Process) { ApcState=CONTAINING_RECORD(&ptr[i],KAPC_STATE,Process); ApcStateOffset=(ULONG)ApcState-(ULONG)Thread; break; } } DbgPrint("ApcState offset: %#x",ApcStateOffset); DbgPrint("DLL injection driver loaded."); return STATUS_SUCCESS; }
VOID NTAPI KeSetSystemTime(IN PLARGE_INTEGER NewTime, OUT PLARGE_INTEGER OldTime, IN BOOLEAN FixInterruptTime, IN PLARGE_INTEGER HalTime OPTIONAL) { TIME_FIELDS TimeFields; KIRQL OldIrql, OldIrql2; LARGE_INTEGER DeltaTime; PLIST_ENTRY ListHead, NextEntry; PKTIMER Timer; PKSPIN_LOCK_QUEUE LockQueue; LIST_ENTRY TempList, TempList2; ULONG Hand, i; /* Sanity checks */ ASSERT((NewTime->HighPart & 0xF0000000) == 0); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); /* Check if this is for the HAL */ if (HalTime) RtlTimeToTimeFields(HalTime, &TimeFields); /* Set affinity to this CPU, lock the dispatcher, and raise IRQL */ KeSetSystemAffinityThread(1); OldIrql = KiAcquireDispatcherLock(); KeRaiseIrql(HIGH_LEVEL, &OldIrql2); /* Query the system time now */ KeQuerySystemTime(OldTime); /* Set the new system time (ordering of these operations is critical) */ SharedUserData->SystemTime.High2Time = NewTime->HighPart; SharedUserData->SystemTime.LowPart = NewTime->LowPart; SharedUserData->SystemTime.High1Time = NewTime->HighPart; /* Check if this was for the HAL and set the RTC time */ if (HalTime) ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields); /* Calculate the difference between the new and the old time */ DeltaTime.QuadPart = NewTime->QuadPart - OldTime->QuadPart; /* Update system boot time */ KeBootTime.QuadPart += DeltaTime.QuadPart; KeBootTimeBias = KeBootTimeBias + DeltaTime.QuadPart; /* Lower IRQL back */ KeLowerIrql(OldIrql2); /* Check if we need to adjust interrupt time */ if (FixInterruptTime) ASSERT(FALSE); /* Setup a temporary list of absolute timers */ InitializeListHead(&TempList); /* Loop current timers */ for (i = 0; i < TIMER_TABLE_SIZE; i++) { /* Loop the entries in this table and lock the timers */ ListHead = &KiTimerTableListHead[i].Entry; LockQueue = KiAcquireTimerLock(i); NextEntry = ListHead->Flink; while (NextEntry != ListHead) { /* Get the timer */ Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry); NextEntry = NextEntry->Flink; /* Is it absolute? */ if (Timer->Header.Absolute) { /* Remove it from the timer list */ KiRemoveEntryTimer(Timer); /* Insert it into our temporary list */ InsertTailList(&TempList, &Timer->TimerListEntry); } } /* Release the lock */ KiReleaseTimerLock(LockQueue); } /* Setup a temporary list of expired timers */ InitializeListHead(&TempList2); /* Loop absolute timers */ while (TempList.Flink != &TempList) { /* Get the timer */ Timer = CONTAINING_RECORD(TempList.Flink, KTIMER, TimerListEntry); RemoveEntryList(&Timer->TimerListEntry); /* Update the due time and handle */ Timer->DueTime.QuadPart -= DeltaTime.QuadPart; Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart); Timer->Header.Hand = (UCHAR)Hand; /* Lock the timer and re-insert it */ LockQueue = KiAcquireTimerLock(Hand); if (KiInsertTimerTable(Timer, Hand)) { /* Remove it from the timer list */ KiRemoveEntryTimer(Timer); /* Insert it into our temporary list */ InsertTailList(&TempList2, &Timer->TimerListEntry); } /* Release the lock */ KiReleaseTimerLock(LockQueue); } /* Process expired timers. This releases the dispatcher lock. */ KiTimerListExpire(&TempList2, OldIrql); /* Revert affinity */ KeRevertToUserAffinityThread(); }
VOID KeSetSystemTime ( IN PLARGE_INTEGER NewTime, OUT PLARGE_INTEGER OldTime, IN BOOLEAN AdjustInterruptTime, IN PLARGE_INTEGER HalTimeToSet OPTIONAL ) /*++ Routine Description: This function sets the system time to the specified value and updates timer queue entries to reflect the difference between the old system time and the new system time. Arguments: NewTime - Supplies a pointer to a variable that specifies the new system time. OldTime - Supplies a pointer to a variable that will receive the previous system time. AdjustInterruptTime - If TRUE the amount of time being adjusted is also applied to InterruptTime and TickCount. HalTimeToSet - Supplies an optional time that if specified is to be used to set the time in the realtime clock. Return Value: None. --*/ { LIST_ENTRY AbsoluteListHead; LIST_ENTRY ExpiredListHead; ULONG Hand; ULONG Index; PLIST_ENTRY ListHead; PKSPIN_LOCK_QUEUE LockQueue; PLIST_ENTRY NextEntry; KIRQL OldIrql1; KIRQL OldIrql2; LARGE_INTEGER TimeDelta; TIME_FIELDS TimeFields; PKTIMER Timer; ASSERT((NewTime->HighPart & 0xf0000000) == 0); ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); // // If a realtime clock value is specified, then convert the time value // to time fields. // if (ARGUMENT_PRESENT(HalTimeToSet)) { RtlTimeToTimeFields(HalTimeToSet, &TimeFields); } // // Set affinity to the processor that keeps the system time, raise IRQL // to dispatcher level and lock the dispatcher database, then raise IRQL // to HIGH_LEVEL to synchronize with the clock interrupt routine. // KeSetSystemAffinityThread((KAFFINITY)1); KiLockDispatcherDatabase(&OldIrql1); KeRaiseIrql(HIGH_LEVEL, &OldIrql2); // // Save the previous system time, set the new system time, and set // the realtime clock, if a time value is specified. // KiQuerySystemTime(OldTime); #if defined(_AMD64_) SharedUserData->SystemTime.High2Time = NewTime->HighPart; *((volatile ULONG64 *)&SharedUserData->SystemTime) = NewTime->QuadPart; #else SharedUserData->SystemTime.High2Time = NewTime->HighPart; SharedUserData->SystemTime.LowPart = NewTime->LowPart; SharedUserData->SystemTime.High1Time = NewTime->HighPart; #endif if (ARGUMENT_PRESENT(HalTimeToSet)) { ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields); } // // Compute the difference between the previous system time and the new // system time. // TimeDelta.QuadPart = NewTime->QuadPart - OldTime->QuadPart; // // Update the boot time to reflect the delta. This keeps time based // on boot time constant // KeBootTime.QuadPart = KeBootTime.QuadPart + TimeDelta.QuadPart; // // Track the overall bias applied to the boot time. // KeBootTimeBias = KeBootTimeBias + TimeDelta.QuadPart; // // Lower IRQL to dispatch level and if needed adjust the physical // system interrupt time. // KeLowerIrql(OldIrql2); if (AdjustInterruptTime != FALSE) { AdjustInterruptTime = KeAdjustInterruptTime(TimeDelta.QuadPart); } // // If the physical interrupt time of the system was not adjusted, then // recompute any absolute timers in the system for the new system time. // if (AdjustInterruptTime == FALSE) { // // Acquire the timer table lock, remove all absolute timers from the // timer queue so their due time can be recomputed, and release the // timer table lock. // InitializeListHead(&AbsoluteListHead); for (Index = 0; Index < TIMER_TABLE_SIZE; Index += 1) { ListHead = &KiTimerTableListHead[Index].Entry; LockQueue = KiAcquireTimerTableLock(Index); NextEntry = ListHead->Flink; while (NextEntry != ListHead) { Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry); NextEntry = NextEntry->Flink; if (Timer->Header.Absolute != FALSE) { KiRemoveEntryTimer(Timer); InsertTailList(&AbsoluteListHead, &Timer->TimerListEntry); } } KiReleaseTimerTableLock(LockQueue); } // // Recompute the due time and reinsert all absolute timers in the timer // tree. If a timer has already expired, then insert the timer in the // expired timer list. // InitializeListHead(&ExpiredListHead); while (AbsoluteListHead.Flink != &AbsoluteListHead) { Timer = CONTAINING_RECORD(AbsoluteListHead.Flink, KTIMER, TimerListEntry); RemoveEntryList(&Timer->TimerListEntry); Timer->DueTime.QuadPart -= TimeDelta.QuadPart; Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart); Timer->Header.Hand = (UCHAR)Hand; LockQueue = KiAcquireTimerTableLock(Hand); if (KiInsertTimerTable(Timer, Hand) == TRUE) { KiRemoveEntryTimer(Timer); InsertTailList(&ExpiredListHead, &Timer->TimerListEntry); } KiReleaseTimerTableLock(LockQueue); } // // If any of the attempts to reinsert a timer failed, then timers have // already expired and must be processed. // // N.B. The following function returns with the dispatcher database // unlocked. // KiTimerListExpire(&ExpiredListHead, OldIrql1); } else { KiUnlockDispatcherDatabase(OldIrql1); } // // Set affinity back to its original value. // KeRevertToUserAffinityThread(); return; }
BOOL GetNtosInformation(WCHAR** pKernelFullPath,ULONG* ulKernelBase, ULONG* ulKernelSize) { ULONG ulBase = 0; ULONG ulSize = 0; ULONG ulBufferLength = 0; ULONG ulUnicodeKernelFullPath = 0; WCHAR wszNtosFullPath[260]; KeSetSystemAffinityThread(1); //使当前线程运行在第一个处理器上 __asm { push eax push ebx mov eax, fs:[0x34] //+0x34得到KdVersionBlock的地址 add eax,0x18 //得到指向PsLoadedModuleList的地址 mov eax,[eax] //得到PsLoadedModuleList的地址 mov ebx,[eax] //取出PsLoadedModuleList里面的内容, 即KLDR_DATA_TABLE_ENTRY结构 mov eax,[ebx+0x18] //取出DllBase, 即ntoskrnl.exe的基地址 mov ulBase, eax mov eax,[ebx+0x20] //+20h SizeOfImage mov ulSize,eax mov eax,ebx add eax,0x24 //+24h 是ntos在3环下的UNICODE_STRING全路径 mov ulUnicodeKernelFullPath,eax pop ebx pop eax } KeRevertToUserAffinityThread();//恢复线程运行的处理器 //PsLoadedModuleList的第一个就是ntos //nt!_LDR_DATA_TABLE_ENTRY //+0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x82195338 - 0x8055e720 ] //+0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0x0 - 0x0 ] //+0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0x0 - 0x0 ] //+0x018 DllBase : 0x804d8000 Void //+0x01c EntryPoint : 0x806a3c08 Void //+0x020 SizeOfImage : 0x20e000 //+0x024 FullDllName : _UNICODE_STRING "\WINDOWS\system32\ntkrnlpa.exe" //+0x02c BaseDllName : _UNICODE_STRING "ntoskrnl.exe" //+0x034 Flags : 0xc004000 //+0x038 LoadCount : 1 //+0x03a TlsIndex : 0 //+0x03c HashLinks : _LIST_ENTRY [ 0x0 - 0x1f107a ] //+0x03c SectionPointer : (null) //+0x040 CheckSum : 0x1f107a //+0x044 TimeDateStamp : 0 //+0x044 LoadedImports : (null) //+0x048 EntryPointActivationContext : (null) //+0x04c PatchInformation : 0x0074006e Void RtlZeroMemory(wszNtosFullPath,260*2); //UNICODE_STRING->Length 不包括NULL字符 if (!MmIsAddressValidEx((PUNICODE_STRING)ulUnicodeKernelFullPath)) { return FALSE; } ulBufferLength = (((PUNICODE_STRING)ulUnicodeKernelFullPath)->Length + 1) * 2; if (SafeCopyMemory((PVOID)((PUNICODE_STRING)ulUnicodeKernelFullPath)->Buffer, wszNtosFullPath, ulBufferLength) != STATUS_SUCCESS) { *ulKernelBase = 0; *ulKernelSize = 0; return FALSE; } //拷贝成功的话,就进行对比 *pKernelFullPath = (WCHAR*)ExAllocatePool(NonPagedPool,260*2); if (!*pKernelFullPath) { *ulKernelBase = 0; *ulKernelSize = 0; return FALSE; } wcscat(*pKernelFullPath,L"\\SystemRoot\\system32\\"); if (wcsstr((const wchar_t*)wszNtosFullPath,L"ntoskrnl.exe") != NULL) { wcscat(*pKernelFullPath,L"ntoskrnl.exe"); } else if (wcsstr((const wchar_t*)wszNtosFullPath,L"ntkrnlpa.exe") != NULL) { wcscat(*pKernelFullPath,L"ntkrnlpa.exe"); } else if (wcsstr((const wchar_t*)wszNtosFullPath,L"ntkrnlmp.exe") != NULL) { wcscat(*pKernelFullPath,L"ntkrnlmp.exe"); } else if (wcsstr((const wchar_t*)wszNtosFullPath,L"ntkrpamp.exe") != NULL) { wcscat(*pKernelFullPath,L"ntkrpamp.exe"); } //else if (wcsstr((const wchar_t*)wszNtosFullPath,L"ntkrnlup.exe") != NULL) //{ // wcscat(*pKernelFullPath,L"ntkrnlup.exe"); //} else//失败了 { *ulKernelBase = 0; *ulKernelSize = 0; ExFreePool(*pKernelFullPath); return FALSE; } *ulKernelBase = ulBase; *ulKernelSize = ulSize; return TRUE; }
/* * @implemented */ BOOLEAN NTAPI KeDisconnectInterrupt(IN PKINTERRUPT Interrupt) { KIRQL OldIrql, Irql; ULONG Vector; DISPATCH_INFO Dispatch; PKINTERRUPT NextInterrupt; BOOLEAN State; /* Set the affinity */ KeSetSystemAffinityThread(1 << Interrupt->Number); /* Lock the dispatcher */ OldIrql = KiAcquireDispatcherLock(); /* Check if it's actually connected */ State = Interrupt->Connected; if (State) { /* Get the vector and IRQL */ Irql = Interrupt->Irql; Vector = Interrupt->Vector; /* Get vector dispatch data */ KiGetVectorDispatch(Vector, &Dispatch); /* Check if it was chained */ if (Dispatch.Type == ChainConnect) { /* Check if the top-level interrupt is being removed */ ASSERT(Irql <= SYNCH_LEVEL); if (Interrupt == Dispatch.Interrupt) { /* Get the next one */ Dispatch.Interrupt = CONTAINING_RECORD(Dispatch.Interrupt-> InterruptListEntry.Flink, KINTERRUPT, InterruptListEntry); /* Reconnect it */ KiConnectVectorToInterrupt(Dispatch.Interrupt, ChainConnect); } /* Remove it */ RemoveEntryList(&Interrupt->InterruptListEntry); /* Get the next one */ NextInterrupt = CONTAINING_RECORD(Dispatch.Interrupt-> InterruptListEntry.Flink, KINTERRUPT, InterruptListEntry); /* Check if this is the only one left */ if (Dispatch.Interrupt == NextInterrupt) { /* Connect it in non-chained mode */ KiConnectVectorToInterrupt(Dispatch.Interrupt, NormalConnect); } } else { /* Only one left, disable and remove it */ HalDisableSystemInterrupt(Interrupt->Vector, Irql); KiConnectVectorToInterrupt(Interrupt, NoConnect); } /* Disconnect it */ Interrupt->Connected = FALSE; } /* Unlock the dispatcher and revert affinity */ KiReleaseDispatcherLock(OldIrql); KeRevertToUserAffinityThread(); /* Return to caller */ return State; }
NTSTATUS DriverDeviceControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PIO_STACK_LOCATION IrpSp; ULONG IOControlCode = 0; ULONG dwBytesWritten = 0; PCHAR pInBuf = NULL, pOutBuf = NULL; unsigned int _cpu_thread_id = 0; unsigned int new_cpu_thread_id = 0; ULONG _num_active_cpus = 0; KAFFINITY _kaffinity = 0; UINT32 core_id = 0; // // Get the current IRP stack location of this request // IrpSp = IoGetCurrentIrpStackLocation (Irp); IOControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode; DbgPrint( "[chipsec] >>>>>>>>>> IOCTL >>>>>>>>>>\n" ); DbgPrint( "[chipsec] DeviceObject = 0x%x IOCTL = 0x%x\n", DeviceObject, IOControlCode ); DbgPrint( "[chipsec] InputBufferLength = 0x%x, OutputBufferLength = 0x%x\n", IrpSp->Parameters.DeviceIoControl.InputBufferLength, IrpSp->Parameters.DeviceIoControl.OutputBufferLength ); // // CPU thread ID // _num_active_cpus = KeQueryActiveProcessorCount( NULL ); _kaffinity = KeQueryActiveProcessors(); _cpu_thread_id = KeGetCurrentProcessorNumber(); DbgPrint( "[chipsec] Active CPU threads : %d (KeNumberProcessors = %d)\n", _num_active_cpus, KeNumberProcessors ); DbgPrint( "[chipsec] Active CPU mask (KAFFINITY): 0x%08X\n", _kaffinity ); DbgPrint( "[chipsec] Current CPU thread : %d\n", _cpu_thread_id ); // // Switch on the IOCTL code that is being requested by the user. If the // operation is a valid one for this device do the needful. // Irp -> IoStatus.Information = 0; switch( IOControlCode ) { case READ_PCI_CFG_REGISTER: { DWORD val; BYTE size = 0; WORD bdf[4]; BYTE bus = 0, dev = 0, fun = 0, off = 0; DbgPrint( "[chipsec] > READ_PCI_CFG_REGISTER\n" ); RtlCopyBytes( bdf,Irp->AssociatedIrp.SystemBuffer, 4*sizeof(WORD) ); RtlCopyBytes( &size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 4*sizeof(WORD), sizeof(BYTE) ); bus = (UINT8)bdf[0]; dev = (UINT8)bdf[1]; fun = (UINT8)bdf[2]; off = (UINT8)bdf[3]; if( 1 != size && 2 != size && 4 != size) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } val = ReadPCICfg( bus, dev, fun, off, size ); IrpSp->Parameters.Read.Length = size; RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (VOID*)&val, size ); DbgPrint( "[chipsec][READ_PCI_CFG_REGISTER] B/D/F: %#04x/%#04x/%#04x, OFFSET: %#04x, value = %#010x (size = 0x%x)\n", bus, dev, fun, off, val, size ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case WRITE_PCI_CFG_REGISTER: { DWORD val = 0; WORD bdf[6]; BYTE bus = 0, dev = 0, fun = 0, off = 0; BYTE size = 0; DbgPrint( "[chipsec] > WRITE_PCI_CFG_REGISTER\n" ); RtlCopyBytes( bdf, Irp->AssociatedIrp.SystemBuffer, 6 * sizeof(WORD) ); bus = (UINT8)bdf[0]; dev = (UINT8)bdf[1]; fun = (UINT8)bdf[2]; off = (UINT8)bdf[3]; RtlCopyBytes( &size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 6*sizeof(WORD), sizeof(BYTE) ); val = ((DWORD)bdf[5] << 16) | bdf[4]; DbgPrint( "[chipsec][WRITE_PCI_CFG_REGISTER] B/D/F: %#02x/%#02x/%#02x, OFFSET: %#02x, value = %#010x (size = %#02x)\n", bus, dev, fun, off, val, size ); WritePCICfg( bus, dev, fun, off, size, val ); Status = STATUS_SUCCESS; break; } case IOCTL_READ_PHYSMEM: { UINT32 len = 0; PVOID virt_addr; PHYSICAL_ADDRESS phys_addr = { 0x0, 0x0 }; DbgPrint( "[chipsec] > IOCTL_READ_PHYSMEM\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength < 3*sizeof(UINT32)) { DbgPrint( "[chipsec][IOCTL_READ_PHYSMEM] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; phys_addr.HighPart = ((UINT32*)pInBuf)[0]; phys_addr.LowPart = ((UINT32*)pInBuf)[1]; len = ((UINT32*)pInBuf)[2]; if( !len ) len = 4; if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < len ) { DbgPrint( "[chipsec][IOCTL_READ_PHYSMEM] ERROR: STATUS_BUFFER_TOO_SMALL\n" ); Status = STATUS_BUFFER_TOO_SMALL; break; } __try { Status = _read_phys_mem( phys_addr, len, pOutBuf ); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_READ_PHYSMEM] ERROR: exception code 0x%X\n", Status ); break; } if( NT_SUCCESS(Status) ) { DbgPrint( "[chipsec][IOCTL_READ_PHYSMEM] Contents:\n" ); _dump_buffer( (unsigned char *)pOutBuf, min(len,0x100) ); dwBytesWritten = len; } break; } case IOCTL_WRITE_PHYSMEM: { UINT32 len = 0; PVOID virt_addr = 0; PHYSICAL_ADDRESS phys_addr = { 0x0, 0x0 }; DbgPrint( "[chipsec] > IOCTL_WRITE_PHYSMEM\n" ); if( Irp->AssociatedIrp.SystemBuffer ) { pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < 3*sizeof(UINT32) ) { DbgPrint( "[chipsec][IOCTL_WRITE_PHYSMEM] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } phys_addr.HighPart = ((UINT32*)pInBuf)[0]; phys_addr.LowPart = ((UINT32*)pInBuf)[1]; len = ((UINT32*)pInBuf)[2]; ((UINT32*)pInBuf) += 3; if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < len + 3*sizeof(UINT32) ) { DbgPrint( "[chipsec][IOCTL_WRITE_PHYSMEM] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } DbgPrint( "[chipsec][IOCTL_WRITE_PHYSMEM] Writing contents:\n" ); _dump_buffer( (unsigned char *)pInBuf, min(len,0x100) ); __try { Status = _write_phys_mem( phys_addr, len, pInBuf ); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_WRITE_PHYSMEM] ERROR: exception code 0x%X\n", Status ); break; } break; } } case IOCTL_ALLOC_PHYSMEM: { SIZE_T NumberOfBytes = 0; PVOID va = 0; PHYSICAL_ADDRESS HighestAcceptableAddress = { 0xFFFFFFFF, 0xFFFFFFFF }; DbgPrint( "[chipsec] > IOCTL_ALLOC_PHYSMEM\n" ); pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf || IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UINT64) + sizeof(UINT32)) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &HighestAcceptableAddress.QuadPart, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(UINT64) ); RtlCopyBytes( &NumberOfBytes, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(UINT64), sizeof(UINT32) ); DbgPrint( "[chipsec] Allocating: NumberOfBytes = 0x%X, PhysAddr = 0x%I64x", NumberOfBytes, HighestAcceptableAddress.QuadPart ); va = MmAllocateContiguousMemory( NumberOfBytes, HighestAcceptableAddress ); if( !va ) { DbgPrint( "[chipsec] ERROR: STATUS_UNSUCCESSFUL - could not allocate memory\n" ); Status = STATUS_UNSUCCESSFUL; } else if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < 2*sizeof(UINT64) ) { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL - should be at least 2*UINT64\n" ); Status = STATUS_BUFFER_TOO_SMALL; } else { PHYSICAL_ADDRESS pa = MmGetPhysicalAddress( va ); DbgPrint( "[chipsec] Allocated Buffer: VirtAddr = 0x%I64x, PhysAddr = 0x%I64x\n", (UINT64)va, pa.QuadPart ); ((UINT64*)pOutBuf)[0] = (UINT64)va; ((UINT64*)pOutBuf)[1] = pa.QuadPart; IrpSp->Parameters.Read.Length = 2*sizeof(UINT64); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; } break; } case IOCTL_FREE_PHYSMEM: { UINT64 va = 0x0; pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; DbgPrint( "[chipsec] > IOCTL_FREE_PHYSMEM\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(UINT64)) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &va, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(UINT64) ); DbgPrint( "[chipsec][IOCTL_FREE_PHYSMEM] Virtual address of the memory being freed: 0x%I64X\n", va ); MmFreeContiguousMemory( (PVOID)va ); IrpSp->Parameters.Read.Length = 0; dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case IOCTL_GET_PHYSADDR: { UINT64 va = 0x0; PHYSICAL_ADDRESS pa = { 0x0, 0x0 }; pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; DbgPrint( "[chipsec] > IOCTL_GET_PHYSADDR\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(UINT64)) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UINT64)) { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL\n" ); Status = STATUS_BUFFER_TOO_SMALL; break; } RtlCopyBytes( &va, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(UINT64) ); pa = MmGetPhysicalAddress( (PVOID)va ); DbgPrint( "[chipsec][IOCTL_GET_PHYSADDR] Traslated virtual address 0x%I64X to physical: 0x%I64X\n", va, pa.QuadPart, pa.LowPart); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)&pa, sizeof(UINT64) ); IrpSp->Parameters.Read.Length = sizeof(UINT64); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case IOCTL_MAP_IO_SPACE: { PVOID va = 0x0; PHYSICAL_ADDRESS pa = { 0x0, 0x0 }; unsigned int len = 0; unsigned int cache_type = 0; pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; DbgPrint( "[chipsec] > IOCTL_MAP_IO_SPACE\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength != 3*8) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UINT64)) { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL\n" ); Status = STATUS_BUFFER_TOO_SMALL; break; } RtlCopyBytes( &pa, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 0x00, 0x8 ); RtlCopyBytes( &len, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 0x08, 0x4 ); RtlCopyBytes( &cache_type, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 0x10, 0x4 ); va = MmMapIoSpace(pa, len, cache_type); DbgPrint( "[chipsec][IOCTL_MAP_IO_SPACE] Mapping physical address 0x%016llX to virtual 0x%016llX\n", pa, va); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)&va, sizeof(va) ); IrpSp->Parameters.Read.Length = sizeof(va); dwBytesWritten = sizeof(va); Status = STATUS_SUCCESS; break; } case IOCTL_LOAD_UCODE_PATCH: { PVOID ucode_buf = NULL; UINT64 ucode_start = 0; UINT16 ucode_size = 0; UINT32 _eax = 0, _edx = 0; int CPUInfo[4] = {-1}; DbgPrint("[chipsec] > IOCTL_LOAD_UCODE_UPDATE\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(BYTE) + sizeof(UINT16) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER (input buffer size < 3)\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &new_cpu_thread_id, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(BYTE) ); if( new_cpu_thread_id >= _num_active_cpus ) new_cpu_thread_id = 0; KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] Changed CPU thread to %d\n", KeGetCurrentProcessorNumber() ); RtlCopyBytes( &ucode_size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE), sizeof(UINT16) ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] Ucode update size = 0x%X\n", ucode_size ); if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < ucode_size + sizeof(BYTE) + sizeof(UINT16) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER (input buffer size < ucode_size + 3)\n" ); Status = STATUS_INVALID_PARAMETER; break; } ucode_buf = ExAllocatePoolWithTag( NonPagedPool, ucode_size, 0x3184 ); if( !ucode_buf ) { DbgPrint( "[chipsec] ERROR: couldn't allocate pool for ucode binary\n" ); break; } RtlCopyBytes( ucode_buf, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE) + sizeof(UINT16), ucode_size ); ucode_start = (UINT64)ucode_buf; DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] ucode update address = 0x%p (eax = 0x%08X, edx = 0x%08X)\n", ucode_start, (UINT32)(ucode_start & 0xFFFFFFFF), (UINT32)((ucode_start >> 32) & 0xFFFFFFFF) ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] ucode update contents:\n" ); _dump_buffer( (unsigned char *)ucode_buf, min(ucode_size,0x100) ); // -- // -- trigger CPU ucode patch update // -- pInBuf points to the beginning of ucode update binary // -- _wrmsr( MSR_IA32_BIOS_UPDT_TRIG, (UINT32)((ucode_start >> 32) & 0xFFFFFFFF), (UINT32)(ucode_start & 0xFFFFFFFF) ); ExFreePoolWithTag( ucode_buf, 0x3184 ); // -- // -- check if patch was loaded // -- // -- need to clear IA32_BIOS_SIGN_ID MSR first // -- CPUID will deposit an update ID value in 64-bit MSR at address MSR_IA32_BIOS_SIGN_ID // -- read IA32_BIOS_SIGN_ID MSR to check patch ID != 0 // -- DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] checking ucode update was loaded..\n" ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] clear IA32_BIOS_SIGN_ID, CPUID EAX=1, read back IA32_BIOS_SIGN_ID\n" ); _wrmsr( MSR_IA32_BIOS_SIGN_ID, 0, 0 ); __cpuid(CPUInfo, 1); _rdmsr( MSR_IA32_BIOS_SIGN_ID, &_eax, &_edx ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] RDMSR( IA32_BIOS_SIGN_ID=0x8b ) = 0x%08x%08x\n", _edx, _eax ); if( 0 != _edx ) DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] Microcode update loaded (ID != 0)\n" ); else DbgPrint( "[chipsec] ERROR: Microcode update failed\n" ); Status = STATUS_SUCCESS; break; } case IOCTL_WRMSR: { UINT32 msrData[3]; UINT32 _eax = 0, _edx = 0; unsigned int _msr_addr; DbgPrint("[chipsec] > IOCTL_WRMSR\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf ) { DbgPrint( "[chipsec][IOCTL_WRMSR] ERROR: NO data provided\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(BYTE) + 3*sizeof(UINT32) ) { DbgPrint( "[chipsec][IOCTL_WRMSR] ERROR: STATUS_INVALID_PARAMETER (input buffer size < sizeof(BYTE) + 3*sizeof(UINT32))\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &new_cpu_thread_id, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(BYTE) ); if( new_cpu_thread_id >= _num_active_cpus ) new_cpu_thread_id = 0; KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); DbgPrint( "[chipsec][IOCTL_WRMSR] Changed CPU thread to %d\n", KeGetCurrentProcessorNumber() ); RtlCopyBytes( msrData, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE), 3 * sizeof(UINT32) ); _msr_addr = msrData[0]; _eax = msrData[1]; _edx = msrData[2]; DbgPrint( "[chipsec][IOCTL_WRMSR] WRMSR( 0x%x ) <-- 0x%08x%08x\n", _msr_addr, _edx, _eax ); // -- // -- write MSR // -- __try { _wrmsr( _msr_addr, _edx, _eax ); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_WRMSR] ERROR: exception code 0x%X\n", Status ); break; } // -- // -- read MSR to check if it was written // -- // _rdmsr( _msr_addr, &_eax, &_edx ); // DbgPrint( "[chipsec][IOCTL_WRMSR] RDMSR( 0x%x ) --> 0x%08x%08x\n", _msr_addr, _edx, _eax ); Status = STATUS_SUCCESS; break; } case IOCTL_RDMSR: { UINT32 msrData[1]; UINT32 _eax = 0; UINT32 _edx = 0; UINT32 _msr_addr = 0; DbgPrint("[chipsec] > IOCTL_RDMSR\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf ) { DbgPrint( "[chipsec] ERROR: No input provided\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(BYTE) + sizeof(UINT32) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER - input buffer size < sizeof(BYTE) + sizeof(UINT32)\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &new_cpu_thread_id, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(BYTE) ); if( new_cpu_thread_id >= _num_active_cpus ) new_cpu_thread_id = 0; KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); DbgPrint( "[chipsec][IOCTL_RDMSR] Changed CPU thread to %d\n", KeGetCurrentProcessorNumber() ); RtlCopyBytes( msrData, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE), sizeof(UINT32) ); _msr_addr = msrData[0]; __try { _rdmsr( _msr_addr, &_eax, &_edx ); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_RDMSR] ERROR: exception code 0x%X\n", Status ); break; } DbgPrint( "[chipsec][IOCTL_RDMSR] RDMSR( 0x%x ) --> 0x%08x%08x\n", _msr_addr, _edx, _eax ); if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= 2*sizeof(UINT32) ) { IrpSp->Parameters.Read.Length = 2*sizeof(UINT32); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (VOID*)&_eax, sizeof(UINT32) ); RtlCopyBytes( ((UINT8*)Irp->AssociatedIrp.SystemBuffer) + sizeof(UINT32), (VOID*)&_edx, sizeof(UINT32) ); dwBytesWritten = 2*sizeof(UINT32); Status = STATUS_SUCCESS; } else { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL - should be at least 2 UINT32\n" ); Status = STATUS_BUFFER_TOO_SMALL; } break; } case READ_IO_PORT: { DWORD value; BYTE size = 0; WORD io_port; DbgPrint( "[chipsec] > READ_IO_PORT\n" ); RtlCopyBytes( &io_port, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(WORD) ); RtlCopyBytes( &size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(WORD), sizeof(BYTE) ); if( 1 != size && 2 != size && 4 != size) { DbgPrint( "[chipsec][READ_IO_PORT] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } __try { value = ReadIOPort( io_port, size ); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); DbgPrint( "[chipsec][READ_IO_PORT] ERROR: exception code 0x%X\n", Status ); break; } IrpSp->Parameters.Read.Length = size; RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (VOID*)&value, size ); DbgPrint( "[chipsec][READ_IO_PORT] I/O Port %#04x, value = %#010x (size = %#02x)\n", io_port, value, size ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case WRITE_IO_PORT: { DWORD value = 0; WORD io_port = 0; BYTE size = 0; DbgPrint( "[chipsec] > WRITE_IO_PORT\n" ); RtlCopyBytes( &io_port, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(WORD) ); RtlCopyBytes( &value, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(WORD), sizeof(DWORD) ); RtlCopyBytes( &size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(WORD) + sizeof(DWORD), sizeof(BYTE) ); DbgPrint( "[chipsec][WRITE_IO_PORT] I/O Port %#04x, value = %#010x (size = %#02x)\n", io_port, value, size ); __try { WriteIOPort( value, io_port, size ); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); DbgPrint( "[chipsec][WRITE_IO_PORT] ERROR: exception code 0x%X\n", Status ); break; } Status = STATUS_SUCCESS; break; } case GET_CPU_DESCRIPTOR_TABLE: { BYTE dt_code = 0; DESCRIPTOR_TABLE_RECORD dtr; PDESCRIPTOR_TABLE_RECORD pdtr = &dtr; PHYSICAL_ADDRESS dt_pa; DbgPrint( "[chipsec] > GET_CPU_DESCRIPTOR_TABLE\n" ); RtlCopyBytes( &new_cpu_thread_id, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(BYTE) ); if( new_cpu_thread_id >= _num_active_cpus ) new_cpu_thread_id = 0; KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] Changed CPU thread to %d\n", KeGetCurrentProcessorNumber() ); RtlCopyBytes( &dt_code, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE), sizeof(BYTE) ); DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] Descriptor table: %x\n", dt_code ); switch( dt_code ) { case CPU_DT_CODE_GDTR: { _store_gdtr( (void*)pdtr ); break; } case CPU_DT_CODE_LDTR: { _store_ldtr( (void*)pdtr ); break; } case CPU_DT_CODE_IDTR: default: { _store_idtr( (void*)pdtr ); break; } } DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] Descriptor table register contents:\n" ); _dump_buffer( (unsigned char *)pdtr, sizeof(DESCRIPTOR_TABLE_RECORD) ); DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] IDTR: Limit = 0x%04x, Base = 0x%I64x\n", dtr.limit, dtr.base ); dt_pa = MmGetPhysicalAddress( (PVOID)dtr.base ); DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] Descriptor table PA: 0x%I64X (0x%08X_%08X)\n", dt_pa.QuadPart, dt_pa.HighPart, dt_pa.LowPart ); IrpSp->Parameters.Read.Length = sizeof(DESCRIPTOR_TABLE_RECORD) + sizeof(dt_pa.QuadPart); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)pdtr, sizeof(DESCRIPTOR_TABLE_RECORD) ); RtlCopyBytes( (UINT8*)Irp->AssociatedIrp.SystemBuffer + sizeof(DESCRIPTOR_TABLE_RECORD), (VOID*)&dt_pa.QuadPart, sizeof(dt_pa.QuadPart) ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case IOCTL_SWSMI: { CPU_REG_TYPE gprs[6] = {0}; CPU_REG_TYPE _rax = 0, _rbx = 0, _rcx = 0, _rdx = 0, _rsi = 0, _rdi = 0; unsigned int _smi_code_data = 0; DbgPrint("[chipsec] > IOCTL_SWSMI\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf ) { DbgPrint( "[chipsec] ERROR: NO data provided\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UINT16) + sizeof(gprs) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER (input buffer size < sizeof(UINT16) + sizeof(gprs))\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &_smi_code_data, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(UINT16) ); RtlCopyBytes( gprs, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(UINT16), sizeof(gprs) ); _rax = gprs[ 0 ]; _rbx = gprs[ 1 ]; _rcx = gprs[ 2 ]; _rdx = gprs[ 3 ]; _rsi = gprs[ 4 ]; _rdi = gprs[ 5 ]; DbgPrint( "[chipsec][IOCTL_SWSMI] SW SMI to ports 0x%X-0x%X <- 0x%04X\n", 0xB2, 0xB3, _smi_code_data ); DbgPrint( " RAX = 0x%I64x\n", _rax ); DbgPrint( " RBX = 0x%I64x\n", _rbx ); DbgPrint( " RCX = 0x%I64x\n", _rcx ); DbgPrint( " RDX = 0x%I64x\n", _rdx ); DbgPrint( " RSI = 0x%I64x\n", _rsi ); DbgPrint( " RDI = 0x%I64x\n", _rdi ); // -- // -- send SMI using port 0xB2 // -- __try { _swsmi( _smi_code_data, _rax, _rbx, _rcx, _rdx, _rsi, _rdi ); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); break; } Status = STATUS_SUCCESS; break; } case IOCTL_CPUID: { DWORD CPUInfo[4] = {-1}; DWORD gprs[2] = {0}; DWORD _rax = 0, _rcx = 0; //CPU_REG_TYPE gprs[6]; //CPU_REG_TYPE _rax = 0, _rbx = 0, _rcx = 0, _rdx = 0, _rsi = 0, _rdi = 0; DbgPrint("[chipsec] > IOCTL_CPUID\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf ) { DbgPrint( "[chipsec] ERROR: NO data provided\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(gprs) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER (input buffer size < %d)\n", sizeof(gprs) ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( gprs, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(gprs) ); _rax = gprs[ 0 ]; _rcx = gprs[ 1 ]; DbgPrint( "[chipsec][IOCTL_CPUID] CPUID:\n" ); DbgPrint( " EAX = 0x%08X\n", _rax ); DbgPrint( " ECX = 0x%08X\n", _rcx ); __cpuidex( CPUInfo, _rax, _rcx ); DbgPrint( "[chipsec][IOCTL_CPUID] CPUID returned:\n" ); DbgPrint( " EAX = 0x%08X\n", CPUInfo[0] ); DbgPrint( " EBX = 0x%08X\n", CPUInfo[1] ); DbgPrint( " ECX = 0x%08X\n", CPUInfo[2] ); DbgPrint( " EDX = 0x%08X\n", CPUInfo[3] ); IrpSp->Parameters.Read.Length = sizeof(CPUInfo); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)CPUInfo, sizeof(CPUInfo) ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case IOCTL_WRCR: { UINT64 val64 = 0; CPU_REG_TYPE value = 0; WORD cr_reg = 0; DbgPrint( "[chipsec] > WRITE_CR\n" ); if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < (sizeof(cr_reg) + sizeof(val64) + sizeof(BYTE))) { Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &cr_reg, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(cr_reg) ); RtlCopyBytes( &val64, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(cr_reg), sizeof(val64) ); new_cpu_thread_id = *((BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(cr_reg) + sizeof(val64)); if( new_cpu_thread_id >= _num_active_cpus ) { // new_cpu_thread_id = 0; Status = STATUS_INVALID_PARAMETER; break; } KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); value = (CPU_REG_TYPE)val64; DbgPrint( "[chipsec][WRITE_CR] CR Reg %#04x, value = %#010x \n", cr_reg, value ); switch (cr_reg) { case 0: WriteCR0(value); Status = STATUS_SUCCESS; break; case 2: WriteCR2(value); Status = STATUS_SUCCESS; break; case 3: WriteCR3(value); Status = STATUS_SUCCESS; break; case 4: WriteCR4(value); Status = STATUS_SUCCESS; break; case 8: #if defined(_M_AMD64) WriteCR8(value); Status = STATUS_SUCCESS; break; #endif default: Status = STATUS_INVALID_PARAMETER; break; } if( !NT_SUCCESS(Status) ) { break; } dwBytesWritten = 0; Status = STATUS_SUCCESS; break; } case IOCTL_RDCR: { UINT64 val64 = 0; CPU_REG_TYPE value = 0; WORD cr_reg = 0; DbgPrint( "[chipsec] > READ_CR\n" ); if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < (sizeof(cr_reg)+sizeof(BYTE)) || IrpSp->Parameters.DeviceIoControl.OutputBufferLength < (sizeof(val64)) ) { Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &cr_reg, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(cr_reg) ); new_cpu_thread_id = *((BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(cr_reg)); if( new_cpu_thread_id >= _num_active_cpus ) { // new_cpu_thread_id = 0; Status = STATUS_INVALID_PARAMETER; break; } KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); switch (cr_reg) { case 0: value = ReadCR0(); Status = STATUS_SUCCESS; break; case 2: value = ReadCR2(); Status = STATUS_SUCCESS; break; case 3: value = ReadCR3(); Status = STATUS_SUCCESS; break; case 4: value = ReadCR4(); Status = STATUS_SUCCESS; break; case 8: #if defined(_M_AMD64) value = ReadCR8(); Status = STATUS_SUCCESS; break; #endif default: Status = STATUS_INVALID_PARAMETER; break; } if( !NT_SUCCESS(Status) ) { break; } val64 = value; RtlCopyBytes( (BYTE*)Irp->AssociatedIrp.SystemBuffer, &val64, sizeof(val64) ); dwBytesWritten = sizeof(val64); DbgPrint( "[chipsec][READ_CR] CR Reg %#04x, value = %#010x \n", cr_reg, value ); Status = STATUS_SUCCESS; break; } case IOCTL_HYPERCALL: { CPU_REG_TYPE regs[11] = {0}; CPU_REG_TYPE result = 0; DbgPrint("[chipsec] > IOCTL_HYPERCALL\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(regs)) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(result)) { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL\n" ); Status = STATUS_BUFFER_TOO_SMALL; break; } RtlCopyBytes( regs, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(regs) ); DbgPrint( "[chipsec][IOCTL_HYPERCALL] HYPERCALL:\n" ); #if defined(_M_AMD64) DbgPrint( " RCX = 0x%016llX RDX = 0x%016llX\n", regs[0], regs[1] ); DbgPrint( " R8 = 0x%016llX R9 = 0x%016llX\n", regs[2], regs[3] ); DbgPrint( " R10 = 0x%016llX R11 = 0x%016llX\n", regs[4], regs[5] ); DbgPrint( " RAX = 0x%016llX RBX = 0x%016llX\n", regs[6], regs[7] ); DbgPrint( " RDI = 0x%016llX RSI = 0x%016llX\n", regs[8], regs[9] ); #endif #if defined(_M_IX86) DbgPrint( " EAX = 0x%08X EBX = 0x%08X ECX = 0x%08X\n", regs[6], regs[7], regs[0] ); DbgPrint( " EDX = 0x%08X ESI = 0x%08X EDI = 0x%08X\n", regs[1], regs[8], regs[9] ); #endif DbgPrint( " XMM0-XMM5 buffer VA = 0x%016llX\n", regs[9] ); __try { result = hypercall(regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7], regs[8], regs[9], regs[10], &hypercall_page); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_HYPERCALL] ERROR: exception code 0x%X\n", Status ); break; } DbgPrint( "[chipsec][IOCTL_HYPERCALL] returned: 0x%016llX\n", result); IrpSp->Parameters.Read.Length = sizeof(result); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)&result, sizeof(result) ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } default: DbgPrint( "[chipsec] ERROR: invalid IOCTL\n"); Status = STATUS_NOT_IMPLEMENTED; break; } // -- switch
VOID NTAPI INIT_FUNCTION KiInitMachineDependent(VOID) { ULONG CpuCount; BOOLEAN FbCaching = FALSE; NTSTATUS Status; ULONG ReturnLength; ULONG i, Affinity, Sample = 0; PFX_SAVE_AREA FxSaveArea; ULONG MXCsrMask = 0xFFBF; ULONG Dummy; KI_SAMPLE_MAP Samples[4]; PKI_SAMPLE_MAP CurrentSample = Samples; /* Check for large page support */ if (KeFeatureBits & KF_LARGE_PAGE) { /* FIXME: Support this */ DPRINT("Large Page support detected but not yet taken advantage of\n"); } /* Check for global page support */ if (KeFeatureBits & KF_GLOBAL_PAGE) { /* Do an IPI to enable it on all CPUs */ CpuCount = KeNumberProcessors; KeIpiGenericCall(Ki386EnableGlobalPage, (ULONG_PTR)&CpuCount); } /* Check for PAT and/or MTRR support */ if (KeFeatureBits & (KF_PAT | KF_MTRR)) { /* Query the HAL to make sure we can use it */ Status = HalQuerySystemInformation(HalFrameBufferCachingInformation, sizeof(BOOLEAN), &FbCaching, &ReturnLength); if ((NT_SUCCESS(Status)) && (FbCaching)) { /* We can't, disable it */ KeFeatureBits &= ~(KF_PAT | KF_MTRR); } } /* Check for PAT support and enable it */ if (KeFeatureBits & KF_PAT) KiInitializePAT(); /* Assume no errata for now */ SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = 0; /* Check if we have an NPX */ if (KeI386NpxPresent) { /* Loop every CPU */ i = KeActiveProcessors; for (Affinity = 1; i; Affinity <<= 1) { /* Check if this is part of the set */ if (i & Affinity) { /* Run on this CPU */ i &= ~Affinity; KeSetSystemAffinityThread(Affinity); /* Detect FPU errata */ if (KiIsNpxErrataPresent()) { /* Disable NPX support */ KeI386NpxPresent = FALSE; SharedUserData-> ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = TRUE; break; } } } } /* If there's no NPX, then we're emulating the FPU */ SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_EMULATED] = !KeI386NpxPresent; /* Check if there's no NPX, so that we can disable associated features */ if (!KeI386NpxPresent) { /* Remove NPX-related bits */ KeFeatureBits &= ~(KF_XMMI64 | KF_XMMI | KF_FXSR | KF_MMX); /* Disable kernel flags */ KeI386FxsrPresent = KeI386XMMIPresent = FALSE; /* Disable processor features that might've been set until now */ SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] = SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] = SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] = SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] = 0; } /* Check for CR4 support */ if (KeFeatureBits & KF_CR4) { /* Do an IPI call to enable the Debug Exceptions */ CpuCount = KeNumberProcessors; KeIpiGenericCall(Ki386EnableDE, (ULONG_PTR)&CpuCount); } /* Check if FXSR was found */ if (KeFeatureBits & KF_FXSR) { /* Do an IPI call to enable the FXSR */ CpuCount = KeNumberProcessors; KeIpiGenericCall(Ki386EnableFxsr, (ULONG_PTR)&CpuCount); /* Check if XMM was found too */ if (KeFeatureBits & KF_XMMI) { /* Do an IPI call to enable XMMI exceptions */ CpuCount = KeNumberProcessors; KeIpiGenericCall(Ki386EnableXMMIExceptions, (ULONG_PTR)&CpuCount); /* FIXME: Implement and enable XMM Page Zeroing for Mm */ /* Patch the RtlPrefetchMemoryNonTemporal routine to enable it */ *(PCHAR)RtlPrefetchMemoryNonTemporal = 0x90; } } /* Check for, and enable SYSENTER support */ KiRestoreFastSyscallReturnState(); /* Loop every CPU */ i = KeActiveProcessors; for (Affinity = 1; i; Affinity <<= 1) { /* Check if this is part of the set */ if (i & Affinity) { /* Run on this CPU */ i &= ~Affinity; KeSetSystemAffinityThread(Affinity); /* Reset MHz to 0 for this CPU */ KeGetCurrentPrcb()->MHz = 0; /* Check if we can use RDTSC */ if (KeFeatureBits & KF_RDTSC) { /* Start sampling loop */ for (;;) { /* Do a dummy CPUID to start the sample */ CPUID(0, &Dummy, &Dummy, &Dummy, &Dummy); /* Fill out the starting data */ CurrentSample->PerfStart = KeQueryPerformanceCounter(NULL); CurrentSample->TSCStart = __rdtsc(); CurrentSample->PerfFreq.QuadPart = -50000; /* Sleep for this sample */ KeDelayExecutionThread(KernelMode, FALSE, &CurrentSample->PerfFreq); /* Do another dummy CPUID */ CPUID(0, &Dummy, &Dummy, &Dummy, &Dummy); /* Fill out the ending data */ CurrentSample->PerfEnd = KeQueryPerformanceCounter(&CurrentSample->PerfFreq); CurrentSample->TSCEnd = __rdtsc(); /* Calculate the differences */ CurrentSample->PerfDelta = CurrentSample->PerfEnd.QuadPart - CurrentSample->PerfStart.QuadPart; CurrentSample->TSCDelta = CurrentSample->TSCEnd - CurrentSample->TSCStart; /* Compute CPU Speed */ CurrentSample->MHz = (ULONG)((CurrentSample->TSCDelta * CurrentSample-> PerfFreq.QuadPart + 500000) / (CurrentSample->PerfDelta * 1000000)); /* Check if this isn't the first sample */ if (Sample) { /* Check if we got a good precision within 1MHz */ if ((CurrentSample->MHz == CurrentSample[-1].MHz) || (CurrentSample->MHz == CurrentSample[-1].MHz + 1) || (CurrentSample->MHz == CurrentSample[-1].MHz - 1)) { /* We did, stop sampling */ break; } } /* Move on */ CurrentSample++; Sample++; if (Sample == sizeof(Samples) / sizeof(Samples[0])) { /* Restart */ CurrentSample = Samples; Sample = 0; } } /* Save the CPU Speed */ KeGetCurrentPrcb()->MHz = CurrentSample[-1].MHz; } /* Check if we have MTRR */ if (KeFeatureBits & KF_MTRR) { /* Then manually initialize MTRR for the CPU */ KiInitializeMTRR(i ? FALSE : TRUE); } /* Check if we have AMD MTRR and initialize it for the CPU */ if (KeFeatureBits & KF_AMDK6MTRR) KiAmdK6InitializeMTRR(); /* Check if this is a buggy Pentium and apply the fixup if so */ if (KiI386PentiumLockErrataPresent) KiI386PentiumLockErrataFixup(); /* Check if the CPU supports FXSR */ if (KeFeatureBits & KF_FXSR) { /* Get the current thread NPX state */ FxSaveArea = KiGetThreadNpxArea(KeGetCurrentThread()); /* Clear initial MXCsr mask */ FxSaveArea->U.FxArea.MXCsrMask = 0; /* Save the current NPX State */ Ke386SaveFpuState(FxSaveArea); /* Check if the current mask doesn't match the reserved bits */ if (FxSaveArea->U.FxArea.MXCsrMask != 0) { /* Then use whatever it's holding */ MXCsrMask = FxSaveArea->U.FxArea.MXCsrMask; } /* Check if nobody set the kernel-wide mask */ if (!KiMXCsrMask) { /* Then use the one we calculated above */ KiMXCsrMask = MXCsrMask; } else { /* Was it set to the same value we found now? */ if (KiMXCsrMask != MXCsrMask) { /* No, something is definitely wrong */ KeBugCheckEx(MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_FXSR, KiMXCsrMask, MXCsrMask, 0); } } /* Now set the kernel mask */ KiMXCsrMask &= MXCsrMask; } } } /* Return affinity back to where it was */ KeRevertToUserAffinityThread(); /* NT allows limiting the duration of an ISR with a registry key */ if (KiTimeLimitIsrMicroseconds) { /* FIXME: TODO */ DPRINT1("ISR Time Limit not yet supported\n"); } /* Set CR0 features based on detected CPU */ KiSetCR0Bits(); }