kernel -- x86_64: Do not set reserved bits in CR3.
authorAggelos Economopoulos <aggelos@dragonflybsd.org>
Mon, 20 May 2013 18:56:07 +0000 (20:56 +0200)
committerAggelos Economopoulos <aggelos@dragonflybsd.org>
Mon, 20 May 2013 18:56:07 +0000 (20:56 +0200)
The x86-64 platform code was setting PG_V, PG_U, and PG_RW bits in the
CR3 register. While the bits were supposed to cleared, Intel and AMD
hardware were ignoring them. Other x86-64 implementations, in
particular the software emulator in Linux's KVM, do check that these
reserved bits are zero.

Fixes issue running DragonFly x86_64 on KVM hosts without
two-dimensional (nested) paging.

Tested on a variety of real hardware (AMD FX(tm)-8150, c2q 6600, others)
and VM configurations (KVM on Intel/AMD hosts, Xen).

Committing-on-behalf-of: Venkatesh Srinivas <vsrinivas@ops101.org>
Reported-by: aggelos@, c.turner1, others.
Testing-by: aggelos@, swildner@, mneumann@, ftigeot@, profmakx@, Enjolras
Bug: 2561

sys/platform/pc64/x86_64/pmap.c
sys/platform/pc64/x86_64/vm_machdep.c

index 9746be4..ee6d0b2 100644 (file)
@@ -4522,7 +4522,6 @@ pmap_setlwpvm(struct lwp *lp, struct vmspace *newvm)
                        tlb_flush_count++;
 #endif
                        curthread->td_pcb->pcb_cr3 = vtophys(pmap->pm_pml4);
-                       curthread->td_pcb->pcb_cr3 |= PG_RW | PG_U | PG_V;
                        load_cr3(curthread->td_pcb->pcb_cr3);
                        pmap = vmspace_pmap(oldvm);
                        atomic_clear_cpumask(&pmap->pm_active, mycpu->gd_cpumask);
index 5fb3e64..c68b5aa 100644 (file)
@@ -140,7 +140,6 @@ cpu_fork(struct lwp *lp1, struct lwp *lp2, int flags)
         * return address on stack.  These are the kernel mode register values.
         */
        pcb2->pcb_cr3 = vtophys(vmspace_pmap(lp2->lwp_proc->p_vmspace)->pm_pml4);
-       pcb2->pcb_cr3 |= PG_RW | PG_U | PG_V;
        pcb2->pcb_rbx = (unsigned long)fork_return;     /* fork_trampoline argument */
        pcb2->pcb_rbp = 0;
        pcb2->pcb_rsp = (unsigned long)lp2->lwp_md.md_regs - sizeof(void *);