92 lines
1.8 KiB
C++
92 lines
1.8 KiB
C++
#include <socks/compiler.h>
|
|
#include <socks/printk.h>
|
|
#include <arch/acpi/io_apic.hpp>
|
|
|
|
#define IOAPICID 0x00
|
|
#define IOAPICVER 0x01
|
|
#define IOAPICARB 0x02
|
|
#define IOAPICREDTBL(n) (0x10 + 2 * n)
|
|
|
|
namespace arch::acpi {
|
|
io_apic::io_apic(uint32_t *base, unsigned int first_irq) : io_base(base), io_first_irq(first_irq)
|
|
{
|
|
io_nr_irq = ((read(IOAPICVER) >> 16) + 1) & 0xFF;
|
|
}
|
|
|
|
uint32_t io_apic::read(uint32_t reg)
|
|
{
|
|
write_once(io_base, reg & 0xFF);
|
|
return read_once(io_base + 4);
|
|
}
|
|
|
|
void io_apic::write(uint32_t reg, uint32_t val)
|
|
{
|
|
write_once(io_base, reg & 0xFF);
|
|
write_once(io_base + 4, val);
|
|
}
|
|
|
|
kern_status_t io_apic::read_irq(unsigned int index, irq_entry &entry)
|
|
{
|
|
if (index >= io_nr_irq) {
|
|
return KERN_NO_ENTRY;
|
|
}
|
|
|
|
uint32_t *entry_data = (uint32_t *)&entry;
|
|
entry_data[0] = read(IOAPICREDTBL(index));
|
|
entry_data[1] = read(IOAPICREDTBL(index) + 1);
|
|
|
|
return KERN_OK;
|
|
}
|
|
|
|
void io_apic::write_irq(unsigned int index, const irq_entry &entry)
|
|
{
|
|
if (index >= io_nr_irq) {
|
|
return;
|
|
}
|
|
|
|
const uint32_t *entry_data = (const uint32_t *)&entry;
|
|
write(IOAPICREDTBL(index), entry_data[0]);
|
|
write(IOAPICREDTBL(index) + 1, entry_data[1]);
|
|
}
|
|
|
|
void io_apic::map_irq(unsigned int src, unsigned int dest, unsigned int dest_cpu)
|
|
{
|
|
io_apic::irq_entry irq{};
|
|
irq.irq_vec = dest;
|
|
irq.irq_dest = dest_cpu;
|
|
irq.irq_delivery = 0;
|
|
irq.irq_destmode = 0;
|
|
irq.irq_polarity = 0;
|
|
irq.irq_triggermode = 0;
|
|
irq.irq_mask = 0;
|
|
|
|
write_irq(src, irq);
|
|
}
|
|
|
|
void io_apic::mask_irq(unsigned int vec)
|
|
{
|
|
irq_entry irq;
|
|
if (read_irq(vec, irq) != KERN_OK) {
|
|
return;
|
|
}
|
|
|
|
irq.irq_mask = 1;
|
|
write_irq(vec, irq);
|
|
}
|
|
|
|
void io_apic::unmask_irq(unsigned int vec, unsigned int dest_cpu)
|
|
{
|
|
irq_entry irq;
|
|
if (read_irq(vec, irq) != KERN_OK) {
|
|
return;
|
|
}
|
|
|
|
irq.irq_mask = 0;
|
|
if (dest_cpu != (unsigned int)-1) {
|
|
irq.irq_dest = dest_cpu;
|
|
}
|
|
|
|
write_irq(vec, irq);
|
|
}
|
|
}
|