4 * @brief Abstraction for Advanced Programmable Interrupts Controller (APIC)
8 * @copyright Copyright (c) 2022
16 #include <arch/x86/interrupts.h>
18 #include <lunaix/spike.h>
19 #include <lunaix/syslog.h>
29 // ensure that external interrupt is disabled
30 cpu_disable_interrupt();
32 // Make sure the APIC is there
33 // FUTURE: Use 8259 as fallback
34 assert_msg(cpu_has_apic(), "No APIC detected!");
36 // As we are going to use APIC, disable the old 8259 PIC
39 // Hardware enable the APIC
40 // By setting bit 11 of IA32_APIC_BASE register
41 // Note: After this point, you can't disable then re-enable it until a reset (i.e., reboot)
47 ::"i"(IA32_APIC_BASE_MSR), "i"(IA32_APIC_ENABLE)
51 // Print the basic information of our current local APIC
52 uint32_t apic_id = apic_read_reg(APIC_IDR) >> 24;
53 uint32_t apic_ver = apic_read_reg(APIC_VER);
55 kprintf(KINFO "ID: %x, Version: %x, Max LVT: %u\n",
58 (apic_ver >> 16) & 0xff);
60 // initialize the local vector table (LVT)
63 // initialize priority registers
65 // set the task priority to the lowest possible, so all external interrupts are acceptable
66 // Note, the lowest possible priority class is 2, not 0, 1, as they are reserved for
67 // internal interrupts (vector 0-31, and each p-class resposible for 16 vectors).
68 // See Intel Manual Vol. 3A, 10-29
69 apic_write_reg(APIC_TPR, APIC_PRIORITY(2, 0));
72 uint32_t spiv = apic_read_reg(APIC_SPIVR);
74 // install our handler for spurious interrupt.
75 spiv = (spiv & ~0xff) | APIC_SPIV_APIC_ENABLE | APIC_SPIV_IV;
76 apic_write_reg(APIC_SPIVR, spiv);
79 #define LVT_ENTRY_LINT0(vector) (LVT_DELIVERY_FIXED | vector)
81 // Pin LINT#1 is configured for relaying NMI, but we masked it here as I think
82 // it is too early for that
83 // LINT#1 *must* be edge trigged (Intel manual vol3. 10-14)
84 #define LVT_ENTRY_LINT1 (LVT_DELIVERY_NMI | LVT_MASKED | LVT_TRIGGER_EDGE)
85 #define LVT_ENTRY_ERROR(vector) (LVT_DELIVERY_FIXED | vector)
90 apic_write_reg(APIC_LVT_LINT0, LVT_ENTRY_LINT0(APIC_LINT0_IV));
91 apic_write_reg(APIC_LVT_LINT1, LVT_ENTRY_LINT1);
92 apic_write_reg(APIC_LVT_ERROR, LVT_ENTRY_ERROR(APIC_ERROR_IV));