AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
apic.c
Go to the documentation of this file.
1
35
36#include <core/system.h>
37#include <core/arch.h>
38#include <core/kargs.h>
39#include <core/string.h>
40#include <cpu/cpu.h>
41#include <cpu/msr.h>
42#include <cpu/sdt.h>
43#include <platform/misc.h>
44#include <sys/cpu.h>
45
46/* the local APIC's registers */
47#define LAPIC_ID 0x020
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
60
61#define SVR_ENABLE 0x100
62#define LVT_MASKED 0x10000
63#define LVT_NMI 0x400
64#define LVT_PERIODIC 0x20000
65#define TIMER_DIV_16 0x3
66
67#define APIC_BASE_ENABLE 0x800
68
69/* the interrupt command register: writing its low half sends the IPI,
70 * and this bit says it is still being delivered */
71#define ICR_PENDING 0x1000
72
73/* the I/O APIC's registers: one is selected, then read or written
74 * through the window */
75#define IOAPIC_SEL 0x00
76#define IOAPIC_WIN 0x10
77#define IOAPIC_VER 0x01
78#define IOAPIC_REDIR(n) (0x10 + 2 * (n))
79
80#define REDIR_MASKED 0x10000
81#define REDIR_LEVEL 0x8000
82#define REDIR_LOW 0x2000
83
84#define IOAPICS_MAX 4
85
86static volatile uint32_t *lapic;
88
89/* the enabled local APICs that the MADT lists, which are the CPUs */
91static int cpu_ids_nr;
92
93/* the LINT input the NMI comes on, as the MADT says */
94static int nmi_lint = 1;
95
96/* the I/O APICs: their registers, and the GSIs of their pins */
101static int ioapics_nr;
102
103/* the ISA IRQs' GSIs, and their flags (0: the ISA bus's, edge-triggered
104 * and active high) */
105static struct {
108} isa[16];
109
110/* each IRQ's route, for /proc/interrupts */
111static struct {
113 int level;
115
117
120static inline uint32_t lapic_read(unsigned reg)
121{
122 return lapic[reg / 4];
123}
124
126static inline void lapic_write(unsigned reg, uint32_t val)
127{
128 lapic[reg / 4] = val;
129}
130
132static struct ioapic *ioapic_of(uint32_t gsi)
133{
134 for (int i = 0; i < ioapics_nr; ++i)
135 if (gsi >= ioapics[i].gsi_base && gsi < ioapics[i].gsi_base + ioapics[i].pins)
136 return &ioapics[i];
137
138 return NULL;
139}
140
142static uint32_t ioapic_read(struct ioapic *io, uint32_t reg)
143{
144 io->regs[IOAPIC_SEL / 4] = reg;
145 return io->regs[IOAPIC_WIN / 4];
146}
147
149static void ioapic_write(struct ioapic *io, uint32_t reg, uint32_t val)
150{
151 io->regs[IOAPIC_SEL / 4] = reg;
152 io->regs[IOAPIC_WIN / 4] = val;
153}
154
157static uint32_t irq_gsi(unsigned irq, int *level, int *low)
158{
159 uint16_t flags = irq < 16 ? isa[irq].flags : 0;
160 uint32_t gsi = irq < 16 ? isa[irq].gsi : irq;
161
162 /* the ISA IRQs conform to the bus: edge-triggered, active high; the
163 * PCI ones past 16 are level-triggered, active low */
164 *level = (flags & ACPI_MPS_TRIGGER_MASK) ? (flags & ACPI_MPS_TRIGGER_MASK) == ACPI_MPS_TRIGGER_LEVEL : irq >= 16;
165 *low = (flags & ACPI_MPS_POLARITY_MASK) ? (flags & ACPI_MPS_POLARITY_MASK) == ACPI_MPS_POLARITY_LOW : irq >= 16;
166
167 return gsi;
168}
169
172static void apic_route(unsigned irq, int masked)
173{
174 int level, low;
175 uint32_t gsi = irq_gsi(irq, &level, &low);
176 struct ioapic *io = ioapic_of(gsi);
177
178 if (!io) {
179 printk("apic: IRQ %d: no I/O APIC has GSI %d\n", irq, gsi);
180 return;
181 }
182
183 uint32_t pin = gsi - io->gsi_base;
184 uint32_t lo = (32 + irq) | (level ? REDIR_LEVEL : 0) | (low ? REDIR_LOW : 0) |
185 (masked ? REDIR_MASKED : 0);
186
187 ioapic_write(io, IOAPIC_REDIR(pin) + 1, lapic_id << 24);
188 ioapic_write(io, IOAPIC_REDIR(pin), lo);
189
190 routes[irq].gsi = gsi;
191 routes[irq].level = level;
192}
193
195static void apic_mask(unsigned irq)
196{
197 if (irq < X86_IRQ_TIMER)
198 apic_route(irq, 1);
199}
200
202static void apic_unmask(unsigned irq)
203{
204 if (irq < X86_IRQ_TIMER)
205 apic_route(irq, 0);
206}
207
209static void apic_eoi(unsigned irq)
210{
212}
213
217{
219}
220
222static const char *apic_describe(unsigned irq)
223{
224 static char buf[32];
225
226 snprintf(buf, sizeof(buf), "ioapic gsi %d %s", routes[irq].gsi,
227 routes[irq].level ? "level" : "edge");
228 return buf;
229}
230
231static struct x86_irq_chip apic_chip = {
232 .name = "apic",
233 .mask = apic_mask,
234 .unmask = apic_unmask,
235 .eoi = apic_eoi,
236 .describe = apic_describe,
237 .timer = "lapic",
238};
239
242static void msi_nothing(unsigned irq)
243{
244}
245
247static const char *msi_describe(unsigned irq)
248{
249 return "msi";
250}
251
252static struct x86_irq_chip msi_chip = {
253 .name = "msi",
254 .mask = msi_nothing,
255 .unmask = msi_nothing,
256 .eoi = apic_eoi,
257 .describe = msi_describe,
258};
259
272{
273 if (!lapic)
274 return -ENODEV;
275
276 int irq = x86_irq_alloc(&msi_chip);
277
278 if (irq < 0)
279 return -ENOSPC;
280
281 int err = irq_install(irq, handler, arg);
282
283 if (err)
284 return err;
285
286 *addr = 0xFEE00000ULL | (uint64_t) lapic_id << 12;
287 *data = 32 + irq;
288 return irq;
289}
290
292static int cpu_has_apic(void)
293{
294 uint32_t a, b, c, d;
295
296 asm volatile("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(1), "c"(0));
297 return !!(d & (1 << 9));
298}
299
314
322int x86_apic_cpus(uint32_t *ids, int max)
323{
324 if (!lapic)
325 return 0;
326
327 int n = MIN(cpu_ids_nr, max);
328
329 for (int i = 0; i < n; ++i)
330 ids[i] = cpu_ids[i];
331
332 return n;
333}
334
343{
344 lapic_write(LAPIC_ICR_HI, id << 24);
346
348 ;
349}
350
360{
361 const char *arg = NULL;
362
363 if (!kargs_get("apic", &arg) && arg && !strcmp(arg, "off")) {
364 printk("apic: off (apic=off)\n");
365 return -ENODEV;
366 }
367
368 struct acpi_madt *madt = x86_acpi_table ? x86_acpi_table("APIC") : NULL;
369
370 if (!cpu_has_apic() || !madt) {
371 printk("apic: %s\n", madt ? "the CPU has none" : "no MADT");
372 return -ENODEV;
373 }
374
375 /* the ISA IRQs come on the pins of the same numbers, unless an
376 * override says otherwise */
377 for (int i = 0; i < 16; ++i) {
378 isa[i].gsi = i;
379 isa[i].flags = 0;
380 }
381
382 uint8_t *p = (uint8_t *) (madt + 1), *end = (uint8_t *) madt + madt->header.length;
383
384 for (; p + 2 <= end && p[1] >= 2; p += p[1]) {
385 switch (p[0]) {
387 struct acpi_madt_local_apic *e = (void *) p;
388
390 cpu_ids[cpu_ids_nr++] = e->apic_id;
391 break;
392 }
393 case ACPI_MADT_IO_APIC: {
394 struct acpi_madt_io_apic *e = (void *) p;
395
396 if (ioapics_nr == IOAPICS_MAX)
397 break;
398
399 struct ioapic *io = &ioapics[ioapics_nr];
400 io->regs = arch_mmio_map(e->address, 4096);
401
402 /* no room to map its registers: this one isn't used */
403 if (!io->regs)
404 break;
405
406 io->address = e->address;
407 io->gsi_base = e->gsi_base;
408 io->pins = ((ioapic_read(io, IOAPIC_VER) >> 16) & 0xff) + 1;
409 ioapics_nr++;
410 break;
411 }
413 struct acpi_madt_override *e = (void *) p;
414
415 if (e->bus == 0 && e->source < 16) {
416 isa[e->source].gsi = e->gsi;
417 isa[e->source].flags = e->flags;
418 }
419 break;
420 }
422 struct acpi_madt_local_apic_nmi *e = (void *) p;
423 nmi_lint = e->lint;
424 break;
425 }
426 }
427 }
428
429 if (!ioapics_nr) {
430 printk("apic: no I/O APIC\n");
431 return -ENODEV;
432 }
433
434 /* the boot CPU's local APIC, where the MADT says; without room to map
435 * it, the 8259s bring the interrupts instead */
437
438 if (!lapic) {
439 printk("apic: no room to map the local APIC\n");
440 return -ENOMEM;
441 }
442
446
447 /* mask every pin until it has a handler */
448 for (int i = 0; i < ioapics_nr; ++i)
449 for (uint32_t pin = 0; pin < ioapics[i].pins; ++pin)
451
452 /* mask the 8259s, if there are any: they would come through LINT0 */
454
456
457 /* MSIs get the IRQs past the I/O APICs' pins */
458 uint32_t gsi_end = 16;
459
460 for (int i = 0; i < ioapics_nr; ++i)
461 if (ioapics[i].gsi_base + ioapics[i].pins > gsi_end)
462 gsi_end = ioapics[i].gsi_base + ioapics[i].pins;
463
464 x86_irq_alloc_from(gsi_end);
465
466 printk("apic: local APIC %d at %p, %d I/O APIC(s), the first at %p (GSI %d, %d pins)\n",
468 (void *) (uintptr_t) ioapics[0].address, ioapics[0].gsi_base, ioapics[0].pins);
469
470 for (int i = 0; i < 16; ++i)
471 if (isa[i].gsi != (uint32_t) i || isa[i].flags)
472 printk("apic: IRQ %d is GSI %d%s\n", i, isa[i].gsi,
473 (isa[i].flags & ACPI_MPS_TRIGGER_MASK) == ACPI_MPS_TRIGGER_LEVEL ? ", level" : "");
474
475 return 0;
476}
477
482{
483 const uint32_t window_us = 20000;
484
487 lapic_write(LAPIC_TIMER_INIT, 0xffffffff);
488
489 if (x86_clock_precise()) {
490 uint64_t t0 = arch_rtime_ns();
491
492 while (arch_rtime_ns() - t0 < window_us * 1000ULL)
493 ;
494 } else {
495 x86_pit_delay(window_us);
496 }
497
498 uint32_t counted = 0xffffffff - lapic_read(LAPIC_TIMER_CUR);
500
501 return (uint32_t) ((uint64_t) counted * ns / (window_us * 1000ULL));
502}
503
513{
514 timer_count = timer_calibrate(period_ns);
515
516 if (!timer_count)
517 timer_count = 1;
518
520
522
523 printk("apic: the timer every %d ns (%d counts, divided by 16)\n", period_ns, timer_count);
524 return period_ns;
525}
526
530{
531 if (!timer_count)
532 return;
533
537 curcpu()->arch.ticking = 1;
538}
int irq_install(unsigned irq, irq_handler_t fn, void *arg)
Installs a handler for an IRQ.
Definition irq.c:32
static void ioapic_write(struct ioapic *io, uint32_t reg, uint32_t val)
Writes an I/O APIC register.
Definition apic.c:149
static struct x86_irq_chip apic_chip
Definition apic.c:231
#define ICR_PENDING
Definition apic.c:71
static void apic_route(unsigned irq, int masked)
Routes IRQ irq to the boot CPU, with vector 32 + irq, masked or not.
Definition apic.c:172
#define LAPIC_LVT_LINT1
Definition apic.c:55
#define LVT_PERIODIC
Definition apic.c:64
static void apic_eoi(unsigned irq)
Tells the local APIC that the interrupt is handled.
Definition apic.c:209
#define LAPIC_EOI
Definition apic.c:49
#define IOAPIC_VER
Definition apic.c:77
static int nmi_lint
Definition apic.c:94
static struct @321312313052114036106345344076272057075275236024 isa[16]
static volatile uint32_t * lapic
Definition apic.c:86
static void apic_unmask(unsigned irq)
Unmasks an IRQ at the I/O APIC.
Definition apic.c:202
#define LAPIC_ICR_LO
Definition apic.c:51
#define LAPIC_TIMER_CUR
Definition apic.c:58
static const char * msi_describe(unsigned irq)
Describes an MSI's route, for /proc/interrupts.
Definition apic.c:247
#define REDIR_LEVEL
Definition apic.c:81
#define LVT_MASKED
Definition apic.c:62
#define REDIR_LOW
Definition apic.c:82
#define IOAPIC_WIN
Definition apic.c:76
#define REDIR_MASKED
Definition apic.c:80
#define LAPIC_TPR
Definition apic.c:48
#define LAPIC_LVT_TIMER
Definition apic.c:53
#define APIC_BASE_ENABLE
Definition apic.c:67
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...
Definition apic.c:481
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.
Definition apic.c:157
#define LAPIC_LVT_ERROR
Definition apic.c:56
#define LAPIC_TIMER_DIV
Definition apic.c:59
static struct ioapic ioapics[IOAPICS_MAX]
#define LAPIC_TIMER_INIT
Definition apic.c:57
static uint32_t lapic_id
Definition apic.c:87
static void lapic_write(unsigned reg, uint32_t val)
Writes a register of the running CPU's local APIC.
Definition apic.c:126
#define LVT_NMI
Definition apic.c:63
static struct x86_irq_chip msi_chip
Definition apic.c:252
static const char * apic_describe(unsigned irq)
Describes an IRQ's route, for /proc/interrupts.
Definition apic.c:222
#define IOAPICS_MAX
Definition apic.c:84
static struct ioapic * ioapic_of(uint32_t gsi)
Returns the I/O APIC that has the pin of gsi, or NULL if none has.
Definition apic.c:132
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.
Definition apic.c:271
#define LAPIC_SVR
Definition apic.c:50
static int cpu_ids_nr
Definition apic.c:91
#define TIMER_DIV_16
Definition apic.c:65
#define LAPIC_ID
Definition apic.c:47
static int ioapics_nr
Definition apic.c:101
#define SVR_ENABLE
Definition apic.c:61
#define IOAPIC_REDIR(n)
Definition apic.c:78
static void apic_mask(unsigned irq)
Masks an IRQ at the I/O APIC.
Definition apic.c:195
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...
Definition apic.c:120
static uint32_t cpu_ids[CPUS_MAX]
Definition apic.c:90
#define IOAPIC_SEL
Definition apic.c:75
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.
Definition apic.c:242
static uint32_t timer_count
Definition apic.c:116
static int cpu_has_apic(void)
Returns whether the CPU has a local APIC (CPUID 1, EDX bit 9).
Definition apic.c:292
#define LAPIC_LVT_LINT0
Definition apic.c:54
static uint32_t ioapic_read(struct ioapic *io, uint32_t reg)
Reads an I/O APIC register.
Definition apic.c:142
#define LAPIC_ICR_HI
Definition apic.c:52
#define MIN(a, b)
Definition system.h:11
struct cpu cpus[CPUS_MAX]
Definition sched.c:28
#define CPUS_MAX
Definition cpu.h:21
void(*) irq_handler_t(void *arg)
Definition irq.h:21
int kargs_get(const char *key, const char **value)
Looks up an argument of the kernel's command line.
Definition kargs.c:73
#define X86_IRQ_NR
Definition misc.h:12
void x86_pic_disable(void)
Masks every IRQ of the 8259s, when the APIC brings the interrupts.
Definition pic.c:152
int x86_clock_precise(void)
Says whether the clock counts finer than the ticks.
Definition clock.c:193
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.
Definition apic.c:512
int x86_irq_alloc(struct x86_irq_chip *chip)
Gives a free IRQ with a controller of its own, for an MSI.
Definition irq.c:99
void x86_lapic_eoi(void)
Tells the running CPU's local APIC that its interrupt (an IPI) is handled.
Definition apic.c:216
void * x86_acpi_table(const char *signature)
Finds one of ACPI's tables, by its signature.
Definition acpi.c:183
void x86_irq_chip_set(struct x86_irq_chip *chip)
Sets the system's interrupt controller.
Definition irq.c:67
#define X86_TIMER_VECTOR
Definition misc.h:14
int x86_apic_setup(void)
Sets up the APIC to bring the interrupts, if the CPU has one, the MADT describes it,...
Definition apic.c:359
#define X86_IRQ_TIMER
Definition misc.h:13
void x86_pit_delay(uint32_t us)
Waits us microseconds, at most 54 ms, busy.
Definition pit.c:123
int x86_apic_cpus(uint32_t *ids, int max)
Lists the CPUs' local APIC IDs, the boot CPU's among them.
Definition apic.c:322
void x86_lapic_ipi(uint32_t id, uint32_t icr)
Sends an IPI to a CPU, and waits until it is delivered.
Definition apic.c:342
void x86_irq_alloc_from(unsigned first)
Sets the first IRQ that x86_irq_alloc() may give: past the I/O APICs' last pin.
Definition irq.c:88
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 apic.c:529
#define X86_SPURIOUS_VECTOR
Definition misc.h:17
void x86_lapic_cpu_setup(void)
Sets up the running CPU's local APIC: enabled, with the spurious vector 0xFF, its timer off,...
Definition apic.c:303
#define APIC_BASE
Definition msr.h:24
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).
Definition pmap.c:508
int printk(const char *fmt,...)
Writes a kernel message, to the message buffer and the consoles.
Definition printk.c:249
#define ACPI_MPS_TRIGGER_MASK
Definition sdt.h:88
#define ACPI_MADT_INT_SRC_OVERRIDE
Definition sdt.h:76
#define ACPI_MPS_POLARITY_MASK
Definition sdt.h:85
#define ACPI_MADT_IO_APIC
Definition sdt.h:75
#define ACPI_MPS_TRIGGER_LEVEL
Definition sdt.h:90
#define ACPI_MADT_ENABLED
Definition sdt.h:81
#define ACPI_MPS_POLARITY_LOW
Definition sdt.h:87
#define ACPI_MADT_LOCAL_APIC_NMI
Definition sdt.h:77
#define ACPI_MADT_LOCAL_APIC
Definition sdt.h:74
int snprintf(char *s, size_t n, const char *fmt,...)
Formats a string into a buffer.
Definition snprintf.c:226
#define NULL
Definition stddef.h:27
__SIZE_TYPE__ uintptr_t
Definition stddef.h:12
unsigned int uint32_t
Definition stddef.h:22
unsigned char uint8_t
Definition stddef.h:20
unsigned long long int uint64_t
Definition stddef.h:23
unsigned short int uint16_t
Definition stddef.h:21
uint16_t flags
uint32_t gsi
An I/O APIC: its registers, and the first GSI its pins bring.
Definition sdt.h:107
uint32_t gsi_base
Definition sdt.h:112
uint32_t address
Definition sdt.h:111
Which local APIC input (LINT0 or LINT1) is the NMI.
Definition sdt.h:126
A CPU's local APIC.
Definition sdt.h:99
uint32_t flags
Definition sdt.h:103
uint8_t apic_id
Definition sdt.h:102
An ISA IRQ that comes on another GSI, or with another polarity or trigger mode, than the default.
Definition sdt.h:117
uint8_t bus
Definition sdt.h:119
uint32_t gsi
Definition sdt.h:121
uint8_t source
Definition sdt.h:120
uint16_t flags
Definition sdt.h:122
The MADT's header: the local APICs' address, and flags.
Definition sdt.h:134
uint32_t local_apic_address
Definition sdt.h:136
struct acpi_sdt_header header
Definition sdt.h:135
uint32_t length
Definition sdt.h:31
uint32_t apic_id
Definition cpu.h:125
struct arch_cpu arch
Definition cpu.h:17
An installed handler, on its interrupt's list.
Definition irq.c:19
Definition apic.c:97
uint32_t address
Definition apic.c:99
uint32_t pins
Definition apic.c:99
uint32_t gsi_base
Definition apic.c:99
volatile uint32_t * regs
Definition apic.c:98
An interrupt controller: the 8259s, or the APIC.
Definition misc.h:20
uint64_t arch_rtime_ns(void)
Reads the monotonic clock, which starts at boot.
Definition timer.c:56