VOID NTAPI HalpInitializePICs(IN BOOLEAN EnableInterrupts) { ULONG_PTR EFlags; /* Save EFlags and disable interrupts */ EFlags = __readeflags(); _disable(); /* Initialize and mask the PIC */ HalpInitializeLegacyPIC(); /* Initialize the I/O APIC */ ApicInitializeIOApic(); /* Manually reserve some vectors */ HalpVectorToIndex[APIC_CLOCK_VECTOR] = 8; HalpVectorToIndex[APC_VECTOR] = 99; HalpVectorToIndex[DISPATCH_VECTOR] = 99; /* Set interrupt handlers in the IDT */ KeRegisterInterruptHandler(APIC_CLOCK_VECTOR, HalpClockInterrupt); #ifndef _M_AMD64 KeRegisterInterruptHandler(APC_VECTOR, HalpApcInterrupt); KeRegisterInterruptHandler(DISPATCH_VECTOR, HalpDispatchInterrupt); #endif /* Register the vectors for APC and dispatch interrupts */ HalpRegisterVector(IDT_INTERNAL, 0, APC_VECTOR, APC_LEVEL); HalpRegisterVector(IDT_INTERNAL, 0, DISPATCH_VECTOR, DISPATCH_LEVEL); /* Restore interrupt state */ if (EnableInterrupts) EFlags |= EFLAGS_INTERRUPT_MASK; __writeeflags(EFlags); }
BOOLEAN NTAPI KeConnectInterrupt(IN PKINTERRUPT Interrupt) { PVOID CurrentHandler; ASSERT(Interrupt->Vector <= MAXIMUM_IDTVECTOR); ASSERT(Interrupt->Number < KeNumberProcessors); ASSERT(Interrupt->Irql <= HIGH_LEVEL); /* Check if its already connected */ if (Interrupt->Connected) return TRUE; /* Query the current handler */ CurrentHandler = KeQueryInterruptHandler(Interrupt->Vector); /* Check if the vector is already unused */ if ((CurrentHandler >= (PVOID)KiUnexpectedRange) && (CurrentHandler <= (PVOID)KiUnexpectedRangeEnd)) { /* Initialize the list for chained interrupts */ InitializeListHead(&Interrupt->InterruptListEntry); /* Set normal dispatch address */ Interrupt->DispatchAddress = KiInterruptDispatch; /* Set the new handler */ KeRegisterInterruptHandler(Interrupt->Vector, Interrupt->DispatchCode); if (!HalEnableSystemInterrupt(Interrupt->Vector, Interrupt->Irql, Interrupt->Mode)) { /* Didn't work, restore old handler */ DPRINT1("HalEnableSystemInterrupt failed\n"); KeRegisterInterruptHandler(Interrupt->Vector, CurrentHandler); return FALSE; } /* Mark as connected */ Interrupt->Connected = TRUE; } else { // later __debugbreak(); } return TRUE; }
VOID NTAPI HalpRestoreTrapHandlers(VOID) { // // Keep dummy GPF handler in case we get an NMI during V8086 // if (!HalpNMIInProgress) { // // Not an NMI -- put back the original handler // KeRegisterInterruptHandler(13, HalpGpfHandler); } // // Restore invalid opcode handler // KeRegisterInterruptHandler(6, HalpBopHandler); }
VOID NTAPI HalpSwitchToRealModeTrapHandlers(VOID) { // // Save the current Invalid Opcode and General Protection Fault Handlers // HalpGpfHandler = KeQueryInterruptHandler(13); HalpBopHandler = KeQueryInterruptHandler(6); // // Now set our own GPF handler to handle exceptions while in real mode // KeRegisterInterruptHandler(13, HalpTrap0D); // // And our own invalid opcode handler to detect the BOP to get us out // KeRegisterInterruptHandler(6, HalpTrap06); }
VOID NTAPI KiConnectVectorToInterrupt(IN PKINTERRUPT Interrupt, IN CONNECT_TYPE Type) { DISPATCH_INFO Dispatch; PKINTERRUPT_ROUTINE Handler; /* Get vector data */ KiGetVectorDispatch(Interrupt->Vector, &Dispatch); /* Check if we're only disconnecting */ if (Type == NoConnect) { /* Set the handler to NoDispatch */ Handler = Dispatch.NoDispatch; } else { /* Get the right handler */ Handler = (Type == NormalConnect) ? Dispatch.InterruptDispatch: Dispatch.ChainedDispatch; ASSERT(Interrupt->FloatingSave == FALSE); /* Set the handler */ Interrupt->DispatchAddress = Handler; /* Read note in trap.s -- patching not needed since JMP is static */ /* Now set the final handler address */ ASSERT(Dispatch.FlatDispatch == NULL); Handler = (PVOID)&Interrupt->DispatchCode; } /* Register the interrupt */ KeRegisterInterruptHandler(Interrupt->Vector, Handler); }
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 }
VOID NTAPI HalpInitializeTsc(VOID) { ULONG_PTR Flags; KIDTENTRY OldIdtEntry, *IdtPointer; PKPCR Pcr = KeGetPcr(); UCHAR RegisterA, RegisterB; /* Check if the CPU supports RDTSC */ if (!(KeGetCurrentPrcb()->FeatureBits & KF_RDTSC)) { KeBugCheck(HAL_INITIALIZATION_FAILED); } /* Save flags and disable interrupts */ Flags = __readeflags(); _disable(); /* Enable the periodic interrupt in the CMOS */ RegisterB = HalpReadCmos(RTC_REGISTER_B); HalpWriteCmos(RTC_REGISTER_B, RegisterB | RTC_REG_B_PI); /* Modify register A to RTC_MODE to get SAMPLE_FREQENCY */ RegisterA = HalpReadCmos(RTC_REGISTER_A); RegisterA = (RegisterA & 0xF0) | RTC_MODE; HalpWriteCmos(RTC_REGISTER_A, RegisterA); /* Save old IDT entry */ IdtPointer = KiGetIdtEntry(Pcr, HalpRtcClockVector); OldIdtEntry = *IdtPointer; /* Set the calibration ISR */ KeRegisterInterruptHandler(HalpRtcClockVector, TscCalibrationISR); /* Reset TSC value to 0 */ __writemsr(MSR_RDTSC, 0); /* Enable the timer interupt */ HalEnableSystemInterrupt(HalpRtcClockVector, CLOCK_LEVEL, Latched); /* Read register C, so that the next interrupt can happen */ HalpReadCmos(RTC_REGISTER_C);; /* Wait for completion */ _enable(); while (TscCalibrationPhase < NUM_SAMPLES) _ReadWriteBarrier(); _disable(); /* Disable the periodic interrupt in the CMOS */ HalpWriteCmos(RTC_REGISTER_B, RegisterB & ~RTC_REG_B_PI); /* Disable the timer interupt */ HalDisableSystemInterrupt(HalpRtcClockVector, CLOCK_LEVEL); /* Restore old IDT entry */ *IdtPointer = OldIdtEntry; /* Calculate an average, using simplified linear regression */ HalpCpuClockFrequency.QuadPart = DoLinearRegression(NUM_SAMPLES - 1, TscCalibrationArray); /* Restore flags */ __writeeflags(Flags); }