diff options
author | dyson <dyson@FreeBSD.org> | 1996-03-28 04:59:34 +0000 |
---|---|---|
committer | dyson <dyson@FreeBSD.org> | 1996-03-28 04:59:34 +0000 |
commit | 0b00dbdf90b05e64737783bb5bc34bdf4fd8e9c3 (patch) | |
tree | da6e46d53618cd894d3055707abe146045053456 /sys/amd64 | |
parent | b37500ce5f313e6812ce71084d588b23231d7bbb (diff) | |
download | FreeBSD-src-0b00dbdf90b05e64737783bb5bc34bdf4fd8e9c3.zip FreeBSD-src-0b00dbdf90b05e64737783bb5bc34bdf4fd8e9c3.tar.gz |
Significant code cleanup, and some performance improvement. Also,
mlock will now work properly without killing the system.
Diffstat (limited to 'sys/amd64')
-rw-r--r-- | sys/amd64/amd64/pmap.c | 216 |
1 files changed, 134 insertions, 82 deletions
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index 420b86a..f92a168 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -39,7 +39,7 @@ * SUCH DAMAGE. * * from: @(#)pmap.c 7.7 (Berkeley) 5/12/91 - * $Id: pmap.c,v 1.80 1996/03/11 05:55:56 hsu Exp $ + * $Id: pmap.c,v 1.81 1996/03/13 00:39:45 dyson Exp $ */ /* @@ -51,13 +51,6 @@ * * Derived from: hp300/@(#)pmap.c 7.1 (Berkeley) 12/5/90 */ -/* - * Major modifications by John S. Dyson primarily to support - * pageable page tables, eliminating pmap_attributes, - * discontiguous memory pages, and using more efficient string - * instructions. Jan 13, 1994. Further modifications on Mar 2, 1994, - * general clean-up and efficiency mods. - */ /* * Manages physical address maps. @@ -131,8 +124,8 @@ static void init_pv_entries __P((int)); #define pmap_pte_u(pte) ((*(int *)pte & PG_U) != 0) #define pmap_pte_v(pte) ((*(int *)pte & PG_V) != 0) -#define pmap_pte_set_w(pte, v) ((v)?(*(int *)pte |= PG_W):(*(int *)pte &= ~PG_W)) -#define pmap_pte_set_prot(pte, v) ((*(int *)pte &= ~PG_PROT), (*(int *)pte |= (v))) +#define pmap_pte_set_w(pte, v) ((v)?(*(int *)pte |= PG_W):(*(int *)pte &= ~PG_W)) +#define pmap_pte_set_prot(pte, v) ((*(int *)pte &= ~PG_PROT), (*(int *)pte |= (v))) /* * Given a map and a machine independent protection code, @@ -179,6 +172,7 @@ static void pmap_enter_quick __P((pmap_t pmap, vm_offset_t va, vm_offset_t pa)); static int pmap_is_managed __P((vm_offset_t pa)); static void pmap_remove_all __P((vm_offset_t pa)); +static void pmap_remove_page __P((struct pmap *pmap, vm_offset_t va)); static __inline void pmap_remove_entry __P((struct pmap *pmap, pv_entry_t pv, vm_offset_t va)); static int pmap_remove_pte __P((struct pmap *pmap, pt_entry_t *ptq, @@ -318,7 +312,7 @@ pmap_is_managed(pa) return 0; for (i = 0; phys_avail[i + 1]; i += 2) { - if (pa >= phys_avail[i] && pa < phys_avail[i + 1]) + if (pa < phys_avail[i + 1] && pa >= phys_avail[i]) return 1; } return 0; @@ -551,7 +545,9 @@ pmap_getpdir() { --nfreepdir; pdir = pdirlist; pdirlist = (caddr_t *) *pdir; +#if 0 /* Not needed anymore */ bzero( (caddr_t) pdir, PAGE_SIZE); +#endif } else { pdir = (caddr_t *) kmem_alloc(kernel_map, PAGE_SIZE); } @@ -564,6 +560,24 @@ pmap_freepdir(void *pdir) { if (nfreepdir > NFREEPDIR) { kmem_free(kernel_map, (vm_offset_t) pdir, PAGE_SIZE); } else { + int i; + pt_entry_t *s; + s = (pt_entry_t *) pdir; + + /* + * remove wired in kernel mappings + */ + bzero(s + KPTDI, nkpt * PTESIZE); + s[APTDPTDI] = 0; + s[PTDPTDI] = 0; + +#if defined(PMAP_DIAGNOSTIC) + for(i=0;i<PAGE_SIZE/4;i++,s++) { + if (*s) { + printf("pmap_freepdir: index %d not zero: %lx\n", i, *s); + } + } +#endif * (caddr_t *) pdir = (caddr_t) pdirlist; pdirlist = (caddr_t *) pdir; ++nfreepdir; @@ -892,6 +906,9 @@ pmap_remove_entry(pmap, pv, va) splx(s); } +/* + * pmap_remove_pte: do the things to unmap a page to mapped into a process + */ static int pmap_remove_pte(pmap, ptq, sva) struct pmap *pmap; @@ -932,6 +949,49 @@ pmap_remove_pte(pmap, ptq, sva) } /* + * Scan pmap for non-null entry up to the entry pointed to + * by pdnxt. Return the va corresponding to the entry. + */ +static __inline vm_offset_t +pmap_scan( vm_offset_t sva, vm_offset_t pdnxt, pt_entry_t *ptp) { + pt_entry_t *ptt, *ptnxt; + + ptnxt = &ptp[pdnxt]; + ptt = &ptp[sva]; + +loop: + if ((ptt != ptnxt) && (*ptt == 0)) { + ptt++; + goto loop; + } + return ptt - ptp; +} + +/* + * Remove a single page from a process address space + */ +static __inline void +pmap_remove_page(pmap, va) + struct pmap *pmap; + register vm_offset_t va; +{ + register pt_entry_t *ptp, *ptq; + /* + * if there is no pte for this address, just skip it!!! + */ + if (*pmap_pde(pmap, va) == 0) + return; + /* + * get a local va for mappings for this pmap. + */ + ptp = get_pt_entry(pmap); + ptq = ptp + i386_btop(va); + if ( *ptq && pmap_remove_pte( pmap, ptq, va)) + pmap_update_1pg(va); + return; +} + +/* * Remove the given range of addresses from the specified map. * * It is assumed that the start and end are properly @@ -959,21 +1019,7 @@ pmap_remove(pmap, sva, eva) * code. */ if ((sva + PAGE_SIZE) == eva) { - pt_entry_t *ptq; - - /* - * if there is no pte for this address, just skip it!!! - */ - if (*pmap_pde(pmap, sva) == 0) - return; - - /* - * get a local va for mappings for this pmap. - */ - ptp = get_pt_entry(pmap); - ptq = ptp + i386_btop(sva); - if ( *ptq && pmap_remove_pte( pmap, ptq, sva)) - pmap_update_1pg(sva); + pmap_remove_page(pmap, sva); return; } @@ -1037,7 +1083,7 @@ pmap_remove(pmap, sva, eva) /* * if the pte isn't wired or held, just skip it. */ - if ((*wc == 0) && (*hc == 0)) { + if ((*hc == 0) && (*wc == 0)) { sva = pdnxt; continue; } @@ -1052,33 +1098,19 @@ pmap_remove(pmap, sva, eva) } /* - * this makes more efficient code + * get get the ptp only if we need to */ - sva--; - if (ptp == NULL) ptp = get_pt_entry(pmap); quickloop: - /* - * This is a very quick scan for a populated page table page - * entry or the end of the page table page. This code works - * best when compiled with -O, -fomit-frame-pointer on GCC. - * -O with frame pointer is a little worse, and -O2 makes this - * code worse yet. This should probably be made into an inline - * asm, but for now this works pretty well. - */ - do { - sva++; - - if (sva == pdnxt) - goto endmainloop; - - } while (*(ptp + sva) == 0); - + sva = pmap_scan(sva, pdnxt, ptp); + if (sva == pdnxt) + goto endmainloop; /* * Remove the found entry. */ va = i386_ptob(sva); +quickloop1: if (pmap_remove_pte( pmap, ptp + sva, va)) update_needed = 1; @@ -1086,8 +1118,16 @@ quickloop: * If the wire count and the hold count for the page table page * are both zero, then we are done. */ - if ((*hc != 0) || (*wc != 0)) + if ((*hc != 0) || (*wc != 0)) { + ++sva; + if (pdnxt == sva) + goto endmainloop; + if (ptp[sva]) { + va += PAGE_SIZE; + goto quickloop1; + } goto quickloop; + } /* * We are done with the current page table page if we get here @@ -1261,46 +1301,28 @@ pmap_protect(pmap, sva, eva, prot) pdnxt = eva; } - /* - * search for page table entries - */ - while ((sva != pdnxt) && (*(ptp + sva) == 0)) - ++sva; - +quickloop: + sva = pmap_scan( sva, pdnxt, ptp); if (sva == pdnxt) { continue; } pte = ptp + sva; - - va = i386_ptob(sva); - i386prot = pte_prot(pmap, prot); - if (va < UPT_MAX_ADDRESS) { - i386prot |= PG_u; - if (va >= UPT_MIN_ADDRESS) - i386prot |= PG_RW; - } - pbits = *(int *)pte; -#if defined(PMAP_DIAGNOSTIC) - if (pmap_nw_modified((pt_entry_t) pbits)) { - printf("pmap_protect: modified page not writable: va: 0x%lx, pte: 0x%lx\n", va, pbits); - } -#endif - if (pbits & PG_M) { - vm_page_t m; - vm_offset_t pa = pbits & PG_FRAME; - m = PHYS_TO_VM_PAGE(pa); - m->dirty = VM_PAGE_BITS_ALL; - *(int *)pte &= ~PG_M; - anychanged = 1; - } - pprot = pbits & PG_PROT; - if (pprot != i386prot) { - pmap_pte_set_prot(pte, i386prot); - anychanged = 1; + + if (pbits & PG_RW) { + if (pbits & PG_M) { + vm_page_t m; + vm_offset_t pa = pbits & PG_FRAME; + m = PHYS_TO_VM_PAGE(pa); + m->dirty = VM_PAGE_BITS_ALL; + } + *(int *)pte &= ~(PG_M|PG_RW); + anychanged=1; } ++sva; + if ( sva < pdnxt) + goto quickloop; } if (anychanged) pmap_update(); @@ -1341,6 +1363,33 @@ pmap_enter(pmap, va, pa, prot, wired) if (va > VM_MAX_KERNEL_ADDRESS) panic("pmap_enter: toobig"); +#ifdef NO_HANDLE_LOCKED_PTES + /* + * Page Directory table entry not valid, we need a new PT page + */ + pte = pmap_pte(pmap, va); + if (pte == NULL) { + printf("kernel page directory invalid pdir=%p, va=0x%lx\n", + pmap->pm_pdir[PTDPTDI], va); + panic("invalid kernel page directory"); + } +#else + /* + * This is here in the case that a page table page is not + * resident, but we are inserting a page there. + */ + if ((va < VM_MIN_KERNEL_ADDRESS) && + (curproc != NULL) && + (pmap == &curproc->p_vmspace->vm_pmap)) { + vm_offset_t v; + v = (vm_offset_t) vtopte(va); + + /* Fault the pte only if needed: */ + if (*((int *)vtopte(v)) == 0) + (void) vm_fault(&curproc->p_vmspace->vm_map, + trunc_page(v), VM_PROT_WRITE, FALSE); + } + /* * Page Directory table entry not valid, we need a new PT page */ @@ -1350,6 +1399,7 @@ pmap_enter(pmap, va, pa, prot, wired) pmap->pm_pdir[PTDPTDI], va); panic("invalid kernel page directory"); } +#endif origpte = *(vm_offset_t *)pte; opa = origpte & PG_FRAME; @@ -1393,7 +1443,7 @@ pmap_enter(pmap, va, pa, prot, wired) * handle validating new mapping. */ if (opa) { - pmap_remove(pmap, va, va + PAGE_SIZE); + pmap_remove_page(pmap, va); opa = 0; origpte = 0; } @@ -1582,7 +1632,7 @@ pmap_enter_quick(pmap, va, pa) pte = vtopte(va); /* a fault on the page table might occur here */ if (*pte) { - pmap_remove(pmap, va, va + PAGE_SIZE); + pmap_remove_page(pmap, va); } pv = pa_to_pvh(pa); @@ -1623,7 +1673,7 @@ pmap_enter_quick(pmap, va, pa) return; } -#define MAX_INIT_PT (512) +#define MAX_INIT_PT (96) /* * pmap_object_init_pt preloads the ptes for a given object * into the specified pmap. This eliminates the blast of soft @@ -1708,6 +1758,7 @@ pmap_object_init_pt(pmap, addr, object, pindex, size) } } } + return; } /* @@ -1794,6 +1845,7 @@ pmap_prefault(pmap, addra, entry, object) m->flags |= PG_MAPPED; pmap_enter_quick(pmap, addr, VM_PAGE_TO_PHYS(m)); vm_page_unhold(m); + } } } |