summaryrefslogtreecommitdiff
path: root/src/sys/arch/amd64/cpu
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2025-09-26 14:10:34 -0400
committerIan Moffett <ian@osmora.org>2025-09-26 14:11:17 -0400
commit47016cc15609864414d83f1a0745e95c1db04db5 (patch)
treee67668504aa83db4502178e54f19bbbe11faf97b /src/sys/arch/amd64/cpu
parentdc886721c6d3438dba49e817a2ebc8a49a5e3880 (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/amd64/cpu')
-rw-r--r--src/sys/arch/amd64/cpu/cpu_lapic.c64
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