Add the PG_NX support for i386/PAE.
Reviewed by: alc
This commit is contained in:
parent
d4909d3f26
commit
754d500925
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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++;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user