1#include <acpi/ioapic.h>
2#include <console/printf.h>
3#include <drivers/mmio.h>
4#include <mem/page.h>
5#include <mem/vmm.h>
6#include <stdint.h>
7#include <uacpi/tables.h>
8
9#include "uacpi/acpi.h"
10#include "uacpi/status.h"
11
12static struct ioapic_info ioapic;
13static LOG_HANDLE_DECLARE_DEFAULT(ioapic);
14
15void ioapic_write(uint8_t reg, uint32_t val) {
16 mmio_write_32(address: &ioapic.mmio_base[0], value: reg); // IOREGSEL
17 mmio_write_32(address: &ioapic.mmio_base[4], value: val); // IOWIN
18}
19
20uint32_t ioapic_read(uint8_t reg) {
21 mmio_write_32(address: &ioapic.mmio_base[0], value: reg);
22 return mmio_read_32(address: &ioapic.mmio_base[4]);
23}
24
25static uint64_t make_redirection_entry(uint8_t vector, uint8_t dest_apic_id,
26 bool masked) {
27 union ioapic_redirection_entry entry = {0};
28 entry.vector = vector;
29 entry.delivery_mode = 0; // Fixed delivery
30 entry.dest_mode = 0; // Physical mode
31 entry.polarity = 0; // Active high
32 entry.trigger_mode = 0; // Edge triggered
33 entry.mask = masked ? 1 : 0;
34 entry.dest_apic_id = dest_apic_id;
35 return entry.raw;
36}
37
38void ioapic_set_redirection_entry(int irq, uint64_t entry) {
39 ioapic_write(reg: 0x10 + irq * 2, val: (uint32_t) (entry & 0xFFFFFFFF));
40 ioapic_write(reg: 0x10 + irq * 2 + 1, val: (uint32_t) (entry >> 32));
41}
42
43void ioapic_route_irq(irq_t irq, uint8_t vector, uint8_t dest_apic_id,
44 bool masked) {
45 uint64_t redir_entry = make_redirection_entry(vector, dest_apic_id, masked);
46 ioapic_set_redirection_entry(irq, entry: redir_entry);
47}
48
49void ioapic_mask_irq(irq_t irq) {
50 uint32_t low = ioapic_read(reg: 0x10 + irq * 2);
51 low |= (1 << 16);
52 ioapic_write(reg: 0x10 + irq * 2, val: low);
53}
54
55void ioapic_unmask_irq(irq_t irq) {
56 uint32_t low = ioapic_read(reg: 0x10 + irq * 2);
57 low &= ~(1 << 16);
58 ioapic_write(reg: 0x10 + irq * 2, val: low);
59}
60
61void ioapic_init(void) {
62 struct uacpi_table apic_table;
63
64 if (uacpi_table_find_by_signature(signature: "APIC", out_table: &apic_table) != UACPI_STATUS_OK) {
65 log_err_global(LOG_HANDLE(ioapic), "MADT not found");
66 return;
67 }
68
69 struct acpi_madt *madt = (struct acpi_madt *) apic_table.ptr;
70
71 uint8_t *ptr = (uint8_t *) madt + sizeof(struct acpi_madt);
72 uint64_t remaining = madt->hdr.length - sizeof(struct acpi_madt);
73
74 while (remaining >= sizeof(struct acpi_entry_hdr)) {
75 struct acpi_entry_hdr *entry = (struct acpi_entry_hdr *) ptr;
76
77 if (entry->type == ACPI_MADT_ENTRY_TYPE_IOAPIC) {
78 struct acpi_madt_ioapic *ioapic_entry =
79 (struct acpi_madt_ioapic *) entry;
80
81 ioapic.id = ioapic_entry->id;
82 ioapic.gsi_base = ioapic_entry->gsi_base;
83 ioapic.mmio_base = mmio_map(phys: ioapic_entry->address, size: 0x20);
84
85 log_info_global(LOG_HANDLE(ioapic),
86 "ID: %u, GSI Base: %u, MMIO: %p", ioapic.id,
87 ioapic.gsi_base, ioapic.mmio_base);
88
89 return;
90 }
91
92 ptr += entry->length;
93 remaining -= entry->length;
94 }
95
96 panic("no I/O APIC entry found in MADT");
97}
98