ULONG_PTR NTAPI HalSetProfileInterval(IN ULONG_PTR Interval) { ULONGLONG TimerInterval; ULONGLONG FixedInterval; FixedInterval = (ULONGLONG)Interval; /* Check bounds */ if (FixedInterval < HalMinProfileInterval) { FixedInterval = HalMinProfileInterval; } else if (FixedInterval > HalMaxProfileInterval) { FixedInterval = HalMaxProfileInterval; } /* Remember interval */ HalCurProfileInterval = FixedInterval; /* Recalculate interval for APIC */ TimerInterval = FixedInterval * KeGetPcr()->HalReserved[HAL_PROFILING_MULTIPLIER] / HalMaxProfileInterval; /* Remember recalculated interval in PCR */ KeGetPcr()->HalReserved[HAL_PROFILING_INTERVAL] = (ULONG)TimerInterval; /* And set it */ ApicWrite(APIC_TICR, (ULONG)TimerInterval); return Interval; }
VOID NTAPI ApicSetTimerInterval(ULONG MicroSeconds) { LVT_REGISTER LvtEntry; ULONGLONG TimerInterval; /* Calculate the Timer interval */ TimerInterval = HalpCpuClockFrequency.QuadPart * MicroSeconds / 1000000; /* Set the count interval */ ApicWrite(APIC_TICR, (ULONG)TimerInterval); /* Set to periodic */ LvtEntry.Long = 0; LvtEntry.TimerMode = 1; LvtEntry.Vector = APIC_PROFILE_VECTOR; LvtEntry.Mask = 0; ApicWrite(APIC_TMRLVTR, LvtEntry.Long); }
FORCEINLINE VOID ApicSetIrql(KIRQL Irql) { #ifdef _M_AMD64 __writecr8(Irql); #elif defined(APIC_LAZY_IRQL) __writefsbyte(FIELD_OFFSET(KPCR, Irql), Irql); #else /* Convert IRQL and write the TPR */ ApicWrite(APIC_TPR, IrqlToTpr(Irql)); #endif }
VOID NTAPI HalStartProfileInterrupt(IN KPROFILE_SOURCE ProfileSource) { LVT_REGISTER LvtEntry; /* Only handle ProfileTime */ if (ProfileSource == ProfileTime) { /* OK, we are profiling now */ HalIsProfiling = TRUE; /* Set interrupt interval */ ApicWrite(APIC_TICR, KeGetPcr()->HalReserved[HAL_PROFILING_INTERVAL]); /* Unmask it */ LvtEntry.Long = 0; LvtEntry.TimerMode = 1; LvtEntry.Vector = APIC_PROFILE_VECTOR; LvtEntry.Mask = 0; ApicWrite(APIC_TMRLVTR, LvtEntry.Long); } }
VOID NTAPI ApicInitializeTimer(ULONG Cpu) { /* Initialize the TSC */ //HalpInitializeTsc(); /* Set clock multiplier to 1 */ ApicWrite(APIC_TDCR, TIMER_DV_DivideBy1); ApicSetTimerInterval(1000); // KeSetTimeIncrement }
FORCEINLINE VOID ApicLowerIrql(KIRQL Irql) { __writefsbyte(FIELD_OFFSET(KPCR, Irql), Irql); /* Is the new Irql lower than set in the TPR? */ if (Irql < KeGetPcr()->IRR) { /* Save the new hard IRQL in the IRR field */ KeGetPcr()->IRR = Irql; /* Need to lower it back */ ApicWrite(APIC_TPR, IrqlToTpr(Irql)); } }
FORCEINLINE VOID ApicRequestInterrupt(IN UCHAR Vector, UCHAR TriggerMode) { APIC_COMMAND_REGISTER CommandRegister; /* Setup the command register */ CommandRegister.Long0 = 0; CommandRegister.Vector = Vector; CommandRegister.MessageType = APIC_MT_Fixed; CommandRegister.TriggerMode = TriggerMode; CommandRegister.DestinationShortHand = APIC_DSH_Self; /* Write the low dword to send the interrupt */ ApicWrite(APIC_ICR0, CommandRegister.Long0); }
VOID NTAPI HalStopProfileInterrupt(IN KPROFILE_SOURCE ProfileSource) { LVT_REGISTER LvtEntry; /* Only handle ProfileTime */ if (ProfileSource == ProfileTime) { /* We are not profiling */ HalIsProfiling = FALSE; /* Mask interrupt */ LvtEntry.Long = 0; LvtEntry.TimerMode = 1; LvtEntry.Vector = APIC_PROFILE_VECTOR; LvtEntry.Mask = 1; ApicWrite(APIC_TMRLVTR, LvtEntry.Long); } }
BOOLEAN NTAPI HalBeginSystemInterrupt( IN KIRQL Irql, IN ULONG Vector, OUT PKIRQL OldIrql) { KIRQL CurrentIrql; /* Get the current IRQL */ CurrentIrql = ApicGetCurrentIrql(); #ifdef APIC_LAZY_IRQL /* Check if this interrupt is allowed */ if (CurrentIrql >= Irql) { IOAPIC_REDIRECTION_REGISTER RedirReg; UCHAR Index; /* It is not, set the real Irql in the TPR! */ ApicWrite(APIC_TPR, IrqlToTpr(CurrentIrql)); /* Save the new hard IRQL in the IRR field */ KeGetPcr()->IRR = CurrentIrql; /* End this interrupt */ ApicSendEOI(); /* Get the irq for this vector */ Index = HalpVectorToIndex[Vector]; /* Check if its valid */ if (Index != 0xff) { /* Read the I/O redirection entry */ RedirReg = ApicReadIORedirectionEntry(Index); /* Re-request the interrupt to be handled later */ ApicRequestInterrupt(Vector, (UCHAR)RedirReg.TriggerMode); } else { /* Re-request the interrupt to be handled later */ ApicRequestInterrupt(Vector, APIC_TGM_Edge); } /* Pretend it was a spurious interrupt */ return FALSE; } #endif /* Save the current IRQL */ *OldIrql = CurrentIrql; /* Set the new IRQL */ ApicRaiseIrql(Irql); /* Turn on interrupts */ _enable(); /* Success */ return TRUE; }
VOID NTAPI ApicInitializeLocalApic(ULONG Cpu) { APIC_BASE_ADRESS_REGISTER BaseRegister; APIC_SPURIOUS_INERRUPT_REGISTER SpIntRegister; LVT_REGISTER LvtEntry; /* Enable the APIC if it wasn't yet */ BaseRegister.Long = __readmsr(MSR_APIC_BASE); BaseRegister.Enable = 1; BaseRegister.BootStrapCPUCore = (Cpu == 0); __writemsr(MSR_APIC_BASE, BaseRegister.Long); /* Set spurious vector and SoftwareEnable to 1 */ SpIntRegister.Long = ApicRead(APIC_SIVR); SpIntRegister.Vector = APIC_SPURIOUS_VECTOR; SpIntRegister.SoftwareEnable = 1; SpIntRegister.FocusCPUCoreChecking = 0; ApicWrite(APIC_SIVR, SpIntRegister.Long); /* Read the version and save it globally */ if (Cpu == 0) ApicVersion = ApicRead(APIC_VER); /* Set the mode to flat (max 8 CPUs supported!) */ ApicWrite(APIC_DFR, APIC_DF_Flat); /* Set logical apic ID */ ApicWrite(APIC_LDR, ApicLogicalId(Cpu) << 24); /* Set the spurious ISR */ KeRegisterInterruptHandler(APIC_SPURIOUS_VECTOR, ApicSpuriousService); /* Create a template LVT */ LvtEntry.Long = 0; LvtEntry.Vector = 0xFF; LvtEntry.MessageType = APIC_MT_Fixed; LvtEntry.DeliveryStatus = 0; LvtEntry.RemoteIRR = 0; LvtEntry.TriggerMode = APIC_TGM_Edge; LvtEntry.Mask = 1; LvtEntry.TimerMode = 0; /* Initialize and mask LVTs */ ApicWrite(APIC_TMRLVTR, LvtEntry.Long); ApicWrite(APIC_THRMLVTR, LvtEntry.Long); ApicWrite(APIC_PCLVTR, LvtEntry.Long); ApicWrite(APIC_EXT0LVTR, LvtEntry.Long); ApicWrite(APIC_EXT1LVTR, LvtEntry.Long); ApicWrite(APIC_EXT2LVTR, LvtEntry.Long); ApicWrite(APIC_EXT3LVTR, LvtEntry.Long); /* LINT0 */ LvtEntry.Vector = APIC_SPURIOUS_VECTOR; LvtEntry.MessageType = APIC_MT_ExtInt; ApicWrite(APIC_LINT0, LvtEntry.Long); /* Enable LINT1 (NMI) */ LvtEntry.Mask = 0; LvtEntry.Vector = APIC_NMI_VECTOR; LvtEntry.MessageType = APIC_MT_NMI; LvtEntry.TriggerMode = APIC_TGM_Level; ApicWrite(APIC_LINT1, LvtEntry.Long); /* Enable error LVTR */ LvtEntry.Vector = APIC_ERROR_VECTOR; LvtEntry.MessageType = APIC_MT_Fixed; ApicWrite(APIC_ERRLVTR, LvtEntry.Long); /* Set the IRQL from the PCR */ ApicSetIrql(KeGetPcr()->Irql); #ifdef APIC_LAZY_IRQL /* Save the new hard IRQL in the IRR field */ KeGetPcr()->IRR = KeGetPcr()->Irql; #endif }