#include #include #include #include #define LAPIC_REG_EOI 0xB0 namespace arch::acpi { static local_apic lapic; local_apic::local_apic(uint32_t *base) : base_(base) { } kern_status_t local_apic::find(struct acpi_madt *madt, local_apic& out) { phys_addr_t local_apic = madt->m_lapic_ptr; unsigned char *p = (unsigned char *)madt + sizeof *madt; unsigned char *madt_end = (unsigned char *)madt + madt->m_base.s_length; while (p < madt_end) { struct acpi_madt_record *rec = (struct acpi_madt_record *)p; struct lapic_override_record *lapic; switch (rec->r_type) { case ACPI_MADT_LAPIC_OVERRIDE: lapic = (struct lapic_override_record *)(rec + 1); out.base_ = (uint32_t *)vm_phys_to_virt(lapic->l_lapic_ptr); return KERN_OK; default: break; } p += rec->r_length; } out.base_ = (uint32_t *)vm_phys_to_virt(local_apic); return KERN_OK; } uint32_t local_apic::read(uint32_t reg) { return read_once(base_ + (reg >> 2)); } void local_apic::write(uint32_t reg, uint32_t val) { write_once(base_ + (reg >> 2), val); } void local_apic::ack() { write(LAPIC_REG_EOI, 0); } void local_apic::send_ipi(unsigned int dest, unsigned int data) { uint32_t dest_val = (read(IPI_DEST) & 0x00FFFFFF) | (dest << 24); write(IPI_STATUS, 0); write(IPI_DEST, dest_val); uint32_t icr_val = (read(IPI_ICR) & 0xFFF00000) | data; write(IPI_ICR, icr_val); do { __asm__ __volatile__("pause" : : : "memory"); } while (read(IPI_ICR) & (1 << 12)); } local_apic& local_apic::get(void) { return lapic; } }