diff options
author | Ian Moffett <ian@osmora.org> | 2025-09-26 14:10:34 -0400 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2025-09-26 14:11:17 -0400 |
commit | 47016cc15609864414d83f1a0745e95c1db04db5 (patch) | |
tree | e67668504aa83db4502178e54f19bbbe11faf97b /src/sys/arch | |
parent | dc886721c6d3438dba49e817a2ebc8a49a5e3880 (diff) |
kern/amd64: Support APIC inter-processor interrupts
This commit introduces support for sending inter-processor interrupts on
the mainbus to other cores on the machine.
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'src/sys/arch')
-rw-r--r-- | src/sys/arch/amd64/cpu/cpu_lapic.c | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/src/sys/arch/amd64/cpu/cpu_lapic.c b/src/sys/arch/amd64/cpu/cpu_lapic.c index be58428..bea0ddf 100644 --- a/src/sys/arch/amd64/cpu/cpu_lapic.c +++ b/src/sys/arch/amd64/cpu/cpu_lapic.c @@ -34,6 +34,7 @@ #include <sys/syslog.h> #include <sys/cpuvar.h> +#include <sys/errno.h> #include <sys/panic.h> #include <sys/cdefs.h> #include <sys/param.h> @@ -239,6 +240,69 @@ lapic_timer_oneshot(bool mask, uint32_t count) } /* + * Send off an inter-processor interrupt to the + * specified processor(s) + */ +int +lapic_tx_ipi(const struct lapic_ipi *ipip) +{ + const uint32_t X2APIC_IPI_SELF = 0x3F0; + uint32_t icr_lo, icr_hi; + struct pcore *core = this_core(); + struct mdcore *mdcore; + + if (ipip == NULL) { + return -EINVAL; + } + + mdcore = &core->md; + + /* + * If we are in x2APIC mode and the shorthand is "self", use + * the x2APIC SELF IPI register as it is more optimized. + */ + if (ipip->shorthand == IPI_SHAND_SELF && mdcore->x2apic) { + lapic_writel(mdcore, X2APIC_IPI_SELF, ipip->vector); + return 0; + } + + icr_lo = 0; + icr_hi = 0; + + /* Encode the low dword */ + icr_lo |= ipip->vector; + icr_lo |= (ipip->delmod & 0x7) << 8; + icr_lo |= (ipip->dest_mode & 0x1) << 11; + icr_lo |= (ipip->shorthand & 0x3) << 18; + + /* + * If we are in x2APIC mode, the LAPIC will queue it so there + * is no need to poll the Delivery Status bit as it does not + * exist. + */ + if (mdcore->x2apic) { + lapic_writel( + mdcore, LAPIC_ICRLO, + (((uint64_t)ipip->apic_id) << 32) | icr_lo + ); + return 0; + } + + /* + * In xAPIC mode, we'll need to poll the Delivery + * Status bit to manually serialize the operation + * until the next IPI is ready. + */ + lapic_writel(mdcore, LAPIC_ICRHI, ((uint32_t)ipip->apic_id << 24)); + lapic_writel(mdcore, LAPIC_ICRLO, icr_lo); + do { + __ASMV("pause"); + icr_lo = lapic_readl(mdcore, LAPIC_ICRLO); + } while (ISSET(icr_lo, BIT(12))); + return 0; +} + +/* * Start Local APIC timer oneshot in usec */ void |