sys/smp: Add xAPIC ICR delivery status checks to INIT-SIPI-SIPI sequence
diff --git a/common/sys/lapic.c b/common/sys/lapic.c
index 5579a00f..ddaa7f10 100644
--- a/common/sys/lapic.c
+++ b/common/sys/lapic.c
@@ -242,6 +242,15 @@ void lapic_write(uint32_t reg, uint32_t data) {
mmoutd(lapic_mmio_base + reg, data);
}
+void lapic_icr_wait(void) {
+ for (int i = 0; i < 1000000; i++) {
+ if (!(lapic_read(LAPIC_REG_ICR0) & (1 << 12))) {
+ return;
+ }
+ asm volatile ("pause");
+ }
+}
+
bool x2apic_check(void) {
uint32_t eax, ebx, ecx, edx;
if (!cpuid(1, 0, &eax, &ebx, &ecx, &edx))
diff --git a/common/sys/lapic.h b/common/sys/lapic.h
index 02bf49f4..9edcfd69 100644
--- a/common/sys/lapic.h
+++ b/common/sys/lapic.h
@@ -17,6 +17,7 @@ bool lapic_check(void);
void lapic_eoi(void);
uint32_t lapic_read(uint32_t reg);
void lapic_write(uint32_t reg, uint32_t data);
+void lapic_icr_wait(void);
bool x2apic_check(void);
bool x2apic_enable(void);
diff --git a/common/sys/smp.c b/common/sys/smp.c
index 30d71a7d..4ecc3049 100644
--- a/common/sys/smp.c
+++ b/common/sys/smp.c
@@ -84,6 +84,7 @@ static bool smp_start_ap(uint32_t lapic_id, struct gdtr *gdtr,
if (x2apic) {
x2apic_write(LAPIC_REG_ICR0, ((uint64_t)lapic_id << 32) | 0x4500);
} else {
+ lapic_icr_wait();
lapic_write(LAPIC_REG_ICR1, lapic_id << 24);
lapic_write(LAPIC_REG_ICR0, 0x4500);
}
@@ -95,10 +96,17 @@ static bool smp_start_ap(uint32_t lapic_id, struct gdtr *gdtr,
x2apic_write(LAPIC_REG_ICR0, ((uint64_t)lapic_id << 32) |
((size_t)trampoline / 4096) | 0x4600);
} else {
+ lapic_icr_wait();
lapic_write(LAPIC_REG_ICR1, lapic_id << 24);
lapic_write(LAPIC_REG_ICR0, ((size_t)trampoline / 4096) | 0x4600);
}
- stall(200);
+ if (j == 0) {
+ stall(200);
+ }
+ }
+
+ if (!x2apic) {
+ lapic_icr_wait();
}
for (int i = 0; i < 100; i++) {
