OsStatus_t ApicPerformIPI( _In_ UUId_t CoreId, _In_ int Assert) { uint32_t IpiHigh = APIC_DESTINATION(CoreId); // We use physical addressing for IPI/SIPI uint32_t IpiLow = 0; IntStatus_t InterruptStatus; OsStatus_t Status; // Determine assert or deassert if (Assert) { IpiLow = APIC_DELIVERY_MODE(APIC_MODE_INIT) | APIC_LEVEL_ASSERT | APIC_DESTINATION_PHYSICAL; } else { IpiLow = APIC_DELIVERY_MODE(APIC_MODE_INIT) | APIC_TRIGGER_LEVEL | APIC_DESTINATION_PHYSICAL; } // Wait for ICR to clear InterruptStatus = InterruptDisable(); Status = ApicWaitForIdle(); if (Status == OsSuccess) { // Always write upper first, irq is sent when low is written ApicWriteLocal(APIC_ICR_HIGH, IpiHigh); ApicWriteLocal(APIC_ICR_LOW, IpiLow); Status = ApicWaitForIdle(); } InterruptRestoreState(InterruptStatus); return Status; }
OsStatus_t ApicPerformSIPI( _In_ UUId_t CoreId, _In_ uintptr_t Address) { uint32_t IpiLow = APIC_DELIVERY_MODE(APIC_MODE_SIPI) | APIC_LEVEL_ASSERT | APIC_DESTINATION_PHYSICAL; uint32_t IpiHigh = APIC_DESTINATION(CoreId); // We use physical addressing for IPI/SIPI uint8_t Vector = 0; IntStatus_t InterruptStatus; OsStatus_t Status; // Sanitize address given assert((Address % 0x1000) == 0); Vector = Address / 0x1000; assert(Vector <= 0xF); IpiLow |= Vector; // Wait for ICR to clear InterruptStatus = InterruptDisable(); Status = ApicWaitForIdle(); if (Status == OsSuccess) { // Always write upper first, irq is sent when low is written ApicWriteLocal(APIC_ICR_HIGH, IpiHigh); ApicWriteLocal(APIC_ICR_LOW, IpiLow); Status = ApicWaitForIdle(); } InterruptRestoreState(InterruptStatus); return Status; }
OsStatus_t ApicSendInterrupt( _In_ InterruptTarget_t Type, _In_ UUId_t Specific, _In_ uint32_t Vector) { uint32_t IpiLow = 0; uint32_t IpiHigh = 0; UUId_t CoreId = ArchGetProcessorCoreId(); IntStatus_t InterruptStatus; OsStatus_t Status; if (!ApicIsInitialized()) { return OsSuccess; } if (Type == InterruptSpecific && Specific == CoreId) { Type = InterruptSelf; } // Handle target types if (Type == InterruptSpecific) { IpiHigh = APIC_DESTINATION(Specific); } else if (Type == InterruptSelf) { IpiLow |= (1 << 18); } else if (Type == InterruptAll) { IpiLow |= (1 << 19); } else { IpiLow |= (1 << 19) | (1 << 18); } // Physical Destination (Bit 11 = 0) // Fixed Delivery // Assert (Bit 14 = 1) // Edge (Bit 15 = 0) IpiLow |= APIC_VECTOR(Vector) | APIC_LEVEL_ASSERT | APIC_DESTINATION_PHYSICAL; // Are we sending to ourself? Handle this a bit differently, if the ICR is already // busy we don't want to clear it as we already a send pending, just queue up interrupt InterruptStatus = InterruptDisable(); Status = ApicWaitForIdle(); if (Status == OsSuccess) { ApicWriteLocal(APIC_ICR_HIGH, IpiHigh); ApicWriteLocal(APIC_ICR_LOW, IpiLow); Status = ApicWaitForIdle(); } InterruptRestoreState(InterruptStatus); return Status; }
void ApicSynchronizeArbIds(void) { // Variables IntStatus_t InterruptStatus; OsStatus_t Status; // Not needed on AMD and not supported on P4 // So we need a check here in place to do it @todo InterruptStatus = InterruptDisable(); Status = ApicWaitForIdle(); assert(Status != OsError); ApicWriteLocal(APIC_ICR_HIGH, 0); ApicWriteLocal(APIC_ICR_LOW, APIC_ICR_SH_ALL | APIC_TRIGGER_LEVEL | APIC_DELIVERY_MODE(APIC_MODE_INIT)); Status = ApicWaitForIdle(); assert(Status != OsError); InterruptRestoreState(InterruptStatus); }
/* The YIELD handler */ int ThreadingYield(void *Args) { /* Get registers */ Registers_t *Regs = NULL; uint32_t TimeSlice = 20; uint32_t TaskPriority = 0; Cpu_t CurrCpu = ApicGetCpu(); /* Send EOI */ ApicSendEoi(0, INTERRUPT_YIELD); /* Switch Task */ Regs = _ThreadingSwitch((Registers_t*)Args, 0, &TimeSlice, &TaskPriority); /* If we just got hold of idle task, well f**k it disable timer * untill we get another task */ if (!(ThreadingGetCurrentThread(CurrCpu)->Flags & THREADING_IDLE)) { /* Set Task Priority */ ApicSetTaskPriority(61 - TaskPriority); /* Restart timer */ ApicWriteLocal(APIC_INITIAL_COUNT, GlbTimerQuantum * TimeSlice); } else { /* Set low priority */ ApicSetTaskPriority(0); /* Disable timer */ ApicWriteLocal(APIC_INITIAL_COUNT, 0); } /* Enter new thread */ enter_thread(Regs); /* Never reached */ return X86_IRQ_HANDLED; }