APIC, HPET, virtual memory
This commit is contained in:
158
kernel/amd64/apic.c
Normal file
158
kernel/amd64/apic.c
Normal file
@@ -0,0 +1,158 @@
|
||||
#include <amd64/apic.h>
|
||||
#include <libk/std.h>
|
||||
#include <limine/requests.h>
|
||||
#include <sys/debug.h>
|
||||
#include <sys/mm.h>
|
||||
#include <uacpi/acpi.h>
|
||||
#include <uacpi/status.h>
|
||||
#include <uacpi/tables.h>
|
||||
#include <uacpi/uacpi.h>
|
||||
|
||||
#define IOAPICS_MAX 24
|
||||
#define INTERRUPT_SRC_OVERRIDES_MAX 24
|
||||
|
||||
static struct acpi_madt_ioapic apics[IOAPICS_MAX];
|
||||
/* clang-format off */
|
||||
static struct acpi_madt_interrupt_source_override intr_src_overrides[INTERRUPT_SRC_OVERRIDES_MAX];
|
||||
/* clang-format on */
|
||||
static size_t ioapic_entries = 0;
|
||||
static size_t intr_src_override_entries = 0;
|
||||
|
||||
extern void amd64_spin (void);
|
||||
|
||||
static uint32_t amd64_ioapic_read (uintptr_t vaddr, uint32_t reg) {
|
||||
*(volatile uint32_t*)vaddr = reg;
|
||||
return *(volatile uint32_t*)(vaddr + 0x10);
|
||||
}
|
||||
|
||||
static void amd64_ioapic_write (uintptr_t vaddr, uint32_t reg, uint32_t value) {
|
||||
*(volatile uint32_t*)vaddr = reg;
|
||||
*(volatile uint32_t*)(vaddr + 0x10) = value;
|
||||
}
|
||||
|
||||
static struct acpi_madt_ioapic* amd64_ioapic_find (uint8_t irq) {
|
||||
struct acpi_madt_ioapic* apic = NULL;
|
||||
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
|
||||
|
||||
for (size_t i = 0; i < ioapic_entries; i++) {
|
||||
apic = &apics[i];
|
||||
uint32_t version = amd64_ioapic_read (
|
||||
(uintptr_t)hhdm->offset + (uintptr_t)apic->address, 1);
|
||||
uint32_t max = (version >> 16);
|
||||
|
||||
if ((apic->gsi_base <= irq) && ((apic->gsi_base + max) > irq))
|
||||
break;
|
||||
}
|
||||
|
||||
return apic;
|
||||
}
|
||||
|
||||
void amd64_ioapic_route_irq (uint8_t vec, uint8_t irq, uint64_t flags,
|
||||
uint64_t lapic_id) {
|
||||
struct acpi_madt_ioapic* apic;
|
||||
struct acpi_madt_interrupt_source_override* override;
|
||||
bool found_override = false;
|
||||
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
|
||||
|
||||
for (size_t i = 0; i < intr_src_override_entries; i++) {
|
||||
override = &intr_src_overrides[i];
|
||||
if (override->source == irq) {
|
||||
found_override = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t calc_flags = (lapic_id << 56) | (flags) | (vec & 0xFF);
|
||||
|
||||
if (found_override) {
|
||||
uint8_t polarity = ((override->flags & 0x03) == 0x03) ? 1 : 0;
|
||||
uint8_t mode = (((override->flags >> 2) & 0x03) == 0x03) ? 1 : 0;
|
||||
calc_flags = (lapic_id << 56) | (mode << 15) | (polarity << 14) |
|
||||
(vec & 0xFF) | flags;
|
||||
}
|
||||
|
||||
apic = amd64_ioapic_find (irq);
|
||||
|
||||
if (apic == NULL)
|
||||
return;
|
||||
|
||||
uint32_t irq_reg = ((irq - apic->gsi_base) * 2) + 0x10;
|
||||
|
||||
amd64_ioapic_write ((uintptr_t)hhdm->offset + (uintptr_t)apic->address,
|
||||
irq_reg, (uint32_t)calc_flags);
|
||||
|
||||
amd64_ioapic_write ((uintptr_t)hhdm->offset + (uintptr_t)apic->address,
|
||||
irq_reg + 1, (uint32_t)(calc_flags >> 32));
|
||||
}
|
||||
|
||||
void amd64_ioapic_mask (uint8_t irq) {
|
||||
struct acpi_madt_ioapic* apic;
|
||||
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
|
||||
|
||||
apic = amd64_ioapic_find (irq);
|
||||
|
||||
if (apic == NULL)
|
||||
return;
|
||||
|
||||
uint32_t irq_reg = ((irq - apic->gsi_base) * 2) + 0x10;
|
||||
|
||||
uint32_t value = amd64_ioapic_read (
|
||||
(uintptr_t)hhdm->offset + (uintptr_t)apic->address, irq_reg);
|
||||
amd64_ioapic_write ((uintptr_t)hhdm->offset + (uintptr_t)apic->address,
|
||||
irq_reg, value | (1 << 16));
|
||||
}
|
||||
|
||||
void amd64_ioapic_unmask (uint8_t irq) {
|
||||
struct acpi_madt_ioapic* apic;
|
||||
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
|
||||
|
||||
apic = amd64_ioapic_find (irq);
|
||||
|
||||
if (apic == NULL)
|
||||
return;
|
||||
|
||||
uint32_t irq_reg = ((irq - apic->gsi_base) * 2) + 0x10;
|
||||
|
||||
uint32_t value = amd64_ioapic_read (
|
||||
(uintptr_t)hhdm->offset + (uintptr_t)apic->address, irq_reg);
|
||||
amd64_ioapic_write ((uintptr_t)hhdm->offset + (uintptr_t)apic->address,
|
||||
irq_reg, value & ~(1 << 16));
|
||||
}
|
||||
|
||||
void amd64_ioapic_init (void) {
|
||||
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
|
||||
|
||||
struct uacpi_table apic_table;
|
||||
uacpi_status status =
|
||||
uacpi_table_find_by_signature (ACPI_MADT_SIGNATURE, &apic_table);
|
||||
if (status != UACPI_STATUS_OK) {
|
||||
DEBUG ("Could not find MADT table!\n");
|
||||
amd64_spin ();
|
||||
}
|
||||
|
||||
struct acpi_madt* apic = (struct acpi_madt*)apic_table.virt_addr;
|
||||
struct acpi_entry_hdr* current = (struct acpi_entry_hdr*)apic->entries;
|
||||
|
||||
for (;;) {
|
||||
if ((uintptr_t)current >= ((uintptr_t)apic->entries + apic->hdr.length -
|
||||
sizeof (struct acpi_madt)))
|
||||
break;
|
||||
|
||||
switch (current->type) {
|
||||
case ACPI_MADT_ENTRY_TYPE_IOAPIC: {
|
||||
struct acpi_madt_ioapic* ioapic = (struct acpi_madt_ioapic*)current;
|
||||
mm_map_kernel_page ((uintptr_t)ioapic->address,
|
||||
(uintptr_t)hhdm->offset + (uintptr_t)ioapic->address,
|
||||
MM_PG_USER | MM_PG_RW);
|
||||
apics[ioapic_entries++] = *ioapic;
|
||||
} break;
|
||||
case ACPI_MADT_ENTRY_TYPE_INTERRUPT_SOURCE_OVERRIDE: {
|
||||
struct acpi_madt_interrupt_source_override* override =
|
||||
(struct acpi_madt_interrupt_source_override*)current;
|
||||
intr_src_overrides[intr_src_override_entries++] = *override;
|
||||
} break;
|
||||
}
|
||||
|
||||
current = (struct acpi_entry_hdr*)((uintptr_t)current + current->length);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user