or $0x20, %ecx /* CR4.PAE = bit 5 */
mov %ecx, %cr4
+ /* --- Check for NX support via CPUID.0x80000001:EDX bit 20 --- */
+ mov $0x80000000, %eax /* Check max extended leaf */
+ cpuid
+ cmp $0x80000001, %eax /* Need leaf 0x80000001 */
+ jb no_nxe /* Skip if not available */
+ mov $0x80000001, %eax /* Get extended feature flags */
+ cpuid
+ bt $20, %edx /* Test bit 20 (NX) */
+ jnc no_nxe /* Skip if NX not supported */
+
+ /* --- Enable NXE in IA32_EFER (MSR 0xC0000080, bit 11) --- */
+ mov $0xC0000080, %ecx /* IA32_EFER MSR */
+ rdmsr
+ or $0x800, %eax /* Set bit 11 (NXE) */
+ wrmsr
+
+no_nxe:
/* --- Load CR3 with PDPT physical address --- */
mov $boot_pdpt, %ecx
sub $KERNEL_VIRT_BASE, %ecx
static uintptr_t g_kernel_as = 0;
static spinlock_t vmm_lock = {0};
+static int g_nxe_enabled = 0; /* IA32_EFER.NXE enabled in boot.S */
static inline void invlpg(uintptr_t vaddr) {
__asm__ volatile("invlpg (%0)" : : "r" (vaddr) : "memory");
}
+/* Check if IA32_EFER.NXE is enabled (MSR 0xC0000080, bit 11) */
+static int check_nxe_enabled(void) {
+ uint32_t eax, edx;
+ __asm__ volatile("rdmsr" : "=a"(eax), "=d"(edx) : "c"(0xC0000080));
+ return (eax & 0x800) != 0; /* Bit 11 = NXE */
+}
+
/* --- PAE address decomposition --- */
static inline uint32_t pae_pdpt_index(uint64_t va) {
if (flags & VMM_FLAG_PWT) x86_flags |= X86_PTE_PWT;
if (flags & VMM_FLAG_PCD) x86_flags |= X86_PTE_PCD;
if (flags & VMM_FLAG_COW) x86_flags |= X86_PTE_COW;
- if (flags & VMM_FLAG_NX) x86_flags |= X86_PTE_NX;
+ /* Only set NX bit if IA32_EFER.NXE is enabled */
+ if ((flags & VMM_FLAG_NX) && g_nxe_enabled) x86_flags |= X86_PTE_NX;
return x86_flags;
}
g_kernel_as = hal_cpu_get_address_space();
+ /* Check if IA32_EFER.NXE was enabled in boot.S */
+ g_nxe_enabled = check_nxe_enabled();
+ if (g_nxe_enabled) {
+ kprintf("[VMM] NX (No-Execute) enabled.\n");
+ } else {
+ kprintf("[VMM] NX not available or not enabled.\n");
+ }
+
/* Test mapping */
vmm_map_page(0xB8000, 0xC00B8000, VMM_FLAG_PRESENT | VMM_FLAG_RW);
kprintf("[VMM] Mapped VGA to 0xC00B8000.\n");
-drive file=$disk,if=ide,format=raw \
-nic user,model=e1000 \
-serial file:$serial_log -monitor none \
- -no-reboot -no-shutdown &]
+ -no-reboot -no-shutdown \
+ -cpu qemu32,+nx &]
# Wait for QEMU to start writing
after 1000