Extend x2APIC check as per VT-d specification
diff --git a/limine.bin b/limine.bin
index fb18ec6b..39bbf983 100644
Binary files a/limine.bin and b/limine.bin differ
diff --git a/stage2/sys/lapic.c b/stage2/sys/lapic.c
new file mode 100644
index 00000000..44f379fa
--- /dev/null
+++ b/stage2/sys/lapic.c
@@ -0,0 +1,65 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <sys/lapic.h>
+#include <sys/cpu.h>
+#include <lib/blib.h>
+#include <lib/acpi.h>
+
+struct dmar {
+ struct sdt;
+ uint8_t host_address_width;
+ uint8_t flags;
+ uint8_t reserved[10];
+ symbol remapping_structures;
+} __attribute__((packed));
+
+uint32_t lapic_read(uint32_t reg) {
+ size_t lapic_mmio_base = (size_t)(rdmsr(0x1b) & 0xfffff000);
+ return mmind((void *)(lapic_mmio_base + reg));
+}
+
+void lapic_write(uint32_t reg, uint32_t data) {
+ size_t lapic_mmio_base = (size_t)(rdmsr(0x1b) & 0xfffff000);
+ mmoutd((void *)(lapic_mmio_base + reg), data);
+}
+
+bool x2apic_check(void) {
+ uint32_t eax, ebx, ecx, edx;
+ cpuid(1, 0, &eax, &ebx, &ecx, &edx);
+
+ if (!(ecx & (1 << 21)))
+ return false;
+
+ // According to the Intel VT-d spec, we're required
+ // to check if bit 0 and 1 of the flags field of the
+ // DMAR ACPI table are set, and if they are, we should
+ // not report x2APIC capabilities.
+ struct dmar *dmar = acpi_get_table("DMAR", 0);
+ if (!dmar)
+ return true;
+
+ if ((dmar->flags & (1 << 0)) && (dmar->flags & (1 << 1)))
+ return false;
+
+ return true;
+}
+
+bool x2apic_enable(void) {
+ if (!x2apic_check())
+ return false;
+
+ uint64_t ia32_apic_base = rdmsr(0x1b);
+ ia32_apic_base |= (1 << 10);
+ wrmsr(0x1b, ia32_apic_base);
+
+ return true;
+}
+
+uint64_t x2apic_read(uint32_t reg) {
+ return rdmsr(0x800 + (reg >> 4));
+}
+
+void x2apic_write(uint32_t reg, uint64_t data) {
+ wrmsr(0x800 + (reg >> 4), data);
+}
diff --git a/stage2/sys/lapic.h b/stage2/sys/lapic.h
index 1c30436a..e211fee5 100644
--- a/stage2/sys/lapic.h
+++ b/stage2/sys/lapic.h
@@ -2,53 +2,18 @@
#define __SYS__APIC_H__
#include <stdint.h>
-#include <stddef.h>
#include <stdbool.h>
-#include <sys/cpu.h>
-#include <lib/blib.h>
#define LAPIC_REG_ICR0 0x300
#define LAPIC_REG_ICR1 0x310
#define LAPIC_REG_SPURIOUS 0x0f0
#define LAPIC_REG_EOI 0x0b0
-static inline uint32_t lapic_read(uint32_t reg) {
- size_t lapic_mmio_base = (size_t)(rdmsr(0x1b) & 0xfffff000);
- return mmind((void *)(lapic_mmio_base + reg));
-}
-
-static inline void lapic_write(uint32_t reg, uint32_t data) {
- size_t lapic_mmio_base = (size_t)(rdmsr(0x1b) & 0xfffff000);
- mmoutd((void *)(lapic_mmio_base + reg), data);
-}
-
-static inline bool x2apic_check(void) {
- uint32_t eax, ebx, ecx, edx;
- cpuid(1, 0, &eax, &ebx, &ecx, &edx);
-
- if (!(ecx & (1 << 21)))
- return false;
-
- return true;
-}
-
-static inline bool x2apic_enable(void) {
- if (!x2apic_check())
- return false;
-
- uint64_t ia32_apic_base = rdmsr(0x1b);
- ia32_apic_base |= (1 << 10);
- wrmsr(0x1b, ia32_apic_base);
-
- return true;
-}
-
-static inline uint64_t x2apic_read(uint32_t reg) {
- return rdmsr(0x800 + (reg >> 4));
-}
-
-static inline void x2apic_write(uint32_t reg, uint64_t data) {
- wrmsr(0x800 + (reg >> 4), data);
-}
+uint32_t lapic_read(uint32_t reg);
+void lapic_write(uint32_t reg, uint32_t data);
+bool x2apic_check(void);
+bool x2apic_enable(void);
+uint64_t x2apic_read(uint32_t reg);
+void x2apic_write(uint32_t reg, uint64_t data);
#endif
