diff options
author | Mike Larkin <mlarkin@cvs.openbsd.org> | 2015-04-12 18:37:55 +0000 |
---|---|---|
committer | Mike Larkin <mlarkin@cvs.openbsd.org> | 2015-04-12 18:37:55 +0000 |
commit | 2319283cdb7317249a07e8732b8d8b8fb971acf5 (patch) | |
tree | 6d8d6fb72835846824861046cdbb44c16798dfb4 /sys/arch/i386/include | |
parent | d91f6149b68e83b07a138caf364b545255828b73 (diff) |
Bring PAE code back to life, in a different form. This diff (via bluhm then
to deraadt, then myself) brings the PAE pmap on i386 (not touched in any
significant way for years) closer to the current non-PAE pmap and allows
us to take a big next step toward better i386 W^X in the kernel (similar to
what we did a few months ago on amd64). Unlike the original PAE pmap, this
diff will not be supporting > 4GB physical memory on i386 - this effort is
specifically geared toward providing W^X (via NX) only.
There still seems to be a bug removing certain pmap entries when PAE is
enabled, so I'm leaving PAE mode disabled for the moment until we can
figure out what is going on, but with this diff in the tree hopefully
others can help.
The pmap functions now operate through function pointers, due to the need
to support both non-PAE and PAE forms. My unscientific testing showed
less than 0.3% (a third of a percent) slowdown with this approach during
a base build.
Discussed for months with guenther, kettenis, and deraadt.
ok kettenis@, deraadt@
Diffstat (limited to 'sys/arch/i386/include')
-rw-r--r-- | sys/arch/i386/include/biosvar.h | 5 | ||||
-rw-r--r-- | sys/arch/i386/include/cpu.h | 3 | ||||
-rw-r--r-- | sys/arch/i386/include/pmap.h | 284 | ||||
-rw-r--r-- | sys/arch/i386/include/pte.h | 25 |
4 files changed, 198 insertions, 119 deletions
diff --git a/sys/arch/i386/include/biosvar.h b/sys/arch/i386/include/biosvar.h index 1f95cdc1376..afe03ffe631 100644 --- a/sys/arch/i386/include/biosvar.h +++ b/sys/arch/i386/include/biosvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: biosvar.h,v 1.61 2013/11/02 15:02:27 kettenis Exp $ */ +/* $OpenBSD: biosvar.h,v 1.62 2015/04/12 18:37:54 mlarkin Exp $ */ /* * Copyright (c) 1997-1999 Michael Shalayeff @@ -35,9 +35,6 @@ #define BOOTBIOS_ADDR (0x7c00) #define BOOTBIOS_MAXSEC ((1 << 28) - 1) - /* physical page for ptp 0 need for various tramps */ -#define PTP0_PA (PAGE_SIZE * 3) - /* BIOS configure flags */ #define BIOSF_BIOS32 0x0001 #define BIOSF_PCIBIOS 0x0002 diff --git a/sys/arch/i386/include/cpu.h b/sys/arch/i386/include/cpu.h index 36aec9df34f..516bbe1f3ca 100644 --- a/sys/arch/i386/include/cpu.h +++ b/sys/arch/i386/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.137 2014/12/16 21:40:05 tedu Exp $ */ +/* $OpenBSD: cpu.h,v 1.138 2015/04/12 18:37:54 mlarkin Exp $ */ /* $NetBSD: cpu.h,v 1.35 1996/05/05 19:29:26 christos Exp $ */ /*- @@ -458,6 +458,7 @@ void mp_setperf_init(void); void vm86_gpfault(struct proc *, int); #endif /* VM86 */ +int cpu_paenable(void *); #endif /* _KERNEL */ /* diff --git a/sys/arch/i386/include/pmap.h b/sys/arch/i386/include/pmap.h index 4d3e0bfbc06..6aa02e3e7c0 100644 --- a/sys/arch/i386/include/pmap.h +++ b/sys/arch/i386/include/pmap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pmap.h,v 1.72 2015/03/13 23:23:13 mlarkin Exp $ */ +/* $OpenBSD: pmap.h,v 1.73 2015/04/12 18:37:54 mlarkin Exp $ */ /* $NetBSD: pmap.h,v 1.44 2000/04/24 17:18:18 thorpej Exp $ */ /* @@ -42,14 +42,6 @@ #include <uvm/uvm_object.h> /* - * The following defines identify the slots used as described above. - */ - -#define PDSLOT_PTE ((KERNBASE/NBPD)-1) /* 831: for recursive PDP map */ -#define PDSLOT_KERN (KERNBASE/NBPD) /* 832: start of kernel space */ -#define PDSLOT_APTE ((unsigned)1023) /* 1023: alternative recursive slot */ - -/* * The following defines give the virtual addresses of various MMU * data structures: * PTE_BASE and APTE_BASE: the base VA of the linear PTE mappings @@ -57,12 +49,9 @@ * PDP_PDE and APDP_PDE: the VA of the PDE that points back to the PDP/APDP */ -#define PTE_BASE ((pt_entry_t *) (PDSLOT_PTE * NBPD) ) -#define APTE_BASE ((pt_entry_t *) (PDSLOT_APTE * NBPD) ) -#define PDP_BASE ((pd_entry_t *)(((char *)PTE_BASE) + (PDSLOT_PTE * PAGE_SIZE))) -#define APDP_BASE ((pd_entry_t *)(((char *)APTE_BASE) + (PDSLOT_APTE * PAGE_SIZE))) -#define PDP_PDE (PDP_BASE + PDSLOT_PTE) -#define APDP_PDE (PDP_BASE + PDSLOT_APTE) +#define PDSLOT_PTE ((KERNBASE/NBPD)-2) /* 830: for recursive PDP map */ +#define PDSLOT_KERN (KERNBASE/NBPD) /* 832: start of kernel space */ +#define PDSLOT_APTE ((unsigned)1022) /* 1022: alternative recursive slot */ /* * The following define determines how many PTPs should be set up for the @@ -71,48 +60,10 @@ * pmap module can add more PTPs to the kernel area on demand. */ -#ifndef NKPTP -#define NKPTP 4 /* 16MB to start */ +#ifndef NKPTP +#define NKPTP 8 /* 16/32MB to start */ #endif -#define NKPTP_MIN 4 /* smallest value we allow */ -#define NKPTP_MAX (1024 - (KERNBASE/NBPD) - 1) - /* largest value (-1 for APTP space) */ - -/* - * various address macros - * - * vtopte: return a pointer to the PTE mapping a VA - * kvtopte: same as above (takes a KVA, but doesn't matter with this pmap) - * ptetov: given a pointer to a PTE, return the VA that it maps - * vtophys: translate a VA to the PA mapped to it - * - * plus alternative versions of the above - */ - -#define vtopte(VA) (PTE_BASE + atop(VA)) -#define kvtopte(VA) vtopte(VA) -#define ptetov(PT) (ptoa(PT - PTE_BASE)) -#define vtophys(VA) ((*vtopte(VA) & PG_FRAME) | \ - ((unsigned)(VA) & ~PG_FRAME)) -#define avtopte(VA) (APTE_BASE + atop(VA)) -#define ptetoav(PT) (ptoa(PT - APTE_BASE)) -#define avtophys(VA) ((*avtopte(VA) & PG_FRAME) | \ - ((unsigned)(VA) & ~PG_FRAME)) - -/* - * PTP macros: - * A PTP's index is the PD index of the PDE that points to it. - * A PTP's offset is the byte-offset in the PTE space that this PTP is at. - * A PTP's VA is the first VA mapped by that PTP. - * - * Note that PAGE_SIZE == number of bytes in a PTP (4096 bytes == 1024 entries) - * NBPD == number of bytes a PTP can map (4MB) - */ - -#define ptp_i2o(I) ((I) * PAGE_SIZE) /* index => offset */ -#define ptp_o2i(O) ((O) / PAGE_SIZE) /* offset => index */ -#define ptp_i2v(I) ((I) * NBPD) /* index => VA */ -#define ptp_v2i(V) ((V) / NBPD) /* VA => index (same as pdei) */ +#define NKPTP_MIN 4 /* smallest value we allow */ /* * PG_AVAIL usage: we make use of the ignored bits of the PTE @@ -122,6 +73,8 @@ #define PG_PVLIST PG_AVAIL2 /* mapping has entry on pvlist */ #define PG_X PG_AVAIL3 /* executable mapping */ +#define PTP0_PA (PAGE_SIZE * 3) + #ifdef _KERNEL /* * pmap data structures: see pmap.c for details of locking. @@ -144,11 +97,13 @@ LIST_HEAD(pmap_head, pmap); /* struct pmap_head: head of a pmap list */ */ struct pmap { + uint64_t pm_pdidx[4]; /* PDIEs for PAE mode */ + paddr_t pm_pdirpa; /* PA of PD (read-only after create) */ + vaddr_t pm_pdir; /* VA of PD (lck by object lock) */ + int pm_pdirsize; /* PD size (4k vs 16k on PAE) */ struct uvm_object pm_obj; /* object (lck by object lock) */ #define pm_lock pm_obj.vmobjlock LIST_ENTRY(pmap) pm_list; /* list (lck by pm_list lock) */ - pd_entry_t *pm_pdir; /* VA of PD (lck by object lock) */ - paddr_t pm_pdirpa; /* PA of PD (read-only after create) */ struct vm_page *pm_ptphint; /* pointer to a PTP in our pmap */ struct pmap_statistics pm_stats; /* pmap stats (lck by object lock) */ @@ -223,18 +178,24 @@ struct pv_page { struct pv_entry pvents[PVE_PER_PVPAGE]; }; + /* - * global kernel variables + * pv_entrys are dynamically allocated in chunks from a single page. + * we keep track of how many pv_entrys are in use for each page and + * we can free pv_entry pages if needed. There is one lock for the + * entire allocation system. */ -extern pd_entry_t PTD[]; +extern char PTD[]; +extern struct pmap kernel_pmap_store; /* kernel pmap */ +extern int nkptp_max; -/* PTDpaddr: is the physical address of the kernel's PDP */ -extern u_int32_t PTDpaddr; +#define PMAP_REMOVE_ALL 0 +#define PMAP_REMOVE_SKIPWIRED 1 -extern struct pmap kernel_pmap_store; /* kernel pmap */ -extern int nkpde; /* current # of PDEs for kernel */ -extern int pmap_pg_g; /* do we support PG_G? */ +#define ALLOCPV_NEED 0 /* need PV now */ +#define ALLOCPV_TRY 1 /* just try to allocate */ +#define ALLOCPV_NONEED 2 /* don't need PV, just growing cache */ /* * Macros @@ -256,53 +217,153 @@ extern int pmap_pg_g; /* do we support PG_G? */ #define pmap_unuse_final(p) /* nothing */ #define pmap_remove_holes(vm) do { /* nothing */ } while (0) - /* * Prototypes */ -void pmap_bootstrap(vaddr_t); -boolean_t pmap_clear_attrs(struct vm_page *, int); -static void pmap_page_protect(struct vm_page *, vm_prot_t); -void pmap_page_remove(struct vm_page *); -static void pmap_protect(struct pmap *, vaddr_t, - vaddr_t, vm_prot_t); -void pmap_remove(struct pmap *, vaddr_t, vaddr_t); -boolean_t pmap_test_attrs(struct vm_page *, int); -void pmap_write_protect(struct pmap *, vaddr_t, - vaddr_t, vm_prot_t); -int pmap_exec_fixup(struct vm_map *, struct trapframe *, - struct pcb *); -void pmap_switch(struct proc *, struct proc *); - +vaddr_t pmap_tmpmap_pa(paddr_t); +void pmap_tmpunmap_pa(void); + +void pmap_bootstrap(vaddr_t); +void pmap_bootstrap_pae(void); +void pmap_virtual_space(vaddr_t *, vaddr_t *); +void pmap_init(void); +struct pmap *pmap_create(void); +void pmap_destroy(struct pmap *); +void pmap_reference(struct pmap *); +void pmap_fork(struct pmap *, struct pmap *); +void pmap_remove(struct pmap *, vaddr_t, vaddr_t); +void pmap_collect(struct pmap *); +void pmap_activate(struct proc *); +void pmap_deactivate(struct proc *); +void pmap_kenter_pa(vaddr_t, paddr_t, vm_prot_t); +void pmap_kremove(vaddr_t, vsize_t); +void pmap_zero_page(struct vm_page *); +void pmap_copy_page(struct vm_page *, struct vm_page *); +void pmap_enter_pv(struct vm_page *, struct pv_entry *, + struct pmap *, vaddr_t, struct vm_page *); +void pmap_free_pvs(struct pmap *, struct pv_entry *); +boolean_t pmap_clear_attrs(struct vm_page *, int); +static void pmap_page_protect(struct vm_page *, vm_prot_t); +void pmap_page_remove(struct vm_page *); +static void pmap_protect(struct pmap *, vaddr_t, + vaddr_t, vm_prot_t); +void pmap_remove(struct pmap *, vaddr_t, vaddr_t); +boolean_t pmap_test_attrs(struct vm_page *, int); +void pmap_write_protect(struct pmap *, vaddr_t, + vaddr_t, vm_prot_t); +int pmap_exec_fixup(struct vm_map *, struct trapframe *, + struct pcb *); +void pmap_exec_account(struct pmap *, vaddr_t, u_int32_t, + u_int32_t); +struct pv_entry *pmap_remove_pv(struct vm_page *, struct pmap *, vaddr_t); +void pmap_apte_flush(void); +void pmap_switch(struct proc *, struct proc *); vaddr_t reserve_dumppages(vaddr_t); /* XXX: not a pmap fn */ - -void pmap_tlb_shootpage(struct pmap *, vaddr_t); -void pmap_tlb_shootrange(struct pmap *, vaddr_t, vaddr_t); -void pmap_tlb_shoottlb(void); +paddr_t vtophys(vaddr_t va); +paddr_t vtophys_pae(vaddr_t va); + +extern u_int32_t (*pmap_pte_set_p)(vaddr_t, paddr_t, u_int32_t); +extern u_int32_t (*pmap_pte_setbits_p)(vaddr_t, u_int32_t, u_int32_t); +extern u_int32_t (*pmap_pte_bits_p)(vaddr_t); +extern paddr_t (*pmap_pte_paddr_p)(vaddr_t); +extern boolean_t (*pmap_clear_attrs_p)(struct vm_page *, int); +extern int (*pmap_enter_p)(pmap_t, vaddr_t, paddr_t, vm_prot_t, int); +extern boolean_t (*pmap_extract_p)(pmap_t, vaddr_t, paddr_t *); +extern vaddr_t (*pmap_growkernel_p)(vaddr_t); +extern void (*pmap_page_remove_p)(struct vm_page *); +extern void (*pmap_do_remove_p)(struct pmap *, vaddr_t, vaddr_t, int); +extern boolean_t (*pmap_test_attrs_p)(struct vm_page *, int); +extern void (*pmap_unwire_p)(struct pmap *, vaddr_t); +extern void (*pmap_write_protect_p)(struct pmap*, vaddr_t, vaddr_t, vm_prot_t); +extern void (*pmap_pinit_pd_p)(pmap_t); +extern void (*pmap_zero_phys_p)(paddr_t); +extern boolean_t (*pmap_zero_page_uncached_p)(paddr_t); +extern void (*pmap_copy_page_p)(struct vm_page *, struct vm_page *); + +u_int32_t pmap_pte_set_pae(vaddr_t, paddr_t, u_int32_t); +u_int32_t pmap_pte_setbits_pae(vaddr_t, u_int32_t, u_int32_t); +u_int32_t pmap_pte_bits_pae(vaddr_t); +paddr_t pmap_pte_paddr_pae(vaddr_t); +boolean_t pmap_clear_attrs_pae(struct vm_page *, int); +int pmap_enter_pae(pmap_t, vaddr_t, paddr_t, vm_prot_t, int); +boolean_t pmap_extract_pae(pmap_t, vaddr_t, paddr_t *); +vaddr_t pmap_growkernel_pae(vaddr_t); +void pmap_page_remove_pae(struct vm_page *); +void pmap_do_remove_pae(struct pmap *, vaddr_t, vaddr_t, int); +boolean_t pmap_test_attrs_pae(struct vm_page *, int); +void pmap_unwire_pae(struct pmap *, vaddr_t); +void pmap_write_protect_pae(struct pmap *, vaddr_t, vaddr_t, vm_prot_t); +void pmap_pinit_pd_pae(pmap_t); +void pmap_zero_phys_pae(paddr_t); +boolean_t pmap_zero_page_uncached_pae(paddr_t); +void pmap_copy_page_pae(struct vm_page *, struct vm_page *); +void pae_copy_phys(paddr_t, paddr_t, int, int); + +#define pmap_pte_set (*pmap_pte_set_p) +#define pmap_pte_setbits (*pmap_pte_setbits_p) +#define pmap_pte_bits (*pmap_pte_bits_p) +#define pmap_pte_paddr (*pmap_pte_paddr_p) +#define pmap_clear_attrs (*pmap_clear_attrs_p) +#define pmap_page_remove (*pmap_page_remove_p) +#define pmap_do_remove (*pmap_do_remove_p) +#define pmap_test_attrs (*pmap_test_attrs_p) +#define pmap_unwire (*pmap_unwire_p) +#define pmap_write_protect (*pmap_write_protect_p) +#define pmap_pinit_pd (*pmap_pinit_pd_p) +#define pmap_zero_phys (*pmap_zero_phys_p) +#define pmap_zero_page_uncached (*pmap_zero_page_uncached_p) +#define pmap_copy_page (*pmap_copy_page_p) + +u_int32_t pmap_pte_set_86(vaddr_t, paddr_t, u_int32_t); +u_int32_t pmap_pte_setbits_86(vaddr_t, u_int32_t, u_int32_t); +u_int32_t pmap_pte_bits_86(vaddr_t); +paddr_t pmap_pte_paddr_86(vaddr_t); +boolean_t pmap_clear_attrs_86(struct vm_page *, int); +int pmap_enter_86(pmap_t, vaddr_t, paddr_t, vm_prot_t, int); +boolean_t pmap_extract_86(pmap_t, vaddr_t, paddr_t *); +vaddr_t pmap_growkernel_86(vaddr_t); +void pmap_page_remove_86(struct vm_page *); +void pmap_do_remove_86(struct pmap *, vaddr_t, vaddr_t, int); +boolean_t pmap_test_attrs_86(struct vm_page *, int); +void pmap_unwire_86(struct pmap *, vaddr_t); +void pmap_write_protect_86(struct pmap *, vaddr_t, vaddr_t, vm_prot_t); +void pmap_pinit_pd_86(pmap_t); +void pmap_zero_phys_86(paddr_t); +boolean_t pmap_zero_page_uncached_86(paddr_t); +void pmap_copy_page_86(struct vm_page *, struct vm_page *); +void pmap_tlb_shootpage(struct pmap *, vaddr_t); +void pmap_tlb_shootrange(struct pmap *, vaddr_t, vaddr_t); +void pmap_tlb_shoottlb(void); #ifdef MULTIPROCESSOR -void pmap_tlb_droppmap(struct pmap *); -void pmap_tlb_shootwait(void); +void pmap_tlb_droppmap(struct pmap *); +void pmap_tlb_shootwait(void); #else #define pmap_tlb_shootwait() #endif -void pmap_prealloc_lowmem_ptp(paddr_t); +void pmap_prealloc_lowmem_ptp(); +void pmap_prealloc_lowmem_ptp_pae(); +vaddr_t pmap_tmpmap_pa(paddr_t); +void pmap_tmpunmap_pa(void); +vaddr_t pmap_tmpmap_pa_pae(paddr_t); +void pmap_tmpunmap_pa_pae(void); + /* * functions for flushing the cache for vaddrs and pages. * these functions are not part of the MI pmap interface and thus * should not be used as such. */ -void pmap_flush_cache(vaddr_t, vsize_t); -void pmap_flush_page(paddr_t); +void pmap_flush_cache(vaddr_t, vsize_t); +void pmap_flush_page(paddr_t); +void pmap_flush_page_pae(paddr_t); #define PMAP_GROWKERNEL /* turn on pmap_growkernel interface */ /* * Do idle page zero'ing uncached to avoid polluting the cache. */ -boolean_t pmap_zero_page_uncached(paddr_t); #define PMAP_PAGEIDLEZERO(pg) pmap_zero_page_uncached(VM_PAGE_TO_PHYS(pg)) /* @@ -363,6 +424,49 @@ pmap_protect(struct pmap *pmap, vaddr_t sva, vaddr_t eva, vm_prot_t prot) } } +/* + * pmap_growkernel, pmap_enter, and pmap_extract get picked up in variuos + * modules from both uvm_pmap.h and pmap.h. Since uvm_pmap.h defines these + * as functions, inline them here to suppress linker warnings. + */ +__inline static vaddr_t +pmap_growkernel(vaddr_t maxkvaddr) +{ + return (*pmap_growkernel_p)(maxkvaddr); +} + +__inline static int +pmap_enter(struct pmap *pmap, vaddr_t va, paddr_t pa, vm_prot_t prot, int flags) +{ + return (*pmap_enter_p)(pmap, va, pa, prot, flags); +} + +__inline static boolean_t +pmap_extract(struct pmap *pmap, vaddr_t va, paddr_t *pa) +{ + return (*pmap_extract_p)(pmap, va, pa); +} + +/* + * p m a p i n l i n e h e l p e r f u n c t i o n s + */ + +/* + * pmap_is_active: is this pmap loaded into the specified processor's %cr3? + */ + +static __inline boolean_t +pmap_is_active(struct pmap *pmap, struct cpu_info *ci) +{ + return (pmap == pmap_kernel() || ci->ci_curpmap == pmap); +} + +static __inline boolean_t +pmap_is_curpmap(struct pmap *pmap) +{ + return (pmap_is_active(pmap, curcpu())); +} + #if defined(USER_LDT) void pmap_ldt_cleanup(struct proc *); #define PMAP_FORK diff --git a/sys/arch/i386/include/pte.h b/sys/arch/i386/include/pte.h index efaa89caaec..c0e1ccfb83d 100644 --- a/sys/arch/i386/include/pte.h +++ b/sys/arch/i386/include/pte.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pte.h,v 1.20 2015/03/13 23:23:13 mlarkin Exp $ */ +/* $OpenBSD: pte.h,v 1.21 2015/04/12 18:37:54 mlarkin Exp $ */ /* $NetBSD: pte.h,v 1.11 1998/02/06 21:58:05 thorpej Exp $ */ /* @@ -37,33 +37,12 @@ #ifndef _MACHINE_PTE_H_ #define _MACHINE_PTE_H_ -#if !defined(_LOCORE) - -/* - * here we define the data types for PDEs and PTEs - */ - -typedef u_int32_t pd_entry_t; /* PDE */ -typedef u_int32_t pt_entry_t; /* PTE */ - -#endif - /* * now we define various for playing with virtual addresses */ #define PDSHIFT 22 /* offset of PD index in VA */ #define NBPD (1 << PDSHIFT) /* # bytes mapped by PD (4MB) */ -#define PDOFSET (NBPD-1) /* mask for non-PD part of VA */ -#if 0 /* not used? */ -#define NPTEPD (NBPD / PAGE_SIZE) /* # of PTEs in a PD */ -#else -#define PTES_PER_PTP (NBPD / PAGE_SIZE) /* # of PTEs in a PTP */ -#endif - -#define PAGE_MASK_L2 (NBPD - 1) - -#define i386_round_pdr(x) ((((unsigned)(x)) + PDOFSET) & ~PDOFSET) /* * here we define the bits of the PDE/PTE, as described above: @@ -87,8 +66,6 @@ typedef u_int32_t pt_entry_t; /* PTE */ #define PG_AVAIL2 0x00000400 /* ignored by hardware */ #define PG_AVAIL3 0x00000800 /* ignored by hardware */ #define PG_PATLG 0x00001000 /* PAT on large pages */ -#define PG_FRAME 0xfffff000 /* page frame mask */ -#define PG_LGFRAME 0xffc00000 /* large (4M) page frame mask */ /* Cacheability bits when we are using PAT */ #define PG_WB (0) /* The default */ |