|
AquilaOS documentation
How it works, and its code
|
x86: the APIC, the local APICs and the I/O APICs. More...
#include <core/system.h>#include <core/arch.h>#include <core/kargs.h>#include <core/string.h>#include <cpu/cpu.h>#include <cpu/msr.h>#include <cpu/sdt.h>#include <platform/misc.h>#include <sys/cpu.h>Go to the source code of this file.
Data Structures | |
| struct | ioapic |
| struct | [struct].isa |
| struct | [struct].routes |
Macros | |
| #define | LAPIC_ID 0x020 |
| #define | LAPIC_TPR 0x080 |
| #define | LAPIC_EOI 0x0B0 |
| #define | LAPIC_SVR 0x0F0 |
| #define | LAPIC_ICR_LO 0x300 |
| #define | LAPIC_ICR_HI 0x310 |
| #define | LAPIC_LVT_TIMER 0x320 |
| #define | LAPIC_LVT_LINT0 0x350 |
| #define | LAPIC_LVT_LINT1 0x360 |
| #define | LAPIC_LVT_ERROR 0x370 |
| #define | LAPIC_TIMER_INIT 0x380 |
| #define | LAPIC_TIMER_CUR 0x390 |
| #define | LAPIC_TIMER_DIV 0x3E0 |
| #define | SVR_ENABLE 0x100 |
| #define | LVT_MASKED 0x10000 |
| #define | LVT_NMI 0x400 |
| #define | LVT_PERIODIC 0x20000 |
| #define | TIMER_DIV_16 0x3 |
| #define | APIC_BASE_ENABLE 0x800 |
| #define | ICR_PENDING 0x1000 |
| #define | IOAPIC_SEL 0x00 |
| #define | IOAPIC_WIN 0x10 |
| #define | IOAPIC_VER 0x01 |
| #define | IOAPIC_REDIR(n) |
| #define | REDIR_MASKED 0x10000 |
| #define | REDIR_LEVEL 0x8000 |
| #define | REDIR_LOW 0x2000 |
| #define | IOAPICS_MAX 4 |
Functions | |
| static uint32_t | lapic_read (unsigned reg) |
| Reads a register of the running CPU's local APIC (every CPU sees its own local APIC at the same address). | |
| static void | lapic_write (unsigned reg, uint32_t val) |
| Writes a register of the running CPU's local APIC. | |
| static struct ioapic * | ioapic_of (uint32_t gsi) |
| Returns the I/O APIC that has the pin of gsi, or NULL if none has. | |
| static uint32_t | ioapic_read (struct ioapic *io, uint32_t reg) |
| Reads an I/O APIC register. | |
| static void | ioapic_write (struct ioapic *io, uint32_t reg, uint32_t val) |
| Writes an I/O APIC register. | |
| static uint32_t | irq_gsi (unsigned irq, int *level, int *low) |
| Returns the GSI (the pin) that IRQ irq comes on, and sets how it is triggered. | |
| static void | apic_route (unsigned irq, int masked) |
| Routes IRQ irq to the boot CPU, with vector 32 + irq, masked or not. | |
| static void | apic_mask (unsigned irq) |
| Masks an IRQ at the I/O APIC. | |
| static void | apic_unmask (unsigned irq) |
| Unmasks an IRQ at the I/O APIC. | |
| static void | apic_eoi (unsigned irq) |
| Tells the local APIC that the interrupt is handled. | |
| void | x86_lapic_eoi (void) |
| Tells the running CPU's local APIC that its interrupt (an IPI) is handled. | |
| static const char * | apic_describe (unsigned irq) |
| Describes an IRQ's route, for /proc/interrupts. | |
| static void | msi_nothing (unsigned irq) |
| Does nothing: an MSI is masked at the device (pci.c), not here; its EOI is the local APIC's. | |
| static const char * | msi_describe (unsigned irq) |
| Describes an MSI's route, for /proc/interrupts. | |
| int | arch_msi_alloc (irq_handler_t handler, void *arg, uint64_t *addr, uint32_t *data) |
| Gets an IRQ for a device's MSI, and installs its handler. | |
| static int | cpu_has_apic (void) |
| Returns whether the CPU has a local APIC (CPUID 1, EDX bit 9). | |
| void | x86_lapic_cpu_setup (void) |
| Sets up the running CPU's local APIC: enabled, with the spurious vector 0xFF, its timer off, the NMI on the LINT input the MADT says, and the other LINT (the 8259s') masked. | |
| int | x86_apic_cpus (uint32_t *ids, int max) |
| Lists the CPUs' local APIC IDs, the boot CPU's among them. | |
| void | x86_lapic_ipi (uint32_t id, uint32_t icr) |
| Sends an IPI to a CPU, and waits until it is delivered. | |
| int | x86_apic_setup (void) |
| Sets up the APIC to bring the interrupts, if the CPU has one, the MADT describes it, and the kernel's command line doesn't say apic=off. | |
| static uint32_t | timer_calibrate (uint32_t ns) |
| Measures how many counts the local APIC's timer makes in ns nanoseconds (with its clock divided by 16), against the clock if it is precise, else with the PIT. | |
| uint32_t | x86_lapic_timer_setup (uint32_t period_ns, irq_handler_t handler) |
| Starts the scheduler's tick with the local APIC's timer, calibrated first. | |
| void | x86_lapic_timer_cpu_start (void) |
| Starts the running CPU's local APIC timer, with the boot CPU's calibration, once it has been done. | |
Variables | |
| static volatile uint32_t * | lapic |
| static uint32_t | lapic_id |
| static uint32_t | cpu_ids [CPUS_MAX] |
| static int | cpu_ids_nr |
| static int | nmi_lint = 1 |
| static struct ioapic | ioapics [IOAPICS_MAX] |
| static int | ioapics_nr |
| static struct | isa [16] |
| static struct | routes [X86_IRQ_NR] |
| static uint32_t | timer_count |
| static struct x86_irq_chip | apic_chip |
| static struct x86_irq_chip | msi_chip |
x86: the APIC, the local APICs and the I/O APICs.
When the CPU has an APIC and ACPI's MADT says where its parts are, the APIC brings the interrupts (an x86_irq_chip, see irq.c); with apic=off, the 8259s do.
A PCI device's interrupt line, in its configuration space, is an ISA IRQ: QEMU's chipsets (pc and q35) work that way. A machine whose PCI interrupts only come on the I/O APIC's pins past 15 would need ACPI's _PRT; a device with MSI doesn't.
References: [1] - Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 3, Chapter 11 (APIC) [2] - 82093AA I/O Advanced Programmable Interrupt Controller (IOAPIC), Intel [3] - ACPI Specification, 5.2.12 (MADT)
Definition in file apic.c.
| #define APIC_BASE_ENABLE 0x800 |
Definition at line 67 of file apic.c.
Referenced by x86_lapic_cpu_setup().
| #define ICR_PENDING 0x1000 |
Definition at line 71 of file apic.c.
Referenced by x86_lapic_ipi().
| #define IOAPIC_REDIR | ( | n | ) |
Definition at line 78 of file apic.c.
Referenced by apic_route(), and x86_apic_setup().
| #define IOAPIC_SEL 0x00 |
Definition at line 75 of file apic.c.
Referenced by ioapic_read(), and ioapic_write().
| #define IOAPIC_VER 0x01 |
Definition at line 77 of file apic.c.
Referenced by x86_apic_setup().
| #define IOAPIC_WIN 0x10 |
Definition at line 76 of file apic.c.
Referenced by ioapic_read(), and ioapic_write().
| #define IOAPICS_MAX 4 |
Definition at line 84 of file apic.c.
Referenced by x86_apic_setup().
| #define LAPIC_EOI 0x0B0 |
Definition at line 49 of file apic.c.
Referenced by apic_eoi(), and x86_lapic_eoi().
| #define LAPIC_ICR_HI 0x310 |
Definition at line 52 of file apic.c.
Referenced by x86_lapic_ipi().
| #define LAPIC_ICR_LO 0x300 |
Definition at line 51 of file apic.c.
Referenced by x86_lapic_ipi().
| #define LAPIC_ID 0x020 |
Definition at line 47 of file apic.c.
Referenced by x86_apic_setup().
| #define LAPIC_LVT_ERROR 0x370 |
Definition at line 56 of file apic.c.
Referenced by x86_lapic_cpu_setup().
| #define LAPIC_LVT_LINT0 0x350 |
Definition at line 54 of file apic.c.
Referenced by x86_lapic_cpu_setup().
| #define LAPIC_LVT_LINT1 0x360 |
Definition at line 55 of file apic.c.
Referenced by x86_lapic_cpu_setup().
| #define LAPIC_LVT_TIMER 0x320 |
Definition at line 53 of file apic.c.
Referenced by timer_calibrate(), x86_lapic_cpu_setup(), and x86_lapic_timer_cpu_start().
| #define LAPIC_SVR 0x0F0 |
Definition at line 50 of file apic.c.
Referenced by x86_lapic_cpu_setup().
| #define LAPIC_TIMER_CUR 0x390 |
Definition at line 58 of file apic.c.
Referenced by timer_calibrate().
| #define LAPIC_TIMER_DIV 0x3E0 |
Definition at line 59 of file apic.c.
Referenced by timer_calibrate(), and x86_lapic_timer_cpu_start().
| #define LAPIC_TIMER_INIT 0x380 |
Definition at line 57 of file apic.c.
Referenced by timer_calibrate(), and x86_lapic_timer_cpu_start().
| #define LAPIC_TPR 0x080 |
Definition at line 48 of file apic.c.
Referenced by x86_lapic_cpu_setup().
| #define LVT_MASKED 0x10000 |
Definition at line 62 of file apic.c.
Referenced by timer_calibrate(), and x86_lapic_cpu_setup().
| #define LVT_NMI 0x400 |
Definition at line 63 of file apic.c.
Referenced by x86_lapic_cpu_setup().
| #define LVT_PERIODIC 0x20000 |
Definition at line 64 of file apic.c.
Referenced by x86_lapic_timer_cpu_start().
| #define REDIR_LEVEL 0x8000 |
Definition at line 81 of file apic.c.
Referenced by apic_route().
| #define REDIR_LOW 0x2000 |
Definition at line 82 of file apic.c.
Referenced by apic_route().
| #define REDIR_MASKED 0x10000 |
Definition at line 80 of file apic.c.
Referenced by apic_route(), and x86_apic_setup().
| #define SVR_ENABLE 0x100 |
Definition at line 61 of file apic.c.
Referenced by x86_lapic_cpu_setup().
| #define TIMER_DIV_16 0x3 |
Definition at line 65 of file apic.c.
Referenced by timer_calibrate(), and x86_lapic_timer_cpu_start().
|
static |
Describes an IRQ's route, for /proc/interrupts.
Definition at line 222 of file apic.c.
References apic_describe(), routes, and snprintf().
Referenced by apic_describe().
|
static |
Tells the local APIC that the interrupt is handled.
Definition at line 209 of file apic.c.
References apic_eoi(), LAPIC_EOI, and lapic_write().
Referenced by apic_eoi().
|
static |
Masks an IRQ at the I/O APIC.
Definition at line 195 of file apic.c.
References apic_mask(), apic_route(), and X86_IRQ_TIMER.
Referenced by apic_mask().
|
static |
Routes IRQ irq to the boot CPU, with vector 32 + irq, masked or not.
Definition at line 172 of file apic.c.
References apic_route(), ioapic::gsi_base, ioapic_of(), IOAPIC_REDIR, ioapic_write(), irq_gsi(), lapic_id, printk(), REDIR_LEVEL, REDIR_LOW, REDIR_MASKED, and routes.
Referenced by apic_mask(), apic_route(), and apic_unmask().
|
static |
Unmasks an IRQ at the I/O APIC.
Definition at line 202 of file apic.c.
References apic_route(), apic_unmask(), and X86_IRQ_TIMER.
Referenced by apic_unmask().
| int arch_msi_alloc | ( | irq_handler_t | handler, |
| void * | arg, | ||
| uint64_t * | addr, | ||
| uint32_t * | data ) |
Gets an IRQ for a device's MSI, and installs its handler.
The message goes to the boot CPU's local APIC, with the IRQ's vector, edge-triggered.
| handler | the interrupt's handler |
| arg | the argument the handler gets |
| addr | set to the address the device writes the message to |
| data | set to the message |
Definition at line 271 of file apic.c.
References arch_msi_alloc(), irq_install(), lapic, lapic_id, msi_chip, and x86_irq_alloc().
Referenced by arch_msi_alloc(), and pci_msi_enable().
|
static |
Returns whether the CPU has a local APIC (CPUID 1, EDX bit 9).
Definition at line 292 of file apic.c.
References cpu_has_apic().
Referenced by cpu_has_apic(), and x86_apic_setup().
Returns the I/O APIC that has the pin of gsi, or NULL if none has.
Definition at line 132 of file apic.c.
References ioapic::gsi_base, ioapic_of(), ioapics, ioapics_nr, NULL, and ioapic::pins.
Referenced by apic_route(), and ioapic_of().
Reads an I/O APIC register.
Definition at line 142 of file apic.c.
References ioapic_read(), IOAPIC_SEL, IOAPIC_WIN, and ioapic::regs.
Referenced by ioapic_read(), and x86_apic_setup().
Writes an I/O APIC register.
Definition at line 149 of file apic.c.
References IOAPIC_SEL, IOAPIC_WIN, ioapic_write(), and ioapic::regs.
Referenced by apic_route(), ioapic_write(), and x86_apic_setup().
|
static |
Returns the GSI (the pin) that IRQ irq comes on, and sets how it is triggered.
Definition at line 157 of file apic.c.
References ACPI_MPS_POLARITY_LOW, ACPI_MPS_POLARITY_MASK, ACPI_MPS_TRIGGER_LEVEL, ACPI_MPS_TRIGGER_MASK, irq_gsi(), and isa.
Referenced by apic_route(), and irq_gsi().
|
inlinestatic |
Reads a register of the running CPU's local APIC (every CPU sees its own local APIC at the same address).
Definition at line 120 of file apic.c.
References lapic, and lapic_read().
Referenced by lapic_read(), timer_calibrate(), x86_apic_setup(), and x86_lapic_ipi().
|
inlinestatic |
Writes a register of the running CPU's local APIC.
Definition at line 126 of file apic.c.
References lapic, and lapic_write().
Referenced by apic_eoi(), lapic_write(), timer_calibrate(), x86_lapic_cpu_setup(), x86_lapic_eoi(), x86_lapic_ipi(), and x86_lapic_timer_cpu_start().
|
static |
Describes an MSI's route, for /proc/interrupts.
Definition at line 247 of file apic.c.
References msi_describe().
Referenced by msi_describe().
|
static |
Does nothing: an MSI is masked at the device (pci.c), not here; its EOI is the local APIC's.
Definition at line 242 of file apic.c.
References msi_nothing().
Referenced by msi_nothing().
Measures how many counts the local APIC's timer makes in ns nanoseconds (with its clock divided by 16), against the clock if it is precise, else with the PIT.
Definition at line 481 of file apic.c.
References arch_rtime_ns(), LAPIC_LVT_TIMER, lapic_read(), LAPIC_TIMER_CUR, LAPIC_TIMER_DIV, LAPIC_TIMER_INIT, lapic_write(), LVT_MASKED, timer_calibrate(), TIMER_DIV_16, x86_clock_precise(), and x86_pit_delay().
Referenced by timer_calibrate(), and x86_lapic_timer_setup().
| int x86_apic_cpus | ( | uint32_t * | ids, |
| int | max ) |
Lists the CPUs' local APIC IDs, the boot CPU's among them.
| ids | where to put them |
| max | how many fit |
Definition at line 322 of file apic.c.
References cpu_ids, cpu_ids_nr, lapic, MIN, and x86_apic_cpus().
Referenced by x86_apic_cpus(), and x86_smp_init().
| int x86_apic_setup | ( | void | ) |
Sets up the APIC to bring the interrupts, if the CPU has one, the MADT describes it, and the kernel's command line doesn't say apic=off.
Definition at line 359 of file apic.c.
References ACPI_MADT_ENABLED, ACPI_MADT_INT_SRC_OVERRIDE, ACPI_MADT_IO_APIC, ACPI_MADT_LOCAL_APIC, ACPI_MADT_LOCAL_APIC_NMI, ACPI_MPS_TRIGGER_LEVEL, ACPI_MPS_TRIGGER_MASK, acpi_madt_io_apic::address, ioapic::address, apic_chip, acpi_madt_local_apic::apic_id, arch_cpu::apic_id, cpu::arch, arch_mmio_map(), acpi_madt_override::bus, cpu_has_apic(), cpu_ids, cpu_ids_nr, cpus, CPUS_MAX, acpi_madt_local_apic::flags, acpi_madt_local_apic_nmi::flags, acpi_madt_override::flags, acpi_madt_override::gsi, acpi_madt_io_apic::gsi_base, ioapic::gsi_base, acpi_madt::header, ioapic_read(), IOAPIC_REDIR, IOAPIC_VER, ioapic_write(), ioapics, IOAPICS_MAX, ioapics_nr, isa, kargs_get(), lapic, LAPIC_ID, lapic_id, lapic_read(), acpi_sdt_header::length, acpi_madt_local_apic_nmi::lint, acpi_madt::local_apic_address, nmi_lint, NULL, ioapic::pins, printk(), REDIR_MASKED, ioapic::regs, acpi_madt_override::source, x86_acpi_table(), x86_apic_setup(), x86_irq_alloc_from(), x86_irq_chip_set(), x86_lapic_cpu_setup(), and x86_pic_disable().
Referenced by x86_apic_setup(), and x86_pc_irq_init().
| void x86_lapic_cpu_setup | ( | void | ) |
Sets up the running CPU's local APIC: enabled, with the spurious vector 0xFF, its timer off, the NMI on the LINT input the MADT says, and the other LINT (the 8259s') masked.
Definition at line 303 of file apic.c.
References APIC_BASE, APIC_BASE_ENABLE, LAPIC_LVT_ERROR, LAPIC_LVT_LINT0, LAPIC_LVT_LINT1, LAPIC_LVT_TIMER, LAPIC_SVR, LAPIC_TPR, lapic_write(), LVT_MASKED, LVT_NMI, nmi_lint, SVR_ENABLE, x86_lapic_cpu_setup(), and X86_SPURIOUS_VECTOR.
Referenced by x86_ap_start(), x86_apic_setup(), and x86_lapic_cpu_setup().
| void x86_lapic_eoi | ( | void | ) |
Tells the running CPU's local APIC that its interrupt (an IPI) is handled.
Definition at line 216 of file apic.c.
References LAPIC_EOI, lapic_write(), and x86_lapic_eoi().
Referenced by __x86_irq_handler(), and x86_lapic_eoi().
Sends an IPI to a CPU, and waits until it is delivered.
| id | the CPU's local APIC ID |
| icr | the low half of the interrupt command register: the delivery mode, the vector, and so on |
Definition at line 342 of file apic.c.
References ICR_PENDING, LAPIC_ICR_HI, LAPIC_ICR_LO, lapic_read(), lapic_write(), and x86_lapic_ipi().
Referenced by ap_boot(), arch_cpu_kick(), tlb_shootdown(), and x86_lapic_ipi().
| void x86_lapic_timer_cpu_start | ( | void | ) |
Starts the running CPU's local APIC timer, with the boot CPU's calibration, once it has been done.
Definition at line 529 of file apic.c.
References LAPIC_LVT_TIMER, LAPIC_TIMER_DIV, LAPIC_TIMER_INIT, lapic_write(), LVT_PERIODIC, timer_count, TIMER_DIV_16, x86_lapic_timer_cpu_start(), and X86_TIMER_VECTOR.
Referenced by __x86_irq_handler(), x86_lapic_timer_cpu_start(), and x86_lapic_timer_setup().
| uint32_t x86_lapic_timer_setup | ( | uint32_t | period_ns, |
| irq_handler_t | handler ) |
Starts the scheduler's tick with the local APIC's timer, calibrated first.
| period_ns | the tick's period, in ns |
| handler | the tick's handler |
Definition at line 512 of file apic.c.
References irq_install(), NULL, printk(), timer_calibrate(), timer_count, X86_IRQ_TIMER, x86_lapic_timer_cpu_start(), and x86_lapic_timer_setup().
Referenced by platform_timer_setup(), and x86_lapic_timer_setup().
|
static |
Definition at line 231 of file apic.c.
Referenced by x86_apic_setup().
Definition at line 90 of file apic.c.
Referenced by x86_apic_cpus(), and x86_apic_setup().
|
static |
Definition at line 91 of file apic.c.
Referenced by x86_apic_cpus(), and x86_apic_setup().
|
static |
Referenced by ioapic_of(), and x86_apic_setup().
|
static |
Definition at line 101 of file apic.c.
Referenced by ioapic_of(), and x86_apic_setup().
| struct [struct].isa isa[16] |
Referenced by irq_gsi(), and x86_apic_setup().
|
static |
Definition at line 86 of file apic.c.
Referenced by arch_msi_alloc(), lapic_read(), lapic_write(), x86_apic_cpus(), and x86_apic_setup().
|
static |
Definition at line 87 of file apic.c.
Referenced by apic_route(), arch_msi_alloc(), and x86_apic_setup().
|
static |
Definition at line 252 of file apic.c.
Referenced by arch_msi_alloc().
|
static |
Definition at line 94 of file apic.c.
Referenced by x86_apic_setup(), and x86_lapic_cpu_setup().
| struct [struct].routes routes[X86_IRQ_NR] |
Referenced by apic_describe(), and apic_route().
|
static |
Definition at line 116 of file apic.c.
Referenced by x86_lapic_timer_cpu_start(), and x86_lapic_timer_setup().