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; }
/* Entry point of a module */ MODULES_API void ModuleInit(void *Data) { /* We need these */ MCoreDevice_t *Device = NULL; MCoreTimerDevice_t *Timer = NULL; PitTimer_t *Pit = NULL; /* We want a frequncy of 1000 hz */ uint32_t Divisor = (1193181 / 1000); IntStatus_t IntrState; /* Unused */ _CRT_UNUSED(Data); /* Allocate */ Device = (MCoreDevice_t*)kmalloc(sizeof(MCoreDevice_t)); Pit = (PitTimer_t*)kmalloc(sizeof(PitTimer_t)); Timer = (MCoreTimerDevice_t*)kmalloc(sizeof(MCoreTimerDevice_t)); /* Disable IRQ's for this duration */ IntrState = InterruptDisable(); Pit->PitCounter = 0; Pit->Divisor = Divisor; /* Setup Timer */ Timer->TimerData = Pit; Timer->Sleep = PitSleep; Timer->Stall = PitStall; Timer->GetTicks = PitGetClocks; /* Install Irq */ InterruptInstallISA(X86_PIT_IRQ, INTERRUPT_PIT, PitIrqHandler, Timer); /* Before enabling, register us */ Pit->DeviceId = DmCreateDevice("PIT Timer", DeviceTimer, Timer); /* We use counter 0, select counter 0 and configure it */ outb(X86_PIT_REGISTER_COMMAND, X86_PIT_COMMAND_SQUAREWAVEGEN | X86_PIT_COMMAND_RL_DATA | X86_PIT_COMMAND_COUNTER_0); /* Set divisor */ outb(X86_PIT_REGISTER_COUNTER0, (uint8_t)(Divisor & 0xFF)); outb(X86_PIT_REGISTER_COUNTER0, (uint8_t)((Divisor >> 8) & 0xFF)); /* Done, reenable interrupts */ InterruptRestoreState(IntrState); }
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); }