Clean up IOAPIC and LAPIC implementations
All checks were successful
Build documentation / build-and-deploy (push) Successful in 33s
All checks were successful
Build documentation / build-and-deploy (push) Successful in 33s
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include <amd64/msr.h>
|
||||
#include <libk/std.h>
|
||||
#include <limine/requests.h>
|
||||
#include <sync/spin_lock.h>
|
||||
#include <sys/debug.h>
|
||||
#include <sys/mm.h>
|
||||
#include <sys/spin.h>
|
||||
@@ -33,8 +34,14 @@
|
||||
/* Divide config register */
|
||||
#define LAPIC_DCR 0x3E0
|
||||
|
||||
struct ioapic {
|
||||
struct acpi_madt_ioapic table_data;
|
||||
spin_lock_t lock;
|
||||
uintptr_t mmio_base;
|
||||
};
|
||||
|
||||
/* Table of IOAPICS */
|
||||
static struct acpi_madt_ioapic apics[IOAPICS_MAX];
|
||||
static struct ioapic ioapics[IOAPICS_MAX];
|
||||
/* Table of interrupt source overrides */
|
||||
/* clang-format off */
|
||||
static struct acpi_madt_interrupt_source_override intr_src_overrides[INTERRUPT_SRC_OVERRIDES_MAX];
|
||||
@@ -43,33 +50,39 @@ static struct acpi_madt_interrupt_source_override intr_src_overrides[INTERRUPT_S
|
||||
static size_t ioapic_entries = 0;
|
||||
/* Count of actual interrupt source overrides */
|
||||
static size_t intr_src_override_entries = 0;
|
||||
/* Local APIC MMIO base address. It comes from MSR_APIC_BASE */
|
||||
static uintptr_t lapic_mmio_base = 0;
|
||||
|
||||
static uint64_t lapic_ticks;
|
||||
|
||||
/* Read IOAPIC */
|
||||
static uint32_t amd64_ioapic_read (uintptr_t vaddr, uint32_t reg) {
|
||||
*(volatile uint32_t*)vaddr = reg;
|
||||
return *(volatile uint32_t*)(vaddr + 0x10);
|
||||
static uint32_t amd64_ioapic_read (struct ioapic* ioapic, uint32_t reg) {
|
||||
spin_lock (&ioapic->lock);
|
||||
*(volatile uint32_t*)ioapic->mmio_base = reg;
|
||||
uint32_t ret = *(volatile uint32_t*)(ioapic->mmio_base + 0x10);
|
||||
spin_unlock (&ioapic->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Write IOAPIC */
|
||||
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 void amd64_ioapic_write (struct ioapic* ioapic, uint32_t reg, uint32_t value) {
|
||||
spin_lock (&ioapic->lock);
|
||||
*(volatile uint32_t*)ioapic->mmio_base = reg;
|
||||
*(volatile uint32_t*)(ioapic->mmio_base + 0x10) = value;
|
||||
spin_unlock (&ioapic->lock);
|
||||
}
|
||||
|
||||
/* Find an IOAPIC corresposting to provided IRQ */
|
||||
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;
|
||||
static struct ioapic* amd64_ioapic_find (uint8_t irq) {
|
||||
struct ioapic* ioapic = NULL;
|
||||
|
||||
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);
|
||||
ioapic = &ioapics[i];
|
||||
/* uint32_t version = amd64_ioapic_read ((uintptr_t)hhdm->offset +
|
||||
* (uintptr_t)ioapic->table_data.address, 1); */
|
||||
uint32_t version = amd64_ioapic_read (ioapic, 1);
|
||||
uint32_t max = ((version >> 16) & 0xFF);
|
||||
|
||||
if ((irq >= apic->gsi_base) && (irq <= (apic->gsi_base + max)))
|
||||
return apic;
|
||||
if ((irq >= ioapic->table_data.gsi_base) && (irq <= (ioapic->table_data.gsi_base + max)))
|
||||
return ioapic;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -85,10 +98,9 @@ static struct acpi_madt_ioapic* amd64_ioapic_find (uint8_t irq) {
|
||||
* lapic_id - Local APIC that will receive the interrupt.
|
||||
*/
|
||||
void amd64_ioapic_route_irq (uint8_t vec, uint8_t irq, uint64_t flags, uint64_t lapic_id) {
|
||||
struct acpi_madt_ioapic* apic = NULL;
|
||||
struct ioapic* ioapic = NULL;
|
||||
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];
|
||||
@@ -111,52 +123,15 @@ void amd64_ioapic_route_irq (uint8_t vec, uint8_t irq, uint64_t flags, uint64_t
|
||||
calc_flags |= flags;
|
||||
}
|
||||
|
||||
apic = amd64_ioapic_find (irq);
|
||||
ioapic = amd64_ioapic_find (irq);
|
||||
|
||||
if (apic == NULL)
|
||||
if (ioapic == NULL)
|
||||
return;
|
||||
|
||||
uint32_t irq_reg = ((irq - apic->gsi_base) * 2) + 0x10;
|
||||
uint32_t irq_reg = ((irq - ioapic->table_data.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));
|
||||
}
|
||||
|
||||
/* Mask a given IRQ */
|
||||
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));
|
||||
}
|
||||
|
||||
/* Unmask a given IRQ */
|
||||
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));
|
||||
amd64_ioapic_write (ioapic, irq_reg + 1, (uint32_t)(calc_flags >> 32));
|
||||
amd64_ioapic_write (ioapic, irq_reg, (uint32_t)calc_flags);
|
||||
}
|
||||
|
||||
/* Find and initialize the IOAPIC */
|
||||
@@ -180,11 +155,15 @@ void amd64_ioapic_init (void) {
|
||||
|
||||
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,
|
||||
struct acpi_madt_ioapic* ioapic_table_data = (struct acpi_madt_ioapic*)current;
|
||||
mm_map_kernel_page ((uintptr_t)ioapic_table_data->address,
|
||||
(uintptr_t)hhdm->offset + (uintptr_t)ioapic_table_data->address,
|
||||
MM_PG_PRESENT | MM_PG_RW | MM_PD_RELOAD);
|
||||
apics[ioapic_entries++] = *ioapic;
|
||||
ioapics[ioapic_entries++] = (struct ioapic){
|
||||
.lock = SPIN_LOCK_INIT,
|
||||
.table_data = *ioapic_table_data,
|
||||
.mmio_base = ((uintptr_t)hhdm->offset + (uintptr_t)ioapic_table_data->address),
|
||||
};
|
||||
} break;
|
||||
case ACPI_MADT_ENTRY_TYPE_INTERRUPT_SOURCE_OVERRIDE: {
|
||||
struct acpi_madt_interrupt_source_override* override =
|
||||
@@ -198,7 +177,7 @@ void amd64_ioapic_init (void) {
|
||||
}
|
||||
|
||||
/* Get MMIO base of Local APIC */
|
||||
static uintptr_t amd64_lapic_base (void) { return lapic_mmio_base; }
|
||||
static uintptr_t amd64_lapic_base (void) { return thiscpu->lapic_mmio_base; }
|
||||
|
||||
/* Write Local APIC */
|
||||
static void amd64_lapic_write (uint32_t reg, uint32_t value) {
|
||||
@@ -216,9 +195,6 @@ uint32_t amd64_lapic_id (void) { return amd64_lapic_read (LAPIC_ID) >> 24; }
|
||||
/* Send End of interrupt command to Local APIC */
|
||||
void amd64_lapic_eoi (void) { amd64_lapic_write (LAPIC_EOI, 0); }
|
||||
|
||||
/* Set initial counter value in Local APIC timer */
|
||||
void amd64_lapic_tick (uint32_t tick) { amd64_lapic_write (LAPIC_TIMICT, tick); }
|
||||
|
||||
/*
|
||||
* Calibrate Local APIC to send interrupts in a set interval.
|
||||
*
|
||||
@@ -255,24 +231,24 @@ static void amd64_lapic_start (uint32_t ticks) {
|
||||
* Initialize Local APIC, configure to send timer interrupts at a given period. See
|
||||
* amd64_lapic_calibrate and amd64_lapic_start.
|
||||
*/
|
||||
uint64_t amd64_lapic_init (uint32_t us) {
|
||||
void amd64_lapic_init (uint32_t us) {
|
||||
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
|
||||
|
||||
amd64_wrmsr (MSR_APIC_BASE, amd64_rdmsr (MSR_APIC_BASE) | (1 << 11));
|
||||
|
||||
uintptr_t lapic_paddr = amd64_rdmsr (MSR_APIC_BASE) & 0xFFFFF000;
|
||||
lapic_mmio_base = lapic_paddr + (uintptr_t)hhdm->offset;
|
||||
thiscpu->lapic_mmio_base = lapic_paddr + (uintptr_t)hhdm->offset;
|
||||
|
||||
mm_map_kernel_page (lapic_paddr, lapic_mmio_base,
|
||||
mm_map_kernel_page (lapic_paddr, thiscpu->lapic_mmio_base,
|
||||
MM_PG_PRESENT | MM_PG_RW | MM_PD_LOCK | MM_PD_RELOAD);
|
||||
|
||||
amd64_lapic_write (LAPIC_SIVR, 0xFF | (1 << 8));
|
||||
|
||||
uint32_t ticks = amd64_lapic_calibrate (us);
|
||||
if (thiscpu->id == 0) {
|
||||
lapic_ticks = amd64_lapic_calibrate (us);
|
||||
}
|
||||
|
||||
amd64_lapic_start (ticks);
|
||||
|
||||
return ticks;
|
||||
amd64_lapic_start (lapic_ticks);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -282,6 +258,11 @@ uint64_t amd64_lapic_init (uint32_t us) {
|
||||
* vec - Interrupt vector/IDT stub, which will be invoked by the IPI.
|
||||
*/
|
||||
void amd64_lapic_ipi (uint8_t lapic_id, uint8_t vec) {
|
||||
/* wait for previous IPI to finish */
|
||||
while (amd64_lapic_read (LAPIC_ICR) & (1 << 12)) {
|
||||
__asm__ volatile ("pause");
|
||||
}
|
||||
|
||||
amd64_lapic_write (LAPIC_ICR + 0x10, (lapic_id << 24));
|
||||
amd64_lapic_write (LAPIC_ICR, vec);
|
||||
}
|
||||
|
||||
@@ -4,14 +4,11 @@
|
||||
#include <libk/std.h>
|
||||
|
||||
void amd64_ioapic_route_irq (uint8_t vec, uint8_t irq, uint64_t flags, uint64_t lapic_id);
|
||||
void amd64_ioapic_mask (uint8_t irq);
|
||||
void amd64_ioapic_unmask (uint8_t irq);
|
||||
void amd64_ioapic_init (void);
|
||||
|
||||
uint32_t amd64_lapic_id (void);
|
||||
void amd64_lapic_tick (uint32_t tick);
|
||||
void amd64_lapic_eoi (void);
|
||||
void amd64_lapic_ipi (uint8_t lapic_id, uint8_t vec);
|
||||
uint64_t amd64_lapic_init (uint32_t us);
|
||||
void amd64_lapic_init (uint32_t us);
|
||||
|
||||
#endif // _KERNEL_AMD64_APIC_H
|
||||
|
||||
@@ -61,8 +61,7 @@ static void amd64_smp_bootstrap (struct limine_mp_info* mp_info) {
|
||||
amd64_init (cpu, true); /* gdt + idt */
|
||||
syscall_init ();
|
||||
|
||||
thiscpu->lapic_ticks = amd64_lapic_init (10000);
|
||||
amd64_lapic_tick (thiscpu->lapic_ticks);
|
||||
amd64_lapic_init (0);
|
||||
|
||||
DEBUG ("CPU %u is online!\n", thiscpu->id);
|
||||
|
||||
@@ -76,7 +75,7 @@ static void amd64_smp_bootstrap (struct limine_mp_info* mp_info) {
|
||||
|
||||
/// Initialize SMP subsystem for AMD64. Start AP CPUs
|
||||
void smp_init (void) {
|
||||
thiscpu->lapic_ticks = amd64_lapic_init (10000);
|
||||
amd64_lapic_init (10000);
|
||||
|
||||
struct limine_mp_response* mp = limine_mp_request.response;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ struct cpu {
|
||||
volatile struct gdt_extended gdt ALIGNED (16);
|
||||
volatile struct tss tss;
|
||||
|
||||
uint64_t lapic_ticks;
|
||||
uintptr_t lapic_mmio_base;
|
||||
uint32_t id;
|
||||
|
||||
struct {
|
||||
|
||||
Reference in New Issue
Block a user