diff options
author | Ian Moffett <ian@osmora.org> | 2024-06-29 18:38:13 -0400 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2024-06-29 18:38:13 -0400 |
commit | 9113fa42e6794e39d7233e17e8106f677ad04d94 (patch) | |
tree | 2c8763b8b0c271d4f2d6b9b4bf2415da7612526d /sys | |
parent | 1bcdbcf7b9b38de99c73ca44b6b9ea7785deaac7 (diff) |
kernel/amd64: lapic: Add support for IPIs
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/amd64/lapic.c | 38 | ||||
-rw-r--r-- | sys/include/arch/amd64/lapic.h | 10 |
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; |