Add the PG_NX support for i386/PAE.

Reviewed by:	alc
This commit is contained in:
ru 2007-04-06 18:15:03 +00:00
parent d4909d3f26
commit 754d500925
8 changed files with 135 additions and 34 deletions

View File

@ -188,20 +188,6 @@ printcpuinfo(void)
}
}
/* Detect AMD features (PTE no-execute bit, 3dnow, 64 bit mode etc) */
if (strcmp(cpu_vendor, "GenuineIntel") == 0 ||
strcmp(cpu_vendor, "AuthenticAMD") == 0) {
if (cpu_exthigh >= 0x80000001) {
do_cpuid(0x80000001, regs);
amd_feature = regs[3] & ~(cpu_feature & 0x0183f3ff);
amd_feature2 = regs[2];
}
if (cpu_exthigh >= 0x80000008) {
do_cpuid(0x80000008, regs);
cpu_procinfo2 = regs[2];
}
}
if (strcmp(cpu_vendor, "GenuineIntel") == 0) {
if ((cpu_id & 0xf00) > 0x300) {
u_int brand_index;
@ -1104,7 +1090,20 @@ finishidentcpu(void)
u_char ccr3;
u_int regs[4];
if (strcmp(cpu_vendor, "CyrixInstead") == 0) {
/* Detect AMD features (PTE no-execute bit, 3dnow, 64 bit mode etc) */
if (strcmp(cpu_vendor, "GenuineIntel") == 0 ||
strcmp(cpu_vendor, "AuthenticAMD") == 0) {
init_exthigh();
if (cpu_exthigh >= 0x80000001) {
do_cpuid(0x80000001, regs);
amd_feature = regs[3] & ~(cpu_feature & 0x0183f3ff);
amd_feature2 = regs[2];
}
if (cpu_exthigh >= 0x80000008) {
do_cpuid(0x80000008, regs);
cpu_procinfo2 = regs[2];
}
} else if (strcmp(cpu_vendor, "CyrixInstead") == 0) {
if (cpu == CPU_486) {
/*
* These conditions are equivalent to:

View File

@ -41,6 +41,9 @@ __FBSDID("$FreeBSD$");
#include <machine/md_var.h>
#include <machine/specialreg.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#if !defined(CPU_DISABLE_SSE) && defined(I686_CPU)
#define CPU_ENABLE_SSE
#endif
@ -686,6 +689,15 @@ initializecpu(void)
break;
}
}
#ifdef PAE
if ((amd_feature & AMDID_NX) != 0) {
uint64_t msr;
msr = rdmsr(MSR_EFER) | EFER_NXE;
wrmsr(MSR_EFER, msr);
pg_nx = PG_NX;
}
#endif
break;
#endif
default:

View File

@ -211,7 +211,7 @@ minidumpsys(struct dumperinfo *di)
j = va >> PDRSHIFT;
if ((pd[j] & (PG_PS | PG_V)) == (PG_PS | PG_V)) {
/* This is an entire 2M page. */
pa = pd[j] & PG_FRAME & ~PDRMASK;
pa = pd[j] & PG_PS_FRAME;
for (k = 0; k < NPTEPG; k++) {
if (is_dumpable(pa))
dump_add_page(pa);
@ -310,7 +310,7 @@ minidumpsys(struct dumperinfo *di)
j = va >> PDRSHIFT;
if ((pd[j] & (PG_PS | PG_V)) == (PG_PS | PG_V)) {
/* This is a single 2M block. Generate a fake PTP */
pa = pd[j] & PG_FRAME & ~PDRMASK;
pa = pd[j] & PG_PS_FRAME;
for (k = 0; k < NPTEPG; k++) {
fakept[k] = (pa + (k * PAGE_SIZE)) | PG_V | PG_RW | PG_A | PG_M;
}

View File

@ -206,6 +206,7 @@ vm_offset_t kernel_vm_end;
extern u_int32_t KERNend;
#ifdef PAE
pt_entry_t pg_nx;
static uma_zone_t pdptzone;
#endif
@ -958,7 +959,7 @@ pmap_extract(pmap_t pmap, vm_offset_t va)
pde = pmap->pm_pdir[va >> PDRSHIFT];
if (pde != 0) {
if ((pde & PG_PS) != 0) {
rtval = (pde & ~PDRMASK) | (va & PDRMASK);
rtval = (pde & PG_PS_FRAME) | (va & PDRMASK);
PMAP_UNLOCK(pmap);
return rtval;
}
@ -991,7 +992,7 @@ pmap_extract_and_hold(pmap_t pmap, vm_offset_t va, vm_prot_t prot)
if (pde != 0) {
if (pde & PG_PS) {
if ((pde & PG_RW) || (prot & VM_PROT_WRITE) == 0) {
m = PHYS_TO_VM_PAGE((pde & ~PDRMASK) |
m = PHYS_TO_VM_PAGE((pde & PG_PS_FRAME) |
(va & PDRMASK));
vm_page_hold(m);
}
@ -1365,7 +1366,7 @@ pmap_allocpte(pmap_t pmap, vm_offset_t va, int flags)
* hold count, and activate it.
*/
if (ptepa) {
m = PHYS_TO_VM_PAGE(ptepa);
m = PHYS_TO_VM_PAGE(ptepa & PG_FRAME);
m->wire_count++;
} else {
/*
@ -1498,7 +1499,8 @@ pmap_release(pmap_t pmap)
mtx_unlock_spin(&allpmaps_lock);
for (i = 0; i < NPGPTD; i++)
ptdpg[i] = PHYS_TO_VM_PAGE(pmap->pm_pdir[PTDPTDI + i]);
ptdpg[i] = PHYS_TO_VM_PAGE(pmap->pm_pdir[PTDPTDI + i] &
PG_FRAME);
bzero(pmap->pm_pdir + PTDPTDI, (nkpt + NPGPTD) *
sizeof(*pmap->pm_pdir));
@ -1946,7 +1948,7 @@ pmap_remove_pte(pmap_t pmap, pt_entry_t *ptq, vm_offset_t va)
pmap_invalidate_page(kernel_pmap, va);
pmap->pm_stats.resident_count -= 1;
if (oldpte & PG_MANAGED) {
m = PHYS_TO_VM_PAGE(oldpte);
m = PHYS_TO_VM_PAGE(oldpte & PG_FRAME);
if (oldpte & PG_M) {
KASSERT((oldpte & PG_RW),
("pmap_remove_pte: modified page not writable: va: %#x, pte: %#jx",
@ -2154,8 +2156,14 @@ pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
return;
}
#ifdef PAE
if ((prot & (VM_PROT_WRITE|VM_PROT_EXECUTE)) ==
(VM_PROT_WRITE|VM_PROT_EXECUTE))
return;
#else
if (prot & VM_PROT_WRITE)
return;
#endif
anychanged = 0;
@ -2163,7 +2171,8 @@ pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
sched_pin();
PMAP_LOCK(pmap);
for (; sva < eva; sva = pdnxt) {
unsigned obits, pbits, pdirindex;
pt_entry_t obits, pbits;
unsigned pdirindex;
pdnxt = (sva + NBPDR) & ~PDRMASK;
@ -2181,7 +2190,12 @@ pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
* Check for large page.
*/
if ((ptpaddr & PG_PS) != 0) {
pmap->pm_pdir[pdirindex] &= ~(PG_M|PG_RW);
if ((prot & VM_PROT_WRITE) == 0)
pmap->pm_pdir[pdirindex] &= ~(PG_M|PG_RW);
#ifdef PAE
if ((prot & VM_PROT_EXECUTE) == 0)
pmap->pm_pdir[pdirindex] |= pg_nx;
#endif
anychanged = 1;
continue;
}
@ -2199,27 +2213,39 @@ pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
* size, PG_RW, PG_A, and PG_M are among the least
* significant 32 bits.
*/
obits = pbits = *(u_int *)pte;
obits = pbits = *pte;
if ((pbits & PG_V) == 0)
continue;
if (pbits & PG_MANAGED) {
m = NULL;
if (pbits & PG_A) {
m = PHYS_TO_VM_PAGE(*pte);
m = PHYS_TO_VM_PAGE(pbits & PG_FRAME);
vm_page_flag_set(m, PG_REFERENCED);
pbits &= ~PG_A;
}
if ((pbits & PG_M) != 0) {
if (m == NULL)
m = PHYS_TO_VM_PAGE(*pte);
m = PHYS_TO_VM_PAGE(pbits & PG_FRAME);
vm_page_dirty(m);
}
}
pbits &= ~(PG_RW | PG_M);
if ((prot & VM_PROT_WRITE) == 0)
pbits &= ~(PG_RW | PG_M);
#ifdef PAE
if ((prot & VM_PROT_EXECUTE) == 0)
pbits |= pg_nx;
#endif
if (pbits != obits) {
#ifdef PAE
if (!atomic_cmpset_64(pte, obits, pbits))
goto retry;
#else
if (!atomic_cmpset_int((u_int *)pte, obits,
pbits))
goto retry;
#endif
if (obits & PG_G)
pmap_invalidate_page(pmap, sva);
else
@ -2384,6 +2410,10 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
newpte |= PG_RW;
vm_page_flag_set(m, PG_WRITEABLE);
}
#ifdef PAE
if ((prot & VM_PROT_EXECUTE) == 0)
newpte |= pg_nx;
#endif
if (wired)
newpte |= PG_W;
if (va < VM_MAXUSER_ADDRESS)
@ -2404,6 +2434,11 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
vm_page_flag_set(om, PG_REFERENCED);
if (opa != VM_PAGE_TO_PHYS(m))
invlva = TRUE;
#ifdef PAE
if ((origpte & PG_NX) == 0 &&
(newpte & PG_NX) != 0)
invlva = TRUE;
#endif
}
if (origpte & PG_M) {
KASSERT((origpte & PG_RW),
@ -2514,7 +2549,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m,
if (ptepa) {
if (ptepa & PG_PS)
panic("pmap_enter_quick: unexpected mapping into 4MB page");
mpte = PHYS_TO_VM_PAGE(ptepa);
mpte = PHYS_TO_VM_PAGE(ptepa & PG_FRAME);
mpte->wire_count++;
} else {
mpte = _pmap_allocpte(pmap, ptepindex,
@ -2560,6 +2595,10 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m,
pmap->pm_stats.resident_count++;
pa = VM_PAGE_TO_PHYS(m);
#ifdef PAE
if ((prot & VM_PROT_EXECUTE) == 0)
pa |= pg_nx;
#endif
/*
* Now validate mapping with RO protection
@ -2746,7 +2785,7 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
continue;
}
srcmpte = PHYS_TO_VM_PAGE(srcptepaddr);
srcmpte = PHYS_TO_VM_PAGE(srcptepaddr & PG_FRAME);
if (srcmpte->wire_count == 0)
panic("pmap_copy: source page table page is unused");
@ -2990,7 +3029,7 @@ pmap_remove_pages(pmap_t pmap)
continue;
}
m = PHYS_TO_VM_PAGE(tpte);
m = PHYS_TO_VM_PAGE(tpte & PG_FRAME);
KASSERT(m->phys_addr == (tpte & PG_FRAME),
("vm_page_t %p phys_addr mismatch %016jx %016jx",
m, (uintmax_t)m->phys_addr,
@ -3521,7 +3560,7 @@ pmap_pid_dump(int pid)
pt_entry_t pa;
vm_page_t m;
pa = *pte;
m = PHYS_TO_VM_PAGE(pa);
m = PHYS_TO_VM_PAGE(pa & PG_FRAME);
printf("va: 0x%x, pt: 0x%x, h: %d, w: %d, f: 0x%x",
va, pa, m->hold_count, m->wire_count, m->flags);
npte++;

View File

@ -736,8 +736,16 @@ trap_pfault(frame, usermode, eva)
map = &vm->vm_map;
}
/*
* PGEX_I is defined only if the execute disable bit capability is
* supported and enabled.
*/
if (frame->tf_err & PGEX_W)
ftype = VM_PROT_WRITE;
#ifdef PAE
else if ((frame->tf_err & PGEX_I) && pg_nx != 0)
ftype = VM_PROT_EXECUTE;
#endif
else
ftype = VM_PROT_READ;

View File

@ -63,12 +63,21 @@
#define PG_AVAIL2 0x400 /* < programmers use */
#define PG_AVAIL3 0x800 /* \ */
#define PG_PDE_PAT 0x1000 /* PAT PAT index */
#ifdef PAE
#define PG_NX (1ull<<63) /* No-execute */
#endif
/* Our various interpretations of the above */
#define PG_W PG_AVAIL1 /* "Wired" pseudoflag */
#define PG_MANAGED PG_AVAIL2
#define PG_FRAME (~((vm_paddr_t)PAGE_MASK))
#ifdef PAE
#define PG_FRAME (0x000ffffffffff000ull)
#define PG_PS_FRAME (0x000fffffffe00000ull)
#else
#define PG_FRAME (~PAGE_MASK)
#define PG_PS_FRAME (0xffc00000)
#endif
#define PG_PROT (PG_RW|PG_U) /* all protection bits . */
#define PG_N (PG_NC_PWT|PG_NC_PCD) /* Non-cacheable */
@ -79,6 +88,7 @@
#define PGEX_P 0x01 /* Protection violation vs. not present */
#define PGEX_W 0x02 /* during a Write cycle */
#define PGEX_U 0x04 /* access from User mode (UPL) */
#define PGEX_I 0x10 /* during an instruction fetch */
/*
* Size of Kernel address space. This is the number of page table pages
@ -201,7 +211,7 @@ pmap_kextract(vm_offset_t va)
vm_paddr_t pa;
if ((pa = PTD[va >> PDRSHIFT]) & PG_PS) {
pa = (pa & ~(NBPDR - 1)) | (va & (NBPDR - 1));
pa = (pa & PG_PS_FRAME) | (va & PDRMASK);
} else {
pa = *vtopte(va);
pa = (pa & PG_FRAME) | (va & PAGE_MASK);
@ -238,10 +248,33 @@ pte_load_store(pt_entry_t *ptep, pt_entry_t v)
return (r);
}
/* XXXRU move to atomic.h? */
static __inline int
atomic_cmpset_64(volatile uint64_t *dst, uint64_t exp, uint64_t src)
{
int64_t res = exp;
__asm __volatile (
" lock ; "
" cmpxchg8b %2 ; "
" setz %%al ; "
" movzbl %%al,%0 ; "
"# atomic_cmpset_64"
: "+A" (res), /* 0 (result) */
"=m" (*dst) /* 1 */
: "m" (*dst), /* 2 */
"b" ((uint32_t)src),
"c" ((uint32_t)(src >> 32)));
return (res);
}
#define pte_load_clear(ptep) pte_load_store((ptep), (pt_entry_t)0ULL)
#define pte_store(ptep, pte) pte_load_store((ptep), (pt_entry_t)pte)
extern pt_entry_t pg_nx;
#else /* PAE */
static __inline pt_entry_t

View File

@ -67,6 +67,11 @@
#define CR4_FXSR 0x00000200 /* Fast FPU save/restore used by OS */
#define CR4_XMM 0x00000400 /* enable SIMD/MMX2 to use except 16 */
/*
* Bits in AMD64 special registers. EFER is 64 bits wide.
*/
#define EFER_NXE 0x000000800 /* PTE No-Execute bit enable (R/W) */
/*
* CPUID instruction features register
*/
@ -420,6 +425,9 @@
#define AMD_WT_ALLOC_PRE 0x20000 /* programmable range enable */
#define AMD_WT_ALLOC_FRE 0x10000 /* fixed (A0000-FFFFF) range enable */
/* AMD64 MSR's */
#define MSR_EFER 0xc0000080 /* extended features */
/* VIA ACE crypto featureset: for via_feature_rng */
#define VIA_HAS_RNG 1 /* cpu has RNG */

View File

@ -43,7 +43,9 @@
* Machine dependent constants for 386.
*/
#ifndef PAE
#define VM_PROT_READ_IS_EXEC /* if you can read -- then you can exec */
#endif
/*
* Virtual memory related constants, all in bytes