summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/amd64/amd64/lapic.c38
-rw-r--r--sys/include/arch/amd64/lapic.h10
2 files changed, 48 insertions, 0 deletions
diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c
index 896c2bd..6d17926 100644
--- a/sys/arch/amd64/amd64/lapic.c
+++ b/sys/arch/amd64/amd64/lapic.c
@@ -284,6 +284,44 @@ lapic_timer_init(void)
return freq;
}
+void
+lapic_send_ipi(uint8_t id, uint8_t shorthand, uint8_t vector)
+{
+ const uint32_t X2APIC_IPI_SELF = 0x3F0;
+ struct cpu_info *ci = this_cpu();
+ uint64_t icr_lo = 0;
+
+ /*
+ * If we are in x2APIC mode and the shorthand is "self", use
+ * the x2APIC SELF IPI register as it is more optimized.
+ */
+ if (shorthand == IPI_SHORTHAND_SELF && ci->has_x2apic) {
+ lapic_writel(X2APIC_IPI_SELF, vector);
+ return;
+ }
+
+ /* Encode dest into the low dword of the ICR */
+ icr_lo |= (vector | IPI_DEST_PHYSICAL);
+ icr_lo |= ((shorthand & 0x3) << 18);
+
+ /*
+ * In xAPIC mode, the Delivery Status bit (bit 12) must
+ * be polled until clear after sending an IPI. However,
+ * in x2APIC mode, this bit does not exist, so there's no
+ * need to worry about polling. Since the x2APIC interface
+ * uses MSRs, we can accomplish what we need with a single
+ * write, unlike with xAPICs where you'd need to write to the
+ * ICR high dword first.
+ */
+ if (ci->has_x2apic) {
+ lapic_writel(LAPIC_ICRLO, ((uint64_t)id << 32) | icr_lo);
+ } else {
+ lapic_writel(LAPIC_ICRHI, ((uint32_t)id << 24));
+ lapic_writel(LAPIC_ICRLO, icr_lo);
+ while (ISSET(lapic_readl(LAPIC_ICRLO), BIT(12)));
+ }
+}
+
/*
* Indicates that the current interrupt is finished
* being serviced.
diff --git a/sys/include/arch/amd64/lapic.h b/sys/include/arch/amd64/lapic.h
index d06bcc9..3b06206 100644
--- a/sys/include/arch/amd64/lapic.h
+++ b/sys/include/arch/amd64/lapic.h
@@ -30,10 +30,20 @@
#ifndef _MACHINE_LAPIC_H_
#define _MACHINE_LAPIC_H_
+#include <sys/param.h>
#include <sys/types.h>
+#define IPI_SHORTHAND_NONE 0x00
+#define IPI_SHORTHAND_SELF 0x01
+#define IPI_SHORTHAND_ALL 0x02
+#define IPI_SHORTHAND_OTHERS 0x03
+
+#define IPI_DEST_PHYSICAL 0
+#define IPI_DEST_LOGICAL BIT(11)
+
void lapic_init(void);
void lapic_eoi(void);
+void lapic_send_ipi(uint8_t id, uint8_t shorthand, uint8_t vector);
extern uintptr_t g_lapic_base;