Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/arch/i386/i386/locore.S,v rcsdiff: /ftp/cvs/cvsroot/src/sys/arch/i386/i386/locore.S,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.118 retrieving revision 1.123 diff -u -p -r1.118 -r1.123 --- src/sys/arch/i386/i386/locore.S 2016/05/14 06:49:34 1.118 +++ src/sys/arch/i386/i386/locore.S 2016/05/15 07:01:36 1.123 @@ -1,4 +1,4 @@ -/* $NetBSD: locore.S,v 1.118 2016/05/14 06:49:34 maxv Exp $ */ +/* $NetBSD: locore.S,v 1.123 2016/05/15 07:01:36 maxv Exp $ */ /* * Copyright-o-rama! @@ -128,7 +128,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: locore.S,v 1.118 2016/05/14 06:49:34 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: locore.S,v 1.123 2016/05/15 07:01:36 maxv Exp $"); #include "opt_compat_oldboot.h" #include "opt_copy_symtab.h" @@ -168,6 +168,9 @@ __KERNEL_RCSID(0, "$NetBSD: locore.S,v 1 #endif /* XEN */ #define RELOC(x) _RELOC(_C_LABEL(x)) +/* 32bit version of PG_NX */ +#define PG_NX32 0x80000000 + #ifndef PAE #define PROC0_PDIR_OFF 0 #else @@ -188,7 +191,6 @@ __KERNEL_RCSID(0, "$NetBSD: locore.S,v 1 * This is done by the first instruction of fillkpt. In the non-PAE case, this * instruction just clears the page table entry. */ - #define fillkpt \ 1: movl $0,(PDE_SIZE-4)(%ebx) ; /* upper 32 bits: 0 */ \ movl %eax,(%ebx) ; /* store phys addr */ \ @@ -197,6 +199,19 @@ __KERNEL_RCSID(0, "$NetBSD: locore.S,v 1 loop 1b ; /* + * fillkpt_nox - Same as fillkpt, but sets the NX/XD bit. + */ +#define fillkpt_nox \ + pushl %ebp ; \ + movl RELOC(nox_flag),%ebp ; \ +1: movl %ebp,(PDE_SIZE-4)(%ebx) ; /* upper 32 bits: NX */ \ + movl %eax,(%ebx) ; /* store phys addr */ \ + addl $PDE_SIZE,%ebx ; /* next PTE/PDE */ \ + addl $PAGE_SIZE,%eax ; /* next phys page */ \ + loop 1b ; \ + popl %ebp ; + +/* * killkpt - Destroy a kernel page table * ebx = page table address * ecx = number of pages to destroy @@ -234,6 +249,7 @@ __KERNEL_RCSID(0, "$NetBSD: locore.S,v 1 */ .data + .globl _C_LABEL(nox_flag) .globl _C_LABEL(cputype) .globl _C_LABEL(cpuid_level) .globl _C_LABEL(esym) @@ -279,6 +295,10 @@ LABEL(lapic_tpr) .long 0 END(lapic_tpr) #endif + + .type _C_LABEL(nox_flag), @object +LABEL(nox_flag) .long 0 /* 32bit NOX flag, set if supported */ +END(nox_flag) .type _C_LABEL(cputype), @object LABEL(cputype) .long 0 /* are we 80486, Pentium, or.. */ END(cputype) @@ -534,6 +554,16 @@ try586: /* Use the `cpuid' instruction. cpuid movl %eax,RELOC(cpuid_level) + /* + * Retrieve the NX/XD flag. We use the 32bit version of PG_NX. + */ + movl $0x80000001,%eax + cpuid + andl $CPUID_NOX,%edx + jz no_NOX + movl $PG_NX32,RELOC(nox_flag) +no_NOX: + 2: /* * Finished with old stack; load new %esp now instead of later so we @@ -581,6 +611,9 @@ try586: /* Use the `cpuid' instruction. * * PROC0 STK is obviously not linked as a page level. It just happens to be * caught between L2 and L1. + * + * Important note: the kernel segments are properly 4k-aligned + * (see kern.ldscript), so there's no need to enforce alignment. */ /* Find end of kernel image; brings us on (1). */ @@ -653,10 +686,6 @@ try586: /* Use the `cpuid' instruction. */ leal (PROC0_PTP1_OFF)(%esi),%ebx - /* Compute &__rodata_start - KERNBASE. */ - movl $RELOC(__rodata_start),%edx - andl $~PGOFSET,%edx - /* Skip the first MB. */ movl $(KERNTEXTOFF - KERNBASE),%eax movl %eax,%ecx @@ -666,22 +695,46 @@ try586: /* Use the `cpuid' instruction. #endif addl %ecx,%ebx - /* Map the kernel text read-only. */ - movl %edx,%ecx + /* Map the kernel text RX. */ + movl $RELOC(__rodata_start),%ecx subl %eax,%ecx shrl $PGSHIFT,%ecx orl $(PG_V|PG_KR),%eax fillkpt - /* Map the data, BSS, and bootstrap tables read-write. */ - leal (PG_V|PG_KW)(%edx),%eax - movl RELOC(tablesize),%ecx - addl %esi,%ecx /* end of tables */ - subl %edx,%ecx /* subtract end of text */ + /* Map the kernel rodata R. */ + movl $RELOC(__rodata_start),%eax + movl $RELOC(__data_start),%ecx + subl %eax,%ecx + shrl $PGSHIFT,%ecx + orl $(PG_V|PG_KR),%eax + fillkpt_nox + + /* Map the kernel data+bss RW. */ + movl $RELOC(__data_start),%eax + movl $RELOC(__kernel_end),%ecx + subl %eax,%ecx shrl $PGSHIFT,%ecx + orl $(PG_V|PG_KW),%eax + fillkpt_nox + + /* + * We actually have to be careful here. The memory layout is as + * follows: + * +----------+---------------------+------------------+ + * | DATA+BSS < [PRELOADED MODULES] | BOOTSTRAP TABLES > + * +----------+---------------------+------------------+ + * We just map everything from < to > with RWX rights. + */ + movl $RELOC(__kernel_end),%eax + movl %esi,%ecx /* start of BOOTSTRAP TABLES */ + addl RELOC(tablesize),%ecx /* end of BOOTSTRAP TABLES */ + subl %eax,%ecx /* subtract end of kernel image */ + shrl $PGSHIFT,%ecx + orl $(PG_V|PG_KW),%eax fillkpt - /* Map ISA I/O mem (later atdevbase) */ + /* We are on (4). Map ISA I/O mem (later atdevbase) RWX. */ movl $(IOM_BEGIN|PG_V|PG_KW/*|PG_N*/),%eax movl $(IOM_SIZE>>PGSHIFT),%ecx fillkpt @@ -737,7 +790,20 @@ try586: /* Use the `cpuid' instruction. movl %eax,%cr3 /* - * 2. Enable paging and the rest of it. + * 2. Set NOX in EFER, if available. + */ + movl RELOC(nox_flag),%ebx + cmpl $0,%ebx + je skip_NOX + movl $MSR_EFER,%ecx + rdmsr + xorl %eax,%eax + orl $(EFER_NXE),%eax + wrmsr +skip_NOX: + + /* + * 3. Enable paging and the rest of it. */ movl %cr0,%eax orl $(CR0_PE|CR0_PG|CR0_NE|CR0_TS|CR0_MP|CR0_WP|CR0_AM),%eax