Advanced Programmable Interrupt Controller (APIC) and IO APIC
This is implemented in
apic
.
The APIC is a part of the CPU, and it is used to manage interrupts and exceptions. It is used to manage the interrupts and exceptions that are triggered by hardware devices, and it is also used to manage the interrupts and exceptions that are triggered by the CPU itself.
Initialization
The initialization of the APIC
is done using ACPI tables,
which contains data about the ACPI, such as:
- Number of CPUs.
- The APIC ID of each CPU.
- The address of the
IO APIC
.
The APIC
is a memory-mapped address provided by the CPU, we can fetch it by reading the MSR
register 0x1B
(which is the APIC_BASE
register).
Then we can map the APIC
and IOAPIC
(also memory-mapped) addresses to the virtual address space using virtual space.
Interrupts
The APIC
can be used to allocate and assign interrupts to hardware devices. We can use the functions:
assign_io_irq
to assign an interrupt to a hardware device.assign_io_irq_custom
which is similar to the above but provide extra changes to the interrupt, such as:with_interrupt_polarity_low
: Set the interrupt polarity to low/high (boolean).with_trigger_mode_level
: Set the trigger mode to level/edge (boolean).with_mask
: Set the interrupt to be masked or not (boolean).
It will set up the interrupts with the correct IO APIC
based on the argument irq_num
provided.
Currently, we have these interrupts configured:
1
: Used by the keyboard driver.14 & 15
: Used by the IDE driver.- HPET timer, with interrupt number specified dynamically based on its configuration,
but looks to be
2
on the VM.
We also have interrupts from the APIC
itself, such as:
- Timer interrupt: this is used by the scheduler to switch between processes.
- Error interrupt: This is mapped, but haven't seen it triggered yet.
- Spurious interrupt: This is mapped, but haven't seen it triggered yet.