#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) }; 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; class APIC { private: bool x2APICSupported = false; 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 IPI(uint8_t CPU, uint32_t InterruptNumber); 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 TicksIn10ms = 0; void OnInterruptReceived(CPU::x64::TrapFrame *Frame); public: uint64_t GetTicksIn10ms() { return TicksIn10ms; } void OneShot(uint32_t Vector, uint64_t Miliseconds); Timer(APIC *apic); ~Timer(); }; } #endif // !__FENNIX_KERNEL_APIC_H__