48#define LAPIC_TPR 0x080
49#define LAPIC_EOI 0x0B0
50#define LAPIC_SVR 0x0F0
51#define LAPIC_ICR_LO 0x300
52#define LAPIC_ICR_HI 0x310
53#define LAPIC_LVT_TIMER 0x320
54#define LAPIC_LVT_LINT0 0x350
55#define LAPIC_LVT_LINT1 0x360
56#define LAPIC_LVT_ERROR 0x370
57#define LAPIC_TIMER_INIT 0x380
58#define LAPIC_TIMER_CUR 0x390
59#define LAPIC_TIMER_DIV 0x3E0
61#define SVR_ENABLE 0x100
62#define LVT_MASKED 0x10000
64#define LVT_PERIODIC 0x20000
65#define TIMER_DIV_16 0x3
67#define APIC_BASE_ENABLE 0x800
71#define ICR_PENDING 0x1000
75#define IOAPIC_SEL 0x00
76#define IOAPIC_WIN 0x10
77#define IOAPIC_VER 0x01
78#define IOAPIC_REDIR(n) (0x10 + 2 * (n))
80#define REDIR_MASKED 0x10000
81#define REDIR_LEVEL 0x8000
82#define REDIR_LOW 0x2000
122 return lapic[reg / 4];
128 lapic[reg / 4] = val;
179 printk(
"apic: IRQ %d: no I/O APIC has GSI %d\n", irq, gsi);
191 routes[irq].level = level;
227 routes[irq].level ?
"level" :
"edge");
296 asm volatile(
"cpuid" :
"=a"(a),
"=b"(b),
"=c"(c),
"=d"(d) :
"a"(1),
"c"(0));
297 return !!(d & (1 << 9));
329 for (
int i = 0; i < n; ++i)
361 const char *arg =
NULL;
363 if (!
kargs_get(
"apic", &arg) && arg && !strcmp(arg,
"off")) {
364 printk(
"apic: off (apic=off)\n");
371 printk(
"apic: %s\n", madt ?
"the CPU has none" :
"no MADT");
377 for (
int i = 0; i < 16; ++i) {
384 for (; p + 2 <= end && p[1] >= 2; p += p[1]) {
430 printk(
"apic: no I/O APIC\n");
439 printk(
"apic: no room to map the local APIC\n");
466 printk(
"apic: local APIC %d at %p, %d I/O APIC(s), the first at %p (GSI %d, %d pins)\n",
470 for (
int i = 0; i < 16; ++i)
472 printk(
"apic: IRQ %d is GSI %d%s\n", i,
isa[i].gsi,
523 printk(
"apic: the timer every %d ns (%d counts, divided by 16)\n", period_ns,
timer_count);
537 curcpu()->arch.ticking = 1;
static void ioapic_write(struct ioapic *io, uint32_t reg, uint32_t val)
Writes an I/O APIC register.
static struct x86_irq_chip apic_chip
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_eoi(unsigned irq)
Tells the local APIC that the interrupt is handled.
static struct @321312313052114036106345344076272057075275236024 isa[16]
static volatile uint32_t * lapic
static void apic_unmask(unsigned irq)
Unmasks an IRQ at the I/O APIC.
static const char * msi_describe(unsigned irq)
Describes an MSI's route, for /proc/interrupts.
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...
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 struct ioapic ioapics[IOAPICS_MAX]
static void lapic_write(unsigned reg, uint32_t val)
Writes a register of the running CPU's local APIC.
static struct x86_irq_chip msi_chip
static const char * apic_describe(unsigned irq)
Describes an IRQ's route, for /proc/interrupts.
static struct ioapic * ioapic_of(uint32_t gsi)
Returns the I/O APIC that has the pin of gsi, or NULL if none has.
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 void apic_mask(unsigned irq)
Masks an IRQ at the I/O APIC.
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 addre...
static uint32_t cpu_ids[CPUS_MAX]
static struct @043132035040270321265025034232135147174332372073 routes[X86_IRQ_NR]
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 uint32_t timer_count
static int cpu_has_apic(void)
Returns whether the CPU has a local APIC (CPUID 1, EDX bit 9).
static uint32_t ioapic_read(struct ioapic *io, uint32_t reg)
Reads an I/O APIC register.
struct cpu cpus[CPUS_MAX]
void(*) irq_handler_t(void *arg)
int kargs_get(const char *key, const char **value)
Looks up an argument of the kernel's command line.
void x86_pic_disable(void)
Masks every IRQ of the 8259s, when the APIC brings the interrupts.
int x86_clock_precise(void)
Says whether the clock counts finer than the ticks.
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.
int x86_irq_alloc(struct x86_irq_chip *chip)
Gives a free IRQ with a controller of its own, for an MSI.
void x86_lapic_eoi(void)
Tells the running CPU's local APIC that its interrupt (an IPI) is handled.
void * x86_acpi_table(const char *signature)
Finds one of ACPI's tables, by its signature.
void x86_irq_chip_set(struct x86_irq_chip *chip)
Sets the system's interrupt controller.
int x86_apic_setup(void)
Sets up the APIC to bring the interrupts, if the CPU has one, the MADT describes it,...
void x86_pit_delay(uint32_t us)
Waits us microseconds, at most 54 ms, busy.
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.
void x86_irq_alloc_from(unsigned first)
Sets the first IRQ that x86_irq_alloc() may give: past the I/O APICs' last pin.
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.
#define X86_SPURIOUS_VECTOR
void x86_lapic_cpu_setup(void)
Sets up the running CPU's local APIC: enabled, with the spurious vector 0xFF, its timer off,...
void * arch_mmio_map(uintptr_t paddr, size_t size)
Maps a device's registers into the kernel's address space, uncached (memory-mapped I/O).
int printk(const char *fmt,...)
Writes a kernel message, to the message buffer and the consoles.
#define ACPI_MPS_TRIGGER_MASK
#define ACPI_MADT_INT_SRC_OVERRIDE
#define ACPI_MPS_POLARITY_MASK
#define ACPI_MADT_IO_APIC
#define ACPI_MPS_TRIGGER_LEVEL
#define ACPI_MADT_ENABLED
#define ACPI_MPS_POLARITY_LOW
#define ACPI_MADT_LOCAL_APIC_NMI
#define ACPI_MADT_LOCAL_APIC
int snprintf(char *s, size_t n, const char *fmt,...)
Formats a string into a buffer.
unsigned long long int uint64_t
unsigned short int uint16_t
An I/O APIC: its registers, and the first GSI its pins bring.
Which local APIC input (LINT0 or LINT1) is the NMI.
An ISA IRQ that comes on another GSI, or with another polarity or trigger mode, than the default.
The MADT's header: the local APICs' address, and flags.
uint32_t local_apic_address
struct acpi_sdt_header header
An installed handler, on its interrupt's list.
An interrupt controller: the 8259s, or the APIC.
uint64_t arch_rtime_ns(void)
Reads the monotonic clock, which starts at boot.