#ifndef __FENNIX_KERNEL_APIC_H__ #define __FENNIX_KERNEL_APIC_H__ #include #include #include namespace APIC { enum APICRegisters { // source from: https://github.com/pdoane/osdev/blob/master/intr/local_apic.c APIC_ID = 0x20, // Local APIC ID APIC_VER = 0x30, // Local APIC Version APIC_TPR = 0x80, // Task Priority APIC_APR = 0x90, // Arbitration Priority APIC_PPR = 0xA0, // Processor Priority APIC_EOI = 0xB0, // EOI APIC_RRD = 0xC0, // Remote Read APIC_LDR = 0xD0, // Logical Destination APIC_DFR = 0xE0, // Destination Format APIC_SVR = 0xF0, // Spurious Interrupt Vector APIC_ISR = 0x100, // In-Service (8 registers) APIC_TMR = 0x180, // Trigger Mode (8 registers) APIC_IRR = 0x200, // Interrupt Request (8 registers) APIC_ESR = 0x280, // Error Status APIC_ICRLO = 0x300, // Interrupt Command APIC_ICRHI = 0x310, // Interrupt Command [63:32] APIC_TIMER = 0x320, // LVT Timer APIC_THERMAL = 0x330, // LVT Thermal Sensor APIC_PERF = 0x340, // LVT Performance Counter APIC_LINT0 = 0x350, // LVT LINT0 APIC_LINT1 = 0x360, // LVT LINT1 APIC_ERROR = 0x370, // LVT Error APIC_TICR = 0x380, // Initial Count (for Timer) APIC_TCCR = 0x390, // Current Count (for Timer) APIC_TDCR = 0x3E0, // Divide Configuration (for Timer) }; enum IOAPICRegisters { GetIOAPICVersion = 0x1 }; enum IOAPICFlags { ActiveHighLow = 2, EdgeLevel = 8 }; enum APICDeliveryMode { Fixed = 0, LowestPriority = 1, SMI = 2, NMI = 4, INIT = 5, Startup = 6, ExtINT = 7 }; typedef union { struct { /** @brief Interrupt Vector */ uint64_t Vector : 8; /** @brief Reserved */ uint64_t Reserved0 : 4; /** * @brief Delivery Status * * 0: Idle * 1: Send Pending */ uint64_t DeliveryStatus : 1; /** @brief Reserved */ uint64_t Reserved1 : 3; /** * @brief Mask * * 0: Not masked * 1: Masked */ uint64_t Mask : 1; /** @brief Timer Mode * * 0: One-shot * 1: Periodic * 2: TSC-Deadline */ uint64_t TimerMode : 1; /** @brief Reserved */ uint64_t Reserved2 : 14; }; uint64_t raw; } __attribute__((packed)) LVTTimer; typedef union { struct { /** @brief Spurious Vector */ uint64_t Vector : 8; /** @brief Enable or disable APIC software */ uint64_t Software : 1; /** @brief Focus Processor Checking */ uint64_t FocusProcessorChecking : 1; /** @brief Reserved */ uint64_t Reserved : 2; /** @brief Disable EOI Broadcast */ uint64_t DisableEOIBroadcast : 1; /** @brief Reserved */ uint64_t Reserved1 : 19; }; uint64_t raw; } __attribute__((packed)) Spurious; typedef union { struct { /** @brief Interrupt Vector */ uint64_t Vector : 8; /** @brief Delivery Mode */ uint64_t DeliveryMode : 3; /** @brief Destination Mode * * 0: Physical * 1: Logical */ uint64_t DestinationMode : 1; /** @brief Delivery Status * * @note Reserved when in x2APIC mode */ uint64_t DeliveryStatus : 1; /** @brief Reserved */ uint64_t Reserved0 : 1; /** @brief Level * * 0: Deassert * 1: Assert */ uint64_t Level : 1; /** @brief Trigger Mode * * 0: Edge * 1: Level */ uint64_t TriggerMode : 1; /** @brief Reserved */ uint64_t Reserved1 : 2; /** @brief Destination Shorthand * * 0: No shorthand * 1: Self * 2: All including self * 3: All excluding self */ uint64_t DestinationShorthand : 2; /** @brief Reserved */ uint64_t Reserved2 : 12; }; uint64_t raw; } __attribute__((packed)) InterruptCommandRegisterLow; typedef union { struct { /** @brief Reserved */ uint64_t Reserved0 : 24; /** @brief Destination */ uint64_t Destination : 8; }; uint64_t raw; } __attribute__((packed)) InterruptCommandRegisterHigh; typedef union { struct { /** @brief Interrupt Vector */ uint64_t Vector : 8; /** @brief Delivery Mode */ uint64_t DeliveryMode : 3; /** @brief Destination Mode * * 0: Physical * 1: Logical */ uint64_t DestinationMode : 1; /** @brief Delivery Status */ uint64_t DeliveryStatus : 1; /** @brief Interrupt Input Pin Polarity * * 0: Active High * 1: Active Low */ uint64_t Polarity : 1; /** @brief Remote IRR */ uint64_t RemoteIRR : 1; /** @brief Trigger Mode * * 0: Edge * 1: Level */ uint64_t TriggerMode : 1; /** @brief Mask */ uint64_t Mask : 1; /** @brief Reserved */ uint64_t Reserved0 : 15; /** @brief Reserved */ uint64_t Reserved1 : 24; /** @brief Destination */ uint64_t DestinationID : 8; }; uint64_t raw; } __attribute__((packed)) RedirectEntry; typedef union { struct { uint64_t Version : 8; uint64_t Reserved : 8; uint64_t MaximumRedirectionEntry : 8; uint64_t Reserved2 : 8; }; uint64_t raw; } __attribute__((packed)) IOAPICVersion; class APIC { private: bool x2APICSupported = false; uint64_t APICBaseAddress = 0; public: uint32_t Read(uint32_t Register); void Write(uint32_t Register, uint32_t Value); void IOWrite(uint64_t Base, uint32_t Register, uint32_t Value); uint32_t IORead(uint64_t Base, uint32_t Register); void EOI(); void RedirectIRQs(int CPU = 0); void WaitForIPI(); void IPI(uint8_t CPU, InterruptCommandRegisterLow icr); void SendInitIPI(uint8_t CPU); void SendStartupIPI(uint8_t CPU, uint64_t StartupAddress); uint32_t IOGetMaxRedirect(uint32_t APICID); void RawRedirectIRQ(uint8_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status); void RedirectIRQ(int CPU, uint8_t IRQ, int Status); APIC(int Core); ~APIC(); }; class Timer : public Interrupts::Handler { private: APIC *lapic; uint64_t Ticks = 0; void OnInterruptReceived(CPU::x64::TrapFrame *Frame); public: uint64_t GetTicks() { return Ticks; } void OneShot(uint32_t Vector, uint64_t Miliseconds); Timer(APIC *apic); ~Timer(); }; } #endif // !__FENNIX_KERNEL_APIC_H__