WIP BROKEN NX enablement, for now only for the second page directory.

TODO:
    * selective NX enablement on pd0, pd1 and pd3.
      Unconditional NX on the whole pd3 makes memtest86+ reboot in a QEMU-emulated computer.
    * if supported on all x86_64 CPUs, simply enable long mode and NX simultaneously ? A real K8 dual-core processor didn't seem to hate it, at least.
    * startup code: NX enablement for x86, on capable computers (CPUID 0x80000001, edx bit 20).
    * set the appropriate flag in the headers.
This commit is contained in:
Lionel Debroux 2023-01-18 23:36:44 +01:00
parent a541469850
commit 61afe1143b
4 changed files with 58 additions and 40 deletions

View File

@ -104,6 +104,7 @@ startup:
movl %esi, boot_params_addr@GOTOFF(%ebx)
# ...and check if the processor supports long mode.
# TODO and NX
movl $0x80000000, %eax # check if function 0x80000001 is available
pushl %ebx # ebx is overwritten by cpuid
@ -206,7 +207,7 @@ init_idt_descr:
jz 1f # bail if not supported
movl %cr4, %eax # enable PAE
orl $0x00000020, %eax
orb $0x20, %al
movl %eax, %cr4
leal pdp@GOTOFF(%ebx), %eax # set the page directory base address
@ -219,7 +220,7 @@ init_idt_descr:
movl $0xc0000080, %ecx # enable long mode
rdmsr
orl $0x00000100, %eax
orb $0x01, %ah
wrmsr
leal pml4@GOTOFF(%ebx), %eax # set the page directory base address
@ -648,17 +649,17 @@ gdt_end:
.data
.macro ptes64 start, count=64
.quad \start + 0x0000000 + 0x83
.quad \start + 0x0200000 + 0x83
.quad \start + 0x0400000 + 0x83
.quad \start + 0x0600000 + 0x83
.quad \start + 0x0800000 + 0x83
.quad \start + 0x0A00000 + 0x83
.quad \start + 0x0C00000 + 0x83
.quad \start + 0x0E00000 + 0x83
.macro ptes64 start, flags, count=64
.quad \start + 0x0000000 + \flags
.quad \start + 0x0200000 + \flags
.quad \start + 0x0400000 + \flags
.quad \start + 0x0600000 + \flags
.quad \start + 0x0800000 + \flags
.quad \start + 0x0A00000 + \flags
.quad \start + 0x0C00000 + \flags
.quad \start + 0x0E00000 + \flags
.if \count-1
ptes64 "(\start+0x01000000)",\count-1
ptes64 "(\start+0x01000000)", \flags, \count-1
.endif
.endm
@ -702,22 +703,22 @@ pdp:
.align 4096
.globl pd0
pd0:
ptes64 0x0000000000000000
ptes64 0x0000000000000000,0x0000000000000083
.align 4096
.globl pd1
pd1:
ptes64 0x0000000040000000
ptes64 0x0000000040000000,0x0000000000000083
.align 4096
.globl pd2
pd2:
ptes64 0x0000000080000000
ptes64 0x0000000080000000,0x0000000000000083
.align 4096
.globl pd3
pd3:
ptes64 0x00000000C0000000
ptes64 0x00000000C0000000,0x0000000000000083
.previous

View File

@ -71,14 +71,14 @@ startup32:
# Enable PAE.
movl %cr4, %eax
orl $0x20, %eax
orb $0x20, %al
movl %eax, %cr4
# Enable long mode.
movl $0xc0000080, %ecx
rdmsr
orl $0x00000100, %eax
orb $0x01, %ah
wrmsr
# Enable paging and protection.
@ -162,6 +162,13 @@ startup:
leaq _stacks(%rip), %rsp
addq %rax, %rsp
# Enable NX.
movl $0xc0000080, %ecx
rdmsr
orb $0x08, %ah
wrmsr
# Initialise the pml4 and pdp tables.
leaq pml4(%rip), %rcx
@ -255,8 +262,8 @@ flush: movw $KERNEL_DS, %ax
# Enable SSE.
movq %cr0, %rax
andw $0xfffb, %ax # clear coprocessor emulation bit
orw $0x0002, %ax # set coprocessor monitoring bit
andb $0xfb, %al # clear coprocessor emulation bit
orb $0x02, %al # set coprocessor monitoring bit
mov %rax, %cr0
movq %cr4, %rax
orw $0x0600, %ax # set OSFXSR and OSXMMEXCPT
@ -465,17 +472,17 @@ gdt_end:
.data
.macro ptes64 start, count=64
.quad \start + 0x0000000 + 0x83
.quad \start + 0x0200000 + 0x83
.quad \start + 0x0400000 + 0x83
.quad \start + 0x0600000 + 0x83
.quad \start + 0x0800000 + 0x83
.quad \start + 0x0A00000 + 0x83
.quad \start + 0x0C00000 + 0x83
.quad \start + 0x0E00000 + 0x83
.macro ptes64 start, flags, count=64
.quad \start + 0x0000000 + \flags
.quad \start + 0x0200000 + \flags
.quad \start + 0x0400000 + \flags
.quad \start + 0x0600000 + \flags
.quad \start + 0x0800000 + \flags
.quad \start + 0x0A00000 + \flags
.quad \start + 0x0C00000 + \flags
.quad \start + 0x0E00000 + \flags
.if \count-1
ptes64 "(\start+0x01000000)",\count-1
ptes64 "(\start+0x01000000)", \flags, \count-1
.endif
.endm
@ -514,22 +521,22 @@ pdp:
.align 4096
.globl pd0
pd0:
ptes64 0x0000000000000000
ptes64 0x0000000000000000,0x0000000000000083
.align 4096
.globl pd1
pd1:
ptes64 0x0000000040000000
ptes64 0x0000000040000000,0x0000000000000083
.align 4096
.globl pd2
pd2:
ptes64 0x0000000080000000
ptes64 0x0000000080000000,0x8000000000000083
.align 4096
.globl pd3
pd3:
ptes64 0x00000000C0000000
ptes64 0x00000000C0000000,0x0000000000000083
.previous
@ -567,14 +574,14 @@ data32 lgdt ap_gdt_descr - ap_trampoline
# Enable PAE.
movl %cr4, %eax
orl $0x20, %eax
orb $0x20, %al
movl %eax, %cr4
# Enable long mode.
movl $0xc0000080, %ecx
rdmsr
orl $0x00000100, %eax
orb $0x01, %ah
wrmsr
# Enable paging and protection.
@ -583,6 +590,13 @@ data32 lgdt ap_gdt_descr - ap_trampoline
orl $0x80000001, %eax
movl %eax, %cr0
# Enable NX.
movl $0xc0000080, %ecx
rdmsr
orb $0x08, %ah
wrmsr
# Jump to the 64-bit entry point.
ap_jump:
data32 ljmp $KERNEL_CS, $0

View File

@ -100,7 +100,9 @@ typedef union {
uint32_t : 12; // ECX feature flags, bit 20
uint32_t x2apic : 1;
uint32_t : 10; // ECX feature flags, bit 31
uint32_t : 29; // EDX extended feature flags, bit 0
uint32_t : 19; // EDX extended feature flags, bit 0
uint32_t nx : 1;
uint32_t : 9;
uint32_t lm : 1;
uint32_t : 2; // EDX extended feature flags, bit 31
};

View File

@ -125,13 +125,14 @@ bool map_window(uintptr_t start_page)
return false;
}
if (cpuid_info.flags.lm == 0 && (start_page >= PAGE_C(64,GB))) {
// Fail, we want an address that is out of bounds
// for PAE and no long mode (ie. 32 bit CPU).
// Fail, we want an address that is out of bounds
// for PAE and no long mode (ie. 32 bit CPU).
return false;
}
// Compute the page table entries.
uint64_t flags = cpuid_info.flags.nx ? UINT64_C(0x8000000000000083) : 0x83;
for (uintptr_t i = 0; i < 512; i++) {
pd2[i] = ((uint64_t)window << 30) + (i << VM_PAGE_SHIFT) + 0x83;
pd2[i] = ((uint64_t)window << 30) + (i << VM_PAGE_SHIFT) + flags;
}
// Reload the PDBR to flush any remnants of the old mapping.
load_pdbr();