AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
apic.c File Reference

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

Detailed Description

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.

  • Each CPU's local APIC is enabled, with the spurious vector 0xFF. Its LINT0 input (where the 8259s would come in) is masked, and the NMI comes on the LINT input the MADT says. Its timer is the scheduler's tick, periodic, calibrated once against the clock. The MADT's local APICs are the CPUs; the boot CPU starts the others with IPIs (cpu/smp.c).
  • The I/O APICs route the device interrupts. IRQ n goes to the pin that the MADT's overrides say (for the ISA IRQs: IRQ 0 is pin 2 on most machines), edge-triggered and active high unless they say otherwise. QEMU's pc overrides the PCI lines (from the devices' configuration space) as level-triggered. Every pin goes to the boot CPU with vector 32 + n, and stays masked until a handler is installed.
  • MSI (arch_msi_alloc()) gets an IRQ above the I/O APICs' pins. Its vector is in the message that the device writes to the local APIC.

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.

Macro Definition Documentation

◆ APIC_BASE_ENABLE

#define APIC_BASE_ENABLE   0x800

Definition at line 67 of file apic.c.

Referenced by x86_lapic_cpu_setup().

◆ ICR_PENDING

#define ICR_PENDING   0x1000

Definition at line 71 of file apic.c.

Referenced by x86_lapic_ipi().

◆ IOAPIC_REDIR

#define IOAPIC_REDIR ( n)
Value:
(0x10 + 2 * (n))

Definition at line 78 of file apic.c.

Referenced by apic_route(), and x86_apic_setup().

◆ IOAPIC_SEL

#define IOAPIC_SEL   0x00

Definition at line 75 of file apic.c.

Referenced by ioapic_read(), and ioapic_write().

◆ IOAPIC_VER

#define IOAPIC_VER   0x01

Definition at line 77 of file apic.c.

Referenced by x86_apic_setup().

◆ IOAPIC_WIN

#define IOAPIC_WIN   0x10

Definition at line 76 of file apic.c.

Referenced by ioapic_read(), and ioapic_write().

◆ IOAPICS_MAX

#define IOAPICS_MAX   4

Definition at line 84 of file apic.c.

Referenced by x86_apic_setup().

◆ LAPIC_EOI

#define LAPIC_EOI   0x0B0

Definition at line 49 of file apic.c.

Referenced by apic_eoi(), and x86_lapic_eoi().

◆ LAPIC_ICR_HI

#define LAPIC_ICR_HI   0x310

Definition at line 52 of file apic.c.

Referenced by x86_lapic_ipi().

◆ LAPIC_ICR_LO

#define LAPIC_ICR_LO   0x300

Definition at line 51 of file apic.c.

Referenced by x86_lapic_ipi().

◆ LAPIC_ID

#define LAPIC_ID   0x020

Definition at line 47 of file apic.c.

Referenced by x86_apic_setup().

◆ LAPIC_LVT_ERROR

#define LAPIC_LVT_ERROR   0x370

Definition at line 56 of file apic.c.

Referenced by x86_lapic_cpu_setup().

◆ LAPIC_LVT_LINT0

#define LAPIC_LVT_LINT0   0x350

Definition at line 54 of file apic.c.

Referenced by x86_lapic_cpu_setup().

◆ LAPIC_LVT_LINT1

#define LAPIC_LVT_LINT1   0x360

Definition at line 55 of file apic.c.

Referenced by x86_lapic_cpu_setup().

◆ LAPIC_LVT_TIMER

#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().

◆ LAPIC_SVR

#define LAPIC_SVR   0x0F0

Definition at line 50 of file apic.c.

Referenced by x86_lapic_cpu_setup().

◆ LAPIC_TIMER_CUR

#define LAPIC_TIMER_CUR   0x390

Definition at line 58 of file apic.c.

Referenced by timer_calibrate().

◆ LAPIC_TIMER_DIV

#define LAPIC_TIMER_DIV   0x3E0

Definition at line 59 of file apic.c.

Referenced by timer_calibrate(), and x86_lapic_timer_cpu_start().

◆ LAPIC_TIMER_INIT

#define LAPIC_TIMER_INIT   0x380

Definition at line 57 of file apic.c.

Referenced by timer_calibrate(), and x86_lapic_timer_cpu_start().

◆ LAPIC_TPR

#define LAPIC_TPR   0x080

Definition at line 48 of file apic.c.

Referenced by x86_lapic_cpu_setup().

◆ LVT_MASKED

#define LVT_MASKED   0x10000

Definition at line 62 of file apic.c.

Referenced by timer_calibrate(), and x86_lapic_cpu_setup().

◆ LVT_NMI

#define LVT_NMI   0x400

Definition at line 63 of file apic.c.

Referenced by x86_lapic_cpu_setup().

◆ LVT_PERIODIC

#define LVT_PERIODIC   0x20000

Definition at line 64 of file apic.c.

Referenced by x86_lapic_timer_cpu_start().

◆ REDIR_LEVEL

#define REDIR_LEVEL   0x8000

Definition at line 81 of file apic.c.

Referenced by apic_route().

◆ REDIR_LOW

#define REDIR_LOW   0x2000

Definition at line 82 of file apic.c.

Referenced by apic_route().

◆ REDIR_MASKED

#define REDIR_MASKED   0x10000

Definition at line 80 of file apic.c.

Referenced by apic_route(), and x86_apic_setup().

◆ SVR_ENABLE

#define SVR_ENABLE   0x100

Definition at line 61 of file apic.c.

Referenced by x86_lapic_cpu_setup().

◆ TIMER_DIV_16

#define TIMER_DIV_16   0x3

Definition at line 65 of file apic.c.

Referenced by timer_calibrate(), and x86_lapic_timer_cpu_start().

Function Documentation

◆ apic_describe()

const char * apic_describe ( unsigned irq)
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().

◆ apic_eoi()

void apic_eoi ( unsigned irq)
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().

◆ apic_mask()

void apic_mask ( unsigned irq)
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().

◆ apic_route()

void apic_route ( unsigned irq,
int masked )
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().

◆ apic_unmask()

void apic_unmask ( unsigned irq)
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().

◆ arch_msi_alloc()

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.

Parameters
handlerthe interrupt's handler
argthe argument the handler gets
addrset to the address the device writes the message to
dataset to the message
Returns
the IRQ, -ENODEV without the APIC (the 8259s take no MSI), or -ENOSPC if there's no free IRQ

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().

◆ cpu_has_apic()

int cpu_has_apic ( void )
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().

◆ ioapic_of()

struct ioapic * ioapic_of ( uint32_t gsi)
static

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().

◆ ioapic_read()

uint32_t ioapic_read ( struct ioapic * io,
uint32_t reg )
static

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().

◆ ioapic_write()

void ioapic_write ( struct ioapic * io,
uint32_t reg,
uint32_t val )
static

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().

◆ irq_gsi()

uint32_t irq_gsi ( unsigned irq,
int * level,
int * low )
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().

◆ lapic_read()

uint32_t lapic_read ( unsigned reg)
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().

◆ lapic_write()

void lapic_write ( unsigned reg,
uint32_t val )
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().

◆ msi_describe()

const char * msi_describe ( unsigned irq)
static

Describes an MSI's route, for /proc/interrupts.

Definition at line 247 of file apic.c.

References msi_describe().

Referenced by msi_describe().

◆ msi_nothing()

void msi_nothing ( unsigned irq)
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().

◆ timer_calibrate()

uint32_t timer_calibrate ( uint32_t ns)
static

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().

◆ x86_apic_cpus()

int x86_apic_cpus ( uint32_t * ids,
int max )

Lists the CPUs' local APIC IDs, the boot CPU's among them.

Parameters
idswhere to put them
maxhow many fit
Returns
how many there are, or 0 without the APIC

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().

◆ x86_apic_setup()

◆ x86_lapic_cpu_setup()

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().

◆ x86_lapic_eoi()

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().

◆ x86_lapic_ipi()

void x86_lapic_ipi ( uint32_t id,
uint32_t icr )

Sends an IPI to a CPU, and waits until it is delivered.

Parameters
idthe CPU's local APIC ID
icrthe 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().

◆ x86_lapic_timer_cpu_start()

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().

◆ 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.

Parameters
period_nsthe tick's period, in ns
handlerthe tick's handler
Returns
the period

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().

Variable Documentation

◆ apic_chip

struct x86_irq_chip apic_chip
static
Initial value:
= {
.name = "apic",
.mask = apic_mask,
.unmask = apic_unmask,
.eoi = apic_eoi,
.describe = apic_describe,
.timer = "lapic",
}
static void apic_eoi(unsigned irq)
Tells the local APIC that the interrupt is handled.
Definition apic.c:209
static void apic_unmask(unsigned irq)
Unmasks an IRQ at the I/O APIC.
Definition apic.c:202
static const char * apic_describe(unsigned irq)
Describes an IRQ's route, for /proc/interrupts.
Definition apic.c:222
static void apic_mask(unsigned irq)
Masks an IRQ at the I/O APIC.
Definition apic.c:195

Definition at line 231 of file apic.c.

Referenced by x86_apic_setup().

◆ cpu_ids

uint32_t cpu_ids[CPUS_MAX]
static

Definition at line 90 of file apic.c.

Referenced by x86_apic_cpus(), and x86_apic_setup().

◆ cpu_ids_nr

int cpu_ids_nr
static

Definition at line 91 of file apic.c.

Referenced by x86_apic_cpus(), and x86_apic_setup().

◆ ioapics

struct ioapic ioapics[IOAPICS_MAX]
static

Referenced by ioapic_of(), and x86_apic_setup().

◆ ioapics_nr

int ioapics_nr
static

Definition at line 101 of file apic.c.

Referenced by ioapic_of(), and x86_apic_setup().

◆ isa

struct [struct].isa isa[16]

Referenced by irq_gsi(), and x86_apic_setup().

◆ lapic

volatile uint32_t* lapic
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().

◆ lapic_id

uint32_t lapic_id
static

Definition at line 87 of file apic.c.

Referenced by apic_route(), arch_msi_alloc(), and x86_apic_setup().

◆ msi_chip

struct x86_irq_chip msi_chip
static
Initial value:
= {
.name = "msi",
.mask = msi_nothing,
.unmask = msi_nothing,
.eoi = apic_eoi,
.describe = msi_describe,
}
static const char * msi_describe(unsigned irq)
Describes an MSI's route, for /proc/interrupts.
Definition apic.c:247
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.
Definition apic.c:242

Definition at line 252 of file apic.c.

Referenced by arch_msi_alloc().

◆ nmi_lint

int nmi_lint = 1
static

Definition at line 94 of file apic.c.

Referenced by x86_apic_setup(), and x86_lapic_cpu_setup().

◆ routes

struct [struct].routes routes[X86_IRQ_NR]

Referenced by apic_describe(), and apic_route().

◆ timer_count

uint32_t timer_count
static

Definition at line 116 of file apic.c.

Referenced by x86_lapic_timer_cpu_start(), and x86_lapic_timer_setup().