22 #include "LocalApic.h" 23 #include "pedigree/kernel/Log.h" 24 #include "pedigree/kernel/machine/TimerHandler.h" 25 #include "pedigree/kernel/processor/InterruptManager.h" 26 #include "pedigree/kernel/processor/PhysicalMemoryManager.h" 27 #include "pedigree/kernel/processor/Processor.h" 28 #include "pedigree/kernel/processor/VirtualAddressSpace.h" 30 #define LAPIC_REG_ID 0x0020 31 #define LAPIC_REG_VERSION 0x0030 32 #define LAPIC_REG_TASK_PRIORITY 0x0080 33 #define LAPIC_REG_PROCESSOR_PRIORITY 0x00A0 34 #define LAPIC_REG_EOI 0x00B0 35 #define LAPIC_REG_LOGICAL_DESTINATION 0x00D0 36 #define LAPIC_REG_DESTINATION_FORMAT 0x00E0 37 #define LAPIC_REG_SPURIOUS_INT 0x00F0 41 #define LAPIC_REG_ERR_STATUS 0x0280 42 #define LAPIC_REG_INT_CMD_LOW 0x0300 43 #define LAPIC_REG_INT_CMD_HIGH 0x0310 44 #define LAPIC_REG_LVT_TIMER 0x0320 45 #define LAPIC_REG_LVT_THERMAL 0x0330 46 #define LAPIC_REG_LVT_PERFORMANCE 0x0340 47 #define LAPIC_REG_LVT_LINT0 0x0350 48 #define LAPIC_REG_LVT_LINT1 0x0360 49 #define LAPIC_REG_LVT_ERROR 0x0370 50 #define LAPIC_REG_INITIAL_COUNT 0x0380 51 #define LAPIC_REG_CURRENT_COUNT 0x0390 52 #define LAPIC_REG_DIVIDE_CONFIG 0x03E0 54 #define LAPIC_TIMER_PERIODIC 0x00020000 55 #define LAPIC_MASKED 0x00010000 59 #define INITIAL_COUNT_VALUE (78125 * 40) 62 #define INITIAL_HZ 100 67 uint32_t eax, ebx, ecx, edx;
69 if (((edx >> 9) & 0x01) != 0x01)
71 ERROR(
"Local APIC: No local APIC present");
76 if (check(physicalAddress) ==
false)
89 physicalAddress) ==
false)
91 ERROR(
"Local APIC: Could not allocate the memory region");
102 IPI_HALT_VECTOR,
this))
105 return initialiseProcessor();
108 bool LocalApic::initialiseProcessor()
111 if (check(m_IoSpace.physicalAddress()) ==
false)
115 uint32_t tmp = m_IoSpace.read32(LAPIC_REG_SPURIOUS_INT);
117 (tmp & 0xFFFFFE00) | 0x100 | SPURIOUS_VECTOR, LAPIC_REG_SPURIOUS_INT);
120 tmp = m_IoSpace.read32(LAPIC_REG_TASK_PRIORITY);
121 m_IoSpace.write32(tmp & 0xFFFFFF00, LAPIC_REG_TASK_PRIORITY);
124 tmp = m_IoSpace.read32(LAPIC_REG_LVT_ERROR);
125 m_IoSpace.write32((tmp & 0xFFFEEF00) | ERROR_VECTOR, LAPIC_REG_LVT_ERROR);
130 m_IoSpace.write32(0x3, LAPIC_REG_DIVIDE_CONFIG);
134 m_IoSpace.write32(0xFFFFFFFF, LAPIC_REG_INITIAL_COUNT);
137 for (
size_t i = 0; i < 10000; ++i)
140 __asm__ __volatile__(
"outb %0, %1" ::
"a"(a),
"Nd"(0x80));
142 uint32_t out = m_IoSpace.read32(LAPIC_REG_CURRENT_COUNT);
144 uint32_t ticks = 0xFFFFFFFFU - out;
147 m_BusFrequency = ticks * 100U;
151 m_IoSpace.write32(LAPIC_TIMER_PERIODIC | TIMER_VECTOR, LAPIC_REG_LVT_TIMER);
154 m_IoSpace.write32(m_BusFrequency / INITIAL_HZ, LAPIC_REG_INITIAL_COUNT);
157 m_IoSpace.write32(0x3, LAPIC_REG_DIVIDE_CONFIG);
164 void LocalApic::interProcessorInterrupt(
165 uint8_t destinationApicId, uint8_t vector,
size_t deliveryMode,
166 bool bAssert,
bool bLevelTriggered)
168 while ((m_IoSpace.read32(LAPIC_REG_INT_CMD_LOW) & 0x1000) != 0)
171 m_IoSpace.write32(destinationApicId << 24, LAPIC_REG_INT_CMD_HIGH);
173 vector | (deliveryMode << 8) | (bAssert ? (1 << 14) : 0) |
174 (bLevelTriggered ? (1 << 15) : 0),
175 LAPIC_REG_INT_CMD_LOW);
178 void LocalApic::interProcessorInterruptAllExcludingThis(
179 uint8_t vector,
size_t deliveryMode)
181 while ((m_IoSpace.read32(LAPIC_REG_INT_CMD_LOW) & 0x1000) != 0)
185 vector | (deliveryMode << 8) | (1 << 14) | (0x3 << 18),
186 LAPIC_REG_INT_CMD_LOW);
189 uint8_t LocalApic::getId()
191 return ((m_IoSpace.read32(LAPIC_REG_ID) >> 24) & 0xFF);
194 bool LocalApic::check(uint64_t physicalAddress)
199 ERROR(
"Local APIC: Disabled");
207 ERROR(
"Local APIC: Wrong physical address");
214 void LocalApic::interrupt(
size_t nInterruptNumber, InterruptState &state)
216 if (nInterruptNumber == TIMER_VECTOR)
227 handler->
timer(0, state);
232 if (nInterruptNumber == IPI_HALT_VECTOR)
239 void LocalApic::ack()
242 m_IoSpace.write32(0x00000000, LAPIC_REG_EOI);
static uint64_t readMachineSpecificRegister(uint32_t index)
static void cpuid(uint32_t inEax, uint32_t inEcx, uint32_t &eax, uint32_t &ebx, uint32_t &ecx, uint32_t &edx)
static PhysicalMemoryManager & instance()
static const size_t continuous
static const size_t force
static const size_t Write
uintptr_t physicalAddress(physical_uintptr_t address) PURE
static const size_t KernelMode
virtual void timer(uint64_t delta, InterruptState &state)=0
virtual bool allocateRegion(MemoryRegion &Region, size_t cPages, size_t pageConstraints, size_t Flags, physical_uintptr_t start=-1)=0
static const size_t nonRamMemory
static const size_t CacheDisable
static InterruptManager & instance()