/*++ Routine Description: Clock interrupt handler for processor 0. Arguments: Interrupt ServiceContext TrapFrame Return Value: TRUE --*/ BOOLEAN HalpHandleDecrementerInterrupt( IN PKINTERRUPT Interrupt, IN PVOID ServiceContext, IN PVOID TrapFrame ) { KIRQL OldIrql; static int recurse = FALSE; ULONG CpuId; HASSERT(!MSR(EE)); CpuId = GetCpuId(); // // Raise irql via updating the PCR // OldIrql = PCR->CurrentIrql; PCR->CurrentIrql = CLOCK2_LEVEL; RInterruptMask(CpuId) = (Irql2Mask[CLOCK2_LEVEL] & registeredInts[CpuId]); WaitForRInterruptMask(CpuId); // // Reset DECREMENTER, accounting for interrupt latency. // HalpUpdateDecrementer(HalpClockCount); // // Call the kernel to update system time // KeUpdateSystemTime(TrapFrame,HalpCurrentTimeIncrement); HalpCurrentTimeIncrement = HalpNewTimeIncrement; if (!recurse) { // // In some circumstances the KdPollBreakIn can // take longer than a decrementer interrupt // to complete. This is do to a conflict // between DMA and PIO. For now, just avoid // recursing into the debugger check. // recurse = TRUE; if (KdDebuggerEnabled && KdPollBreakIn()) { HalpEnableInterrupts(); DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); HalpDisableInterrupts(); } recurse = FALSE; } // // Lower Irql to original value and enable interrupts // PCR->CurrentIrql = OldIrql; RInterruptMask(CpuId) = (Irql2Mask[OldIrql] & registeredInts[CpuId]); WaitForRInterruptMask(CpuId); return (TRUE); }
/*++ Routine Description: Clock interrupt handler for processors other than 0. Arguments: Interrupt ServiceContext TrapFrame Return Value: TRUE --*/ BOOLEAN HalpHandleDecrementerInterrupt1( IN PKINTERRUPT Interrupt, IN PVOID ServiceContext, IN PVOID TrapFrame ) { KIRQL OldIrql; ULONG CpuId; HASSERT(!MSR(EE)); CpuId = GetCpuId(); // // Raise irql via updating the PCR // OldIrql = PCR->CurrentIrql; PCR->CurrentIrql = CLOCK2_LEVEL; RInterruptMask(CpuId) = (Irql2Mask[CLOCK2_LEVEL] & registeredInts[CpuId]); WaitForRInterruptMask(CpuId); // // Reset DECREMENTER (no account for latency) // HalpUpdateDecrementer(HalpFullTickClockCount); // // Call the kernel to update run time for this thread and process. // KeUpdateRunTime(TrapFrame); HDBG(DBG_PROC1DBG, { // // Check for the debugger BreakIn only every minute or so. // (decrementer is interms of ms so we multiple by 10,000 // on the order of a minute). // static Count = 0; if (++Count > 10000) { Count = 0; if (KdDebuggerEnabled && KdPollBreakIn()) { HalpEnableInterrupts(); DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); HalpDisableInterrupts(); } } } );
VOID FASTCALL KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame, IN ULONG Increment, IN KIRQL Irql) { PKPRCB Prcb = KeGetCurrentPrcb(); ULARGE_INTEGER CurrentTime, InterruptTime; LONG OldTickOffset; /* Check if this tick is being skipped */ if (Prcb->SkipTick) { /* Handle it next time */ Prcb->SkipTick = FALSE; /* Increase interrupt count and end the interrupt */ Prcb->InterruptCount++; KiEndInterrupt(Irql, TrapFrame); /* Note: non-x86 return back to the caller! */ return; } /* Add the increment time to the shared data */ InterruptTime.QuadPart = *(ULONGLONG*)&SharedUserData->InterruptTime; InterruptTime.QuadPart += Increment; KiWriteSystemTime(&SharedUserData->InterruptTime, InterruptTime); /* Check for timer expiration */ KiCheckForTimerExpiration(Prcb, TrapFrame, InterruptTime); /* Update the tick offset */ OldTickOffset = InterlockedExchangeAdd(&KiTickOffset, -(LONG)Increment); /* If the debugger is enabled, check for break-in request */ if (KdDebuggerEnabled && KdPollBreakIn()) { /* Break-in requested! */ DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); } /* Check for full tick */ if (OldTickOffset <= (LONG)Increment) { /* Update the system time */ CurrentTime.QuadPart = *(ULONGLONG*)&SharedUserData->SystemTime; CurrentTime.QuadPart += KeTimeAdjustment; KiWriteSystemTime(&SharedUserData->SystemTime, CurrentTime); /* Update the tick count */ CurrentTime.QuadPart = (*(ULONGLONG*)&KeTickCount) + 1; KiWriteSystemTime(&KeTickCount, CurrentTime); /* Update it in the shared user data */ KiWriteSystemTime(&SharedUserData->TickCount, CurrentTime); /* Check for expiration with the new tick count as well */ KiCheckForTimerExpiration(Prcb, TrapFrame, InterruptTime); /* Reset the tick offset */ KiTickOffset += KeMaximumIncrement; /* Update processor/thread runtime */ KeUpdateRunTime(TrapFrame, Irql); } else { /* Increase interrupt count only */ Prcb->InterruptCount++; } /* Disable interrupts and end the interrupt */ KiEndInterrupt(Irql, TrapFrame); }
VOID NTAPI KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock) { CCHAR Cpu; PKTHREAD InitialThread; ULONG64 InitialStack; PKIPCR Pcr; /* HACK */ FrLdrDbgPrint = LoaderBlock->u.I386.CommonDataArea; //FrLdrDbgPrint("Hello from KiSystemStartup!!!\n"); /* Save the loader block */ KeLoaderBlock = LoaderBlock; /* Get the current CPU number */ Cpu = KeNumberProcessors++; // FIXME /* LoaderBlock initialization for Cpu 0 */ if (Cpu == 0) { /* Set the initial stack, idle thread and process */ LoaderBlock->KernelStack = (ULONG_PTR)P0BootStack; LoaderBlock->Thread = (ULONG_PTR)&KiInitialThread; LoaderBlock->Process = (ULONG_PTR)&KiInitialProcess.Pcb; LoaderBlock->Prcb = (ULONG_PTR)&KiInitialPcr.Prcb; } /* Get Pcr from loader block */ Pcr = CONTAINING_RECORD(LoaderBlock->Prcb, KIPCR, Prcb); /* Set the PRCB for this Processor */ KiProcessorBlock[Cpu] = &Pcr->Prcb; /* Align stack to 16 bytes */ LoaderBlock->KernelStack &= ~(16 - 1); /* Save the initial thread and stack */ InitialStack = LoaderBlock->KernelStack; // Checkme InitialThread = (PKTHREAD)LoaderBlock->Thread; /* Set us as the current process */ InitialThread->ApcState.Process = (PVOID)LoaderBlock->Process; /* Initialize the PCR */ KiInitializePcr(Pcr, Cpu, InitialThread, (PVOID)KiDoubleFaultStack); /* Initialize the CPU features */ KiInitializeCpu(Pcr); /* Initial setup for the boot CPU */ if (Cpu == 0) { /* Initialize the module list (ntos, hal, kdcom) */ KiInitModuleList(LoaderBlock); /* Setup the TSS descriptors and entries */ KiInitializeTss(Pcr->TssBase, InitialStack); /* Setup the IDT */ KeInitExceptions(); /* Initialize debugging system */ KdInitSystem(0, KeLoaderBlock); /* Check for break-in */ if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); } DPRINT1("Pcr = %p, Gdt = %p, Idt = %p, Tss = %p\n", Pcr, Pcr->GdtBase, Pcr->IdtBase, Pcr->TssBase); /* Acquire lock */ while (InterlockedBitTestAndSet64((PLONG64)&KiFreezeExecutionLock, 0)) { /* Loop until lock is free */ while ((*(volatile KSPIN_LOCK*)&KiFreezeExecutionLock) & 1); } /* Initialize the Processor with HAL */ HalInitializeProcessor(Cpu, KeLoaderBlock); /* Set processor as active */ KeActiveProcessors |= 1ULL << Cpu; /* Release lock */ InterlockedAnd64((PLONG64)&KiFreezeExecutionLock, 0); /* Raise to HIGH_LEVEL */ KfRaiseIrql(HIGH_LEVEL); /* Machine specific kernel initialization */ if (Cpu == 0) KiInitializeKernelMachineDependent(&Pcr->Prcb, LoaderBlock); /* Switch to new kernel stack and start kernel bootstrapping */ KiSwitchToBootStack(InitialStack & ~3); }
VOID NTAPI INIT_FUNCTION KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock) { ULONG Cpu; PKTHREAD InitialThread; ULONG InitialStack; PKGDTENTRY Gdt; PKIDTENTRY Idt; KIDTENTRY NmiEntry, DoubleFaultEntry; PKTSS Tss; PKIPCR Pcr; /* Boot cycles timestamp */ BootCycles = __rdtsc(); /* Save the loader block and get the current CPU */ KeLoaderBlock = LoaderBlock; Cpu = KeNumberProcessors; if (!Cpu) { /* If this is the boot CPU, set FS and the CPU Number*/ Ke386SetFs(KGDT_R0_PCR); __writefsdword(KPCR_PROCESSOR_NUMBER, Cpu); /* Set the initial stack and idle thread as well */ LoaderBlock->KernelStack = (ULONG_PTR)P0BootStack; LoaderBlock->Thread = (ULONG_PTR)&KiInitialThread; } /* Save the initial thread and stack */ InitialStack = LoaderBlock->KernelStack; InitialThread = (PKTHREAD)LoaderBlock->Thread; /* Clean the APC List Head */ InitializeListHead(&InitialThread->ApcState.ApcListHead[KernelMode]); /* Initialize the machine type */ KiInitializeMachineType(); /* Skip initial setup if this isn't the Boot CPU */ if (Cpu) goto AppCpuInit; /* Get GDT, IDT, PCR and TSS pointers */ KiGetMachineBootPointers(&Gdt, &Idt, &Pcr, &Tss); /* Setup the TSS descriptors and entries */ Ki386InitializeTss(Tss, Idt, Gdt); /* Initialize the PCR */ RtlZeroMemory(Pcr, PAGE_SIZE); KiInitializePcr(Cpu, Pcr, Idt, Gdt, Tss, InitialThread, (PVOID)KiDoubleFaultStack); /* Set us as the current process */ InitialThread->ApcState.Process = &KiInitialProcess.Pcb; /* Clear DR6/7 to cleanup bootloader debugging */ __writefsdword(KPCR_TEB, 0); __writefsdword(KPCR_DR6, 0); __writefsdword(KPCR_DR7, 0); /* Setup the IDT */ KeInitExceptions(); /* Load Ring 3 selectors for DS/ES */ Ke386SetDs(KGDT_R3_DATA | RPL_MASK); Ke386SetEs(KGDT_R3_DATA | RPL_MASK); /* Save NMI and double fault traps */ RtlCopyMemory(&NmiEntry, &Idt[2], sizeof(KIDTENTRY)); RtlCopyMemory(&DoubleFaultEntry, &Idt[8], sizeof(KIDTENTRY)); /* Copy kernel's trap handlers */ RtlCopyMemory(Idt, (PVOID)KiIdtDescriptor.Base, KiIdtDescriptor.Limit + 1); /* Restore NMI and double fault */ RtlCopyMemory(&Idt[2], &NmiEntry, sizeof(KIDTENTRY)); RtlCopyMemory(&Idt[8], &DoubleFaultEntry, sizeof(KIDTENTRY)); AppCpuInit: /* Loop until we can release the freeze lock */ do { /* Loop until execution can continue */ while (*(volatile PKSPIN_LOCK*)&KiFreezeExecutionLock == (PVOID)1); } while(InterlockedBitTestAndSet((PLONG)&KiFreezeExecutionLock, 0)); /* Setup CPU-related fields */ __writefsdword(KPCR_NUMBER, Cpu); __writefsdword(KPCR_SET_MEMBER, 1 << Cpu); __writefsdword(KPCR_SET_MEMBER_COPY, 1 << Cpu); __writefsdword(KPCR_PRCB_SET_MEMBER, 1 << Cpu); /* Initialize the Processor with HAL */ HalInitializeProcessor(Cpu, KeLoaderBlock); /* Set active processors */ KeActiveProcessors |= __readfsdword(KPCR_SET_MEMBER); KeNumberProcessors++; /* Check if this is the boot CPU */ if (!Cpu) { /* Initialize debugging system */ KdInitSystem(0, KeLoaderBlock); /* Check for break-in */ if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); } /* Raise to HIGH_LEVEL */ KfRaiseIrql(HIGH_LEVEL); /* Switch to new kernel stack and start kernel bootstrapping */ KiSwitchToBootStack(InitialStack & ~3); }