diff --git a/sys/arch/vax/include/cpu.h b/sys/arch/vax/include/cpu.h index 9182f6986ac1..70ace8ec4976 100644 --- a/sys/arch/vax/include/cpu.h +++ b/sys/arch/vax/include/cpu.h @@ -1,4 +1,4 @@ -/* $NetBSD: cpu.h,v 1.61 2001/06/14 22:56:58 thorpej Exp $ */ +/* $NetBSD: cpu.h,v 1.62 2002/03/10 22:32:31 ragge Exp $ */ /* * Copyright (c) 1994 Ludd, University of Lule}, Sweden @@ -52,7 +52,6 @@ #define enablertclock() #define cpu_wait(p) -#define cpu_swapout(p) /* * All cpu-dependent info is kept in this struct. Pointer to the diff --git a/sys/arch/vax/include/pmap.h b/sys/arch/vax/include/pmap.h index 65e6de517719..9345582e10dd 100644 --- a/sys/arch/vax/include/pmap.h +++ b/sys/arch/vax/include/pmap.h @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.h,v 1.51 2002/03/01 23:55:11 ragge Exp $ */ +/* $NetBSD: pmap.h,v 1.52 2002/03/10 22:32:31 ragge Exp $ */ /* * Copyright (c) 1987 Carnegie-Mellon University @@ -55,8 +55,17 @@ */ #define LTOHPS (PGSHIFT - VAX_PGSHIFT) #define LTOHPN (1 << LTOHPS) -#define PROCPTSIZE ((MAXTSIZ + MAXDSIZ + MAXSSIZ + MMAPSPACE) / VAX_NBPG) -#define NPTEPGS (PROCPTSIZE / (sizeof(struct pte) * LTOHPN)) +#define PROCPTSIZE ((MAXTSIZ + MAXDSIZ + MAXSSIZ + MMAPSPACE) / VAX_NBPG) +#define NPTEPGS (PROCPTSIZE / (NBPG / (sizeof(struct pte) * LTOHPN))) + +/* + * Link struct if more than one process share pmap (like vfork). + * This is rarely used. + */ +struct pm_share { + struct pm_share *ps_next; + struct pcb *ps_pcb; +}; /* * Pmap structure @@ -64,15 +73,20 @@ */ typedef struct pmap { - vaddr_t pm_stack; /* Base of alloced p1 pte space */ - int ref_count; /* reference count */ + struct pte *pm_p1ap; /* Base of alloced p1 pte space */ + short pm_count; /* reference count */ + short pm_flags; +#define PM_ACTIVE 1 /* Process connected to pmap */ + struct pte *pm_p0base; /* Pointer to saved ptes */ + struct pm_share *pm_share; /* PCBs using this pmap */ struct pte *pm_p0br; /* page 0 base register */ long pm_p0lr; /* page 0 length register */ struct pte *pm_p1br; /* page 1 base register */ long pm_p1lr; /* page 1 length register */ + u_char *pm_pref; /* pte reference count array */ + struct pte *pm_p1base; /* Number of pages wired */ struct simplelock pm_lock; /* Lock entry in MP environment */ struct pmap_statistics pm_stats; /* Some statistics */ - u_char pm_refcnt[NPTEPGS]; /* Refcount per pte page */ } *pmap_t; /* @@ -82,7 +96,7 @@ typedef struct pmap { struct pv_entry { struct pv_entry *pv_next; /* next pv_entry */ - struct pte *pv_pte; /* pte for this physical page */ + vaddr_t pv_vaddr; /* address for this physical page */ struct pmap *pv_pmap; /* pmap this entry belongs to */ int pv_attr; /* write/modified bits */ }; @@ -158,8 +172,7 @@ pmap_extract(pmap_t pmap, vaddr_t va, paddr_t *pap) #define pmap_remove(pmap, start, slut) pmap_protect(pmap, start, slut, 0) #define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count) #define pmap_wired_count(pmap) ((pmap)->pm_stats.wired_count) -#define pmap_deactivate(p) /* Dont do anything */ -#define pmap_reference(pmap) (pmap)->ref_count++ +#define pmap_reference(pmap) (pmap)->pm_count++ /* These can be done as efficient inline macros */ #define pmap_copy_page(src, dst) \ diff --git a/sys/arch/vax/vax/pmap.c b/sys/arch/vax/vax/pmap.c index 5f4bf37a228b..bfd7f131924a 100644 --- a/sys/arch/vax/vax/pmap.c +++ b/sys/arch/vax/vax/pmap.c @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.c,v 1.109 2002/03/01 23:55:10 ragge Exp $ */ +/* $NetBSD: pmap.c,v 1.110 2002/03/10 22:32:31 ragge Exp $ */ /* * Copyright (c) 1994, 1998, 1999 Ludd, University of Lule}, Sweden. * All rights reserved. @@ -67,7 +67,7 @@ void qdearly(void); #define ISTACK_SIZE NBPG -vaddr_t istack; +vaddr_t istack; /* * This code uses bitfield operators for most page table entries. */ @@ -87,7 +87,7 @@ vaddr_t istack; * Page 4: unused */ long scratch; -#define SCRATCHPAGES 4 +#define SCRATCHPAGES 4 struct pmap kernel_pmap_store; @@ -95,16 +95,22 @@ struct pmap kernel_pmap_store; struct pte *Sysmap; /* System page table */ struct pv_entry *pv_table; /* array of entries, one per LOGICAL page */ int pventries; -vaddr_t iospace; +vaddr_t iospace; vaddr_t ptemapstart, ptemapend; struct extent *ptemap; -#define PTMAPSZ EXTENT_FIXED_STORAGE_SIZE(100) +#define PTMAPSZ EXTENT_FIXED_STORAGE_SIZE(100) char ptmapstorage[PTMAPSZ]; extern caddr_t msgbufaddr; -#define IOSPACE(p) (((u_long)(p)) & 0xe0000000) +#define IOSPACE(p) (((u_long)(p)) & 0xe0000000) +#define NPTEPROCSPC 0x1000 /* # of virtual PTEs per process space */ +#define NPTEPG 0x80 /* # of PTEs per page (logical or physical) */ +#define PPTESZ sizeof(struct pte) +#define NOVADDR 0xffffffff /* Illegal virtual address */ +#define WAITOK M_WAITOK +#define NOWAIT M_NOWAIT #ifdef PMAPDEBUG volatile int recurse; @@ -114,14 +120,16 @@ volatile int recurse; recurse = __LINE__; \ } #define RECURSEEND {recurse = 0; } +#define PMDEBUG(x) if (startpmapdebug)printf x #else #define RECURSESTART #define RECURSEEND +#define PMDEBUG(x) #endif #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) static struct simplelock pvtable_lock; -#define PVTABLE_LOCK simple_lock(&pvtable_lock); +#define PVTABLE_LOCK simple_lock(&pvtable_lock); #define PVTABLE_UNLOCK simple_unlock(&pvtable_lock); #else #define PVTABLE_LOCK @@ -142,8 +150,8 @@ static inline #endif void rensa(int, struct pte *); -vaddr_t avail_start, avail_end; -vaddr_t virtual_avail, virtual_end; /* Available virtual memory */ +vaddr_t avail_start, avail_end; +vaddr_t virtual_avail, virtual_end; /* Available virtual memory */ struct pv_entry *get_pventry(void); void free_pventry(struct pv_entry *); @@ -196,7 +204,7 @@ calc_kvmsize(vsize_t usrptsize) #endif #ifdef LKM /* LKMs are allocated out of kernel_map */ -#define MAXLKMSIZ 0x100000 /* XXX */ +#define MAXLKMSIZ 0x100000 /* XXX */ kvmsize += MAXLKMSIZ; #endif return kvmsize; @@ -224,6 +232,9 @@ pmap_bootstrap() physmem = btoc(avail_end); usrptsize = PROCPTSIZE * maxproc; + if (vax_btop(usrptsize)* PPTESZ > avail_end/20) + usrptsize = (avail_end/(20 * PPTESZ)) * VAX_NBPG; + kvmsize = calc_kvmsize(usrptsize); sysptsize = kvmsize >> VAX_PGSHIFT; /* @@ -277,7 +288,7 @@ pmap_bootstrap() /* zero all mapped physical memory from Sysmap to here */ memset((void *)istack, 0, (avail_start + KERNBASE) - istack); - /* QDSS console mapping hack */ + /* QDSS console mapping hack */ #if NQD > 0 qdearly(); #endif @@ -300,7 +311,7 @@ pmap_bootstrap() virtual_end = trunc_page(virtual_end); -#if 1 /* Breaks cninit() on some machines */ +#if 0 /* Breaks cninit() on some machines */ cninit(); printf("Sysmap %p, istack %lx, scratch %lx\n",Sysmap,istack,scratch); printf("etext %p, kvmsize %lx\n", &etext, kvmsize); @@ -316,21 +327,21 @@ pmap_bootstrap() /* Init kernel pmap */ - pmap->pm_p1br = (void *)0x80000000; - pmap->pm_p0br = (void *)0x80000000; + pmap->pm_p1br = (struct pte *)KERNBASE; + pmap->pm_p0br = (struct pte *)KERNBASE; pmap->pm_p1lr = 0x200000; - pmap->pm_p0lr = AST_PCB; + pmap->pm_p0lr = 0; pmap->pm_stats.wired_count = pmap->pm_stats.resident_count = 0; /* btop(virtual_avail - KERNBASE); */ - pmap->ref_count = 1; + pmap->pm_count = 1; simple_lock_init(&pmap->pm_lock); /* Activate the kernel pmap. */ mtpr(pcb->P1BR = pmap->pm_p1br, PR_P1BR); mtpr(pcb->P0BR = pmap->pm_p0br, PR_P0BR); mtpr(pcb->P1LR = pmap->pm_p1lr, PR_P1LR); - mtpr(pcb->P0LR = pmap->pm_p0lr, PR_P0LR); + mtpr(pcb->P0LR = (pmap->pm_p0lr|AST_PCB), PR_P0LR); /* cpu_info struct */ pcb->SSP = scratch + VAX_NBPG; @@ -382,11 +393,9 @@ pmap_steal_memory(size, vstartp, vendp) vaddr_t v; int npgs; -#ifdef PMAPDEBUG - if (startpmapdebug) - printf("pmap_steal_memory: size 0x%lx start %p end %p\n", - size, vstartp, vendp); -#endif + PMDEBUG(("pmap_steal_memory: size 0x%lx start %p end %p\n", + size, vstartp, vendp)); + size = round_page(size); npgs = btoc(size); @@ -414,16 +423,236 @@ pmap_steal_memory(size, vstartp, vendp) void pmap_init() { - /* - * Create the extent map used to manage the page table space. + /* + * Create the extent map used to manage the page table space. * XXX - M_HTABLE is bogus. - */ - ptemap = extent_create("ptemap", ptemapstart, ptemapend, - M_HTABLE, ptmapstorage, PTMAPSZ, EX_NOCOALESCE); - if (ptemap == NULL) + */ + ptemap = extent_create("ptemap", ptemapstart, ptemapend, + M_HTABLE, ptmapstorage, PTMAPSZ, EX_NOCOALESCE); + if (ptemap == NULL) panic("pmap_init"); } +static u_long +pmap_extwrap(vsize_t nsize) +{ + int res; + u_long rv; + + for (;;) { + res = extent_alloc(ptemap, nsize, PAGE_SIZE, 0, + EX_WAITOK|EX_MALLOCOK, &rv); + if (res == EAGAIN) + return 0; + if (res == 0) + return rv; + } +} + +/* + * Do a fast page removal. + */ +static void +rmpage(pmap_t pm, int *br) +{ + struct pv_entry *pv, *pl, *pf; + + pv = pv_table + ((br[0] & PG_FRAME) >> LTOHPS); + if (((br[0] & PG_PROT) == PG_RW) && + ((pv->pv_attr & PG_M) != PG_M)) + pv->pv_attr |= br[0]|br[1]|br[2]|br[3]|br[4]|br[5]|br[6]|br[7]; + simple_lock(&pm->pm_lock); + pm->pm_stats.resident_count--; + if (br[0] & PG_W) + pm->pm_stats.wired_count--; + simple_unlock(&pm->pm_lock); + if (pv->pv_pmap == pm) { + pv->pv_vaddr = NOVADDR; + pv->pv_pmap = 0; + } else + for (pl = pv; pl->pv_next; pl = pl->pv_next) { + if (pl->pv_next->pv_pmap != pm) + continue; + pf = pl->pv_next; + pl->pv_next = pl->pv_next->pv_next; + free_pventry(pf); + break; + } +} +/* + * Update the PCBs using this pmap after a change. + */ +static void +update_pcbs(struct pmap *pm) +{ + struct pm_share *ps; + + ps = pm->pm_share; + while (ps != NULL) { + ps->ps_pcb->P0BR = pm->pm_p0br; + ps->ps_pcb->P0LR = pm->pm_p0lr|AST_PCB; + ps->ps_pcb->P1BR = pm->pm_p1br; + ps->ps_pcb->P1LR = pm->pm_p1lr; + ps = ps->ps_next; + } + + /* If curproc uses this pmap update the regs too */ + if (pm == curproc->p_vmspace->vm_map.pmap) { + mtpr(pm->pm_p0br, PR_P0BR); + mtpr(pm->pm_p0lr|AST_PCB, PR_P0LR); + mtpr(pm->pm_p1br, PR_P1BR); + mtpr(pm->pm_p1lr, PR_P1LR); + } +#if defined(MULTIPROCESSOR) && defined(notyet) + /* If someone else is using this pmap, be sure to reread */ + cpu_send_ipi(IPI_DEST_ALL, IPI_NEWPTE); +#endif +} + +/* + * Remove a full process space. Update all processes pcbs. + */ +static void +rmspace(struct pmap *pm) +{ + int lr, i, j, *br; + paddr_t paddr; + + if (pm->pm_p0lr == AST_PCB && pm->pm_p1lr == 0x200000) + return; /* Already free */ + + lr = (pm->pm_p0lr & ~AST_MASK)/1024; + for (i = 0; i < lr; i++) { + if (pm->pm_pref[i] == 0) + continue; + br = (int *)&pm->pm_p0br[i*1024]; + for (j = 0; j < 1024; j+=8) { + if (br[j] == 0) + continue; + rmpage(pm, &br[j]); + if (--pm->pm_pref[i] == 0) { + paddr = kvtopte(br)->pg_pfn << VAX_PGSHIFT; + uvm_pagefree(PHYS_TO_VM_PAGE(paddr)); + break; + } + } + } + lr = pm->pm_p1lr/1024; + for (i = lr; i < 0x800; i++) { + if (pm->pm_pref[i+0x800] == 0) + continue; + br = (int *)&pm->pm_p1br[i*1024]; + for (j = 0; j < 1024; j+=8) { + if (br[j] == 0) + continue; + rmpage(pm, &br[j]); + if (--pm->pm_pref[i+0x800] == 0) { + paddr = kvtopte(br)->pg_pfn << VAX_PGSHIFT; + uvm_pagefree(PHYS_TO_VM_PAGE(paddr)); + break; + } + } + } + + extent_free(ptemap, (u_long)pm->pm_p0br, + (pm->pm_p0lr & ~AST_MASK) * PPTESZ, EX_WAITOK); + extent_free(ptemap, (u_long)pm->pm_p1ap, + (0x200000 - pm->pm_p1lr) * PPTESZ, EX_WAITOK); + pm->pm_p0br = pm->pm_p1br = (struct pte *)KERNBASE; + pm->pm_p0lr = AST_PCB; + pm->pm_p1lr = 0x200000; + pm->pm_p1ap = NULL; + update_pcbs(pm); +} + +/* + * Find a process to remove the process space for. + * This is based on uvm_swapout_threads(). + * Avoid to remove ourselves. + */ + +#define swappable(p, pm) \ + (((p)->p_flag & (P_SYSTEM | P_INMEM | P_WEXIT)) == P_INMEM && \ + ((p)->p_holdcnt == 0) && ((p)->p_vmspace->vm_map.pmap != pm)) + +static int +pmap_rmproc(struct pmap *pm) +{ + struct pmap *ppm; + struct proc *p; + struct proc *outp, *outp2; + int outpri, outpri2; + int didswap = 0; + extern int maxslp; + + outp = outp2 = NULL; + outpri = outpri2 = 0; + proclist_lock_read(); + LIST_FOREACH(p, &allproc, p_list) { + if (!swappable(p, pm)) + continue; + ppm = p->p_vmspace->vm_map.pmap; + if (ppm->pm_p0lr == AST_PCB && ppm->pm_p1lr == 0x200000) + continue; /* Already swapped */ + switch (p->p_stat) { + case SRUN: + case SONPROC: + if (p->p_swtime > outpri2) { + outp2 = p; + outpri2 = p->p_swtime; + } + continue; + case SSLEEP: + case SSTOP: + if (p->p_slptime >= maxslp) { + rmspace(p->p_vmspace->vm_map.pmap); + didswap++; + } else if (p->p_slptime > outpri) { + outp = p; + outpri = p->p_slptime; + } + continue; + } + } + proclist_unlock_read(); + if (didswap == 0) { + if ((p = outp) == NULL) + p = outp2; + if (p) { + rmspace(p->p_vmspace->vm_map.pmap); + didswap++; + } + } + return didswap; +} + +/* + * Allocate space for user page tables, from ptemap. + * Never fails; if the map is full then: + * 1) Remove processes idle for more than 20 seconds or stopped. + * 2) Remove processes idle for less than 20 seconds. + * 3) Remove all processes (except the current, if it exists), + * probably too fragmented ptemap. + * + * Argument is needed space, in bytes. + * Returns a pointer to the newly allocated space. + */ +static vaddr_t +pmap_getusrptes(pmap_t pm, vsize_t nsize) +{ + u_long rv; + +#ifdef DEBUG + if (nsize & PAGE_MASK) + panic("pmap_getusrptes: bad size %lx", nsize); +#endif + while (((rv = pmap_extwrap(nsize)) == 0) && (pmap_rmproc(pm) != 0)) + ; + if (rv) + return rv; + panic("usrptmap space leakage"); +} + /* * Decrement a reference to a pte page. If all references are gone, * free the page. @@ -434,64 +663,156 @@ pmap_decpteref(pmap, pte) struct pte *pte; { paddr_t paddr; - int index; + int idx; if (pmap == pmap_kernel()) return; - index = ((vaddr_t)pte - (vaddr_t)pmap->pm_p0br) >> PGSHIFT; + + if ((pmap->pm_p0br <= pte) && + ((pmap->pm_p0br + (pmap->pm_p0lr & ~AST_MASK)) > pte)) + idx = ((pte - pmap->pm_p0br) >> LTOHPS)/NPTEPG; + else + idx = ((pte - pmap->pm_p1br) >> LTOHPS)/NPTEPG + 0x800; pte = (struct pte *)trunc_page((vaddr_t)pte); -#ifdef PMAPDEBUG - if (startpmapdebug) - printf("pmap_decpteref: pmap %p pte %p index %d refcnt %d\n", - pmap, pte, index, pmap->pm_refcnt[index]); -#endif + + PMDEBUG(("pmap_decpteref: pmap %p pte %p index %d refcnt %d\n", + pmap, pte, idx, pmap->pm_pref[idx])); #ifdef DEBUG - if ((index < 0) || (index >= NPTEPGS)) - panic("pmap_decpteref: bad index %d", index); + if ((idx < 0) || (idx >= NPTEPROCSPC)) + panic("pmap_decpteref: bad index %d", idx); #endif - pmap->pm_refcnt[index]--; + pmap->pm_pref[idx]--; #ifdef DEBUG - if (pmap->pm_refcnt[index] >= VAX_NBPG/sizeof(struct pte)) + if (pmap->pm_pref[idx] >= VAX_NBPG/sizeof(struct pte)) panic("pmap_decpteref"); #endif - if (pmap->pm_refcnt[index] == 0) { + if (pmap->pm_pref[idx] == 0) { +#ifdef DEBUG + int i, *ptr = (int *)pte; + for (i = 0; i < 1024; i++) + if (ptr[i] != 0) + panic("pmap_decpteref: ptr[%d] != 0", i); +#endif paddr = kvtopte(pte)->pg_pfn << VAX_PGSHIFT; uvm_pagefree(PHYS_TO_VM_PAGE(paddr)); bzero(kvtopte(pte), sizeof(struct pte) * LTOHPN); } } +static void +grow_p0(struct pmap *pm, int reqlen) +{ + vaddr_t nptespc; + char *from, *to; + int srclen, dstlen; + int inuse, len, p0lr; + u_long p0br; + + PMDEBUG(("grow_p0: pmap %p reqlen %d\n", pm, reqlen)); + + /* Get new pte space */ + p0lr = pm->pm_p0lr & ~AST_MASK; + inuse = p0lr != 0; + len = round_page((reqlen+1) * PPTESZ); + RECURSEEND; + nptespc = pmap_getusrptes(pm, len); + RECURSESTART; + + /* + * Copy the old ptes to the new space. + * Done by moving on system page table. + */ + srclen = vax_btop(p0lr * PPTESZ) * PPTESZ; + dstlen = vax_btoc(len)*PPTESZ; + from = (char *)kvtopte(pm->pm_p0br); + to = (char *)kvtopte(nptespc); + + PMDEBUG(("grow_p0: from %p to %p src %d dst %d\n", + from, to, srclen, dstlen)); + + if (inuse) + bcopy(from, to, srclen); + bzero(to+srclen, dstlen-srclen); + p0br = (u_long)pm->pm_p0br; + pm->pm_p0br = (struct pte *)nptespc; + pm->pm_p0lr = (len/PPTESZ) | AST_PCB; + update_pcbs(pm); + + /* Remove the old after update_pcbs() (for multicpu propagation) */ + if (inuse) + extent_free(ptemap, p0br, p0lr*PPTESZ, EX_WAITOK); +} + + +static void +grow_p1(struct pmap *pm, int len) +{ + vaddr_t nptespc, optespc; + int nlen, olen; + + PMDEBUG(("grow_p1: pm %p len %x\n", pm, len)); + + /* Get new pte space */ + nlen = 0x800000 - trunc_page(len * PPTESZ); + RECURSEEND; + nptespc = pmap_getusrptes(pm, nlen); + RECURSESTART; + olen = 0x800000 - (pm->pm_p1lr * PPTESZ); + optespc = (vaddr_t)pm->pm_p1ap; + + /* + * Copy the old ptes to the new space. + * Done by moving on system page table. + */ + bzero(kvtopte(nptespc), vax_btop(nlen-olen) * PPTESZ); + if (optespc) + bcopy(kvtopte(optespc), kvtopte(nptespc+nlen-olen), + vax_btop(olen)); + + pm->pm_p1ap = (struct pte *)nptespc; + pm->pm_p1br = (struct pte *)(nptespc+nlen-0x800000); + pm->pm_p1lr = 0x200000 - nlen/PPTESZ; + update_pcbs(pm); + + if (optespc) + extent_free(ptemap, optespc, olen, EX_WAITOK); +} + /* * Initialize a preallocated an zeroed pmap structure, */ static void pmap_pinit(pmap_t pmap) { - int bytesiz, res; + struct pte *pt; + struct vm_page *pg; /* * Allocate PTEs and stash them away in the pmap. - * XXX Ok to use kmem_alloc_wait() here? */ - bytesiz = PROCPTSIZE * sizeof(struct pte); - res = extent_alloc(ptemap, bytesiz, 4, 0, EX_WAITSPACE|EX_WAITOK, - (u_long *)&pmap->pm_p0br); - if (res) - panic("pmap_pinit"); - pmap->pm_p0lr = vax_btoc(MAXTSIZ + MAXDSIZ + MMAPSPACE) | AST_PCB; - (vaddr_t)pmap->pm_p1br = (vaddr_t)pmap->pm_p0br + bytesiz - 0x800000; - pmap->pm_p1lr = (0x200000 - vax_btoc(MAXSSIZ)); - pmap->pm_stack = USRSTACK; + pmap->pm_p0br = (struct pte *)pmap_getusrptes(pmap, PAGE_SIZE); + pmap->pm_p0lr = (PAGE_SIZE/PPTESZ) | AST_PCB; + bzero(kvtopte(pmap->pm_p0br), PPTESZ * LTOHPN); -#ifdef PMAPDEBUG -if (startpmapdebug) - printf("pmap_pinit(%p): p0br=%p p0lr=0x%lx p1br=%p p1lr=0x%lx\n", - pmap, pmap->pm_p0br, pmap->pm_p0lr, pmap->pm_p1br, pmap->pm_p1lr); -#endif + pt = (struct pte *)pmap_getusrptes(pmap, PAGE_SIZE); + pmap->pm_p1br = pt + (PAGE_SIZE/PPTESZ) - 0x200000; + pmap->pm_p1lr = (0x200000 - (PAGE_SIZE/PPTESZ)); + bzero(kvtopte(pt), PPTESZ * LTOHPN); + pmap->pm_p1ap = pt; - pmap->ref_count = 1; + PMDEBUG(("pmap_pinit(%p): p0br=%p p0lr=0x%lx p1br=%p p1lr=0x%lx\n", + pmap, pmap->pm_p0br, pmap->pm_p0lr, pmap->pm_p1br, pmap->pm_p1lr)); + + for (;;) { + pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO); + if (pg != NULL) + break; + uvm_wait("pmap_pinit"); + } + pmap->pm_pref = (u_char *)(VM_PAGE_TO_PHYS(pg)|KERNBASE); + pmap->pm_count = 1; pmap->pm_stats.resident_count = pmap->pm_stats.wired_count = 0; } @@ -524,27 +845,36 @@ pmap_release(struct pmap *pmap) int i; #endif -#ifdef PMAPDEBUG -if(startpmapdebug)printf("pmap_release: pmap %p\n",pmap); -#endif + PMDEBUG(("pmap_release: pmap %p\n",pmap)); if (pmap->pm_p0br == 0) return; #ifdef DEBUG - for (i = 0; i < NPTEPGS; i++) - if (pmap->pm_refcnt[i]) + for (i = 0; i < NPTEPROCSPC; i++) + if (pmap->pm_pref[i]) panic("pmap_release: refcnt %d index %d", - pmap->pm_refcnt[i], i); + pmap->pm_pref[i], i); saddr = (vaddr_t)pmap->pm_p0br; - eaddr = saddr + PROCPTSIZE * sizeof(struct pte); + eaddr = saddr + (pmap->pm_p0lr & ~AST_MASK) * PPTESZ; for (; saddr < eaddr; saddr += NBPG) if (kvtopte(saddr)->pg_pfn) - panic("pmap_release: page mapped"); + panic("pmap_release: P0 page mapped"); + saddr = (vaddr_t)pmap->pm_p1br + pmap->pm_p1lr * PPTESZ; + eaddr = KERNBASE; + for (; saddr < eaddr; saddr += NBPG) + if (kvtopte(saddr)->pg_pfn) + panic("pmap_release: P1 page mapped"); #endif - extent_free(ptemap, (u_long)pmap->pm_p0br, - PROCPTSIZE * sizeof(struct pte), EX_WAITOK); + uvm_pagefree(PHYS_TO_VM_PAGE((vaddr_t)pmap->pm_pref & ~KERNBASE)); + + if ((pmap->pm_p0lr & ~AST_MASK) != 0) + extent_free(ptemap, (u_long)pmap->pm_p0br, + (pmap->pm_p0lr & ~AST_MASK) * PPTESZ, EX_WAITOK); + if (pmap->pm_p1lr != 0x200000) + extent_free(ptemap, (u_long)pmap->pm_p1ap, + (0x200000 - pmap->pm_p1lr) * PPTESZ, EX_WAITOK); } /* @@ -559,52 +889,68 @@ pmap_destroy(pmap_t pmap) { int count; -#ifdef PMAPDEBUG -if(startpmapdebug)printf("pmap_destroy: pmap %p\n",pmap); -#endif + PMDEBUG(("pmap_destroy: pmap %p\n",pmap)); simple_lock(&pmap->pm_lock); - count = --pmap->ref_count; + count = --pmap->pm_count; simple_unlock(&pmap->pm_lock); if (count == 0) { +#ifdef DEBUG + if (pmap->pm_share && pmap->pm_share->ps_next) + panic("pmap_destroy used pmap"); +#endif pmap_release(pmap); FREE(pmap, M_VMPMAP); } } +static struct pte * +vaddrtopte(struct pv_entry *pv) +{ + struct pmap *pm; + if (pv->pv_pmap == NULL || pv->pv_vaddr == NOVADDR) + return NULL; + if (pv->pv_vaddr & KERNBASE) + return &Sysmap[(pv->pv_vaddr & ~KERNBASE) >> VAX_PGSHIFT]; + pm = pv->pv_pmap; + if (pv->pv_vaddr & 0x40000000) + return &pm->pm_p1br[vax_btop(pv->pv_vaddr & ~0x40000000)]; + else + return &pm->pm_p0br[vax_btop(pv->pv_vaddr)]; +} + + /* * Rensa is a help routine to remove a pv_entry from the pv list. * Arguments are physical clustering page and page table entry pointer. */ void -rensa(clp, ptp) - int clp; - struct pte *ptp; +rensa(int clp, struct pte *ptp) { + struct pte *pte; struct pv_entry *pf, *pl, *pv = pv_table + clp; int s, *g; -#ifdef PMAPDEBUG - if (startpmapdebug) - printf("rensa: pv %p clp 0x%x ptp %p\n", pv, clp, ptp); -#endif + PMDEBUG(("rensa: pv %p clp 0x%x ptp %p\n", pv, clp, ptp)); + if (IOSPACE(ptp->pg_pfn << VAX_PGSHIFT)) return; /* Nothing in pv_table */ s = splvm(); PVTABLE_LOCK; RECURSESTART; - if (pv->pv_pte == ptp) { - g = (int *)pv->pv_pte; + pte = vaddrtopte(pv); + if (pte == ptp) { + g = (int *)pte; if ((pv->pv_attr & (PG_V|PG_M)) != (PG_V|PG_M)) pv->pv_attr |= g[0]|g[1]|g[2]|g[3]|g[4]|g[5]|g[6]|g[7]; - pv->pv_pte = 0; simple_lock(&pv->pv_pmap->pm_lock); pv->pv_pmap->pm_stats.resident_count--; if (g[0] & PG_W) { pv->pv_pmap->pm_stats.wired_count--; } simple_unlock(&pv->pv_pmap->pm_lock); + pv->pv_vaddr = NOVADDR; pv->pv_pmap = 0; PVTABLE_UNLOCK; splx(s); @@ -612,10 +958,11 @@ rensa(clp, ptp) return; } for (pl = pv; pl->pv_next; pl = pl->pv_next) { - if (pl->pv_next->pv_pte == ptp) { + pte = vaddrtopte(pl->pv_next); + if (pte == ptp) { pf = pl->pv_next; pl->pv_next = pl->pv_next->pv_next; - g = (int *)pf->pv_pte; + g = (int *)vaddrtopte(pf); if ((pv->pv_attr & (PG_V|PG_M)) != (PG_V|PG_M)) pv->pv_attr |= g[0]|g[1]|g[2]|g[3]|g[4]|g[5]|g[6]|g[7]; @@ -645,10 +992,8 @@ pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot) int *ptp, opte; ptp = (int *)kvtopte(va); -#ifdef PMAPDEBUG -if(startpmapdebug) - printf("pmap_kenter_pa: va: %lx, pa %lx, prot %x ptp %p\n", va, pa, prot, ptp); -#endif + PMDEBUG(("pmap_kenter_pa: va: %lx, pa %lx, prot %x ptp %p\n", + va, pa, prot, ptp)); opte = ptp[0]; ptp[0] = PG_V | ((prot & VM_PROT_WRITE)? PG_KW : PG_KR) | PG_PFNUM(pa) | PG_SREF; @@ -671,15 +1016,13 @@ void pmap_kremove(vaddr_t va, vsize_t len) { struct pte *pte; - #ifdef PMAPDEBUG int i; - - if(startpmapdebug) - printf("pmap_kremove: va: %lx, len %lx, ptp %p\n", - va, len, kvtopte(va)); #endif + PMDEBUG(("pmap_kremove: va: %lx, len %lx, ptp %p\n", + va, len, kvtopte(va))); + pte = kvtopte(va); #ifdef PMAPDEBUG @@ -713,22 +1056,19 @@ pmap_kremove(vaddr_t va, vsize_t len) int pmap_enter(pmap, v, p, prot, flags) pmap_t pmap; - vaddr_t v; - paddr_t p; + vaddr_t v; + paddr_t p; vm_prot_t prot; int flags; { - struct pv_entry *pv, *tmp; - int i, s, newpte, oldpte, *patch, index = 0; /* XXX gcc */ + struct pv_entry *pv, *tmp; + int i, s, newpte, oldpte, *patch, idx = 0; /* XXX gcc */ #ifdef PMAPDEBUG boolean_t wired = (flags & PMAP_WIRED) != 0; #endif -#ifdef PMAPDEBUG -if (startpmapdebug) - printf("pmap_enter: pmap %p v %lx p %lx prot %x wired %d access %x\n", - pmap, v, p, prot, wired, flags & VM_PROT_ALL); -#endif + PMDEBUG(("pmap_enter: pmap %p v %lx p %lx prot %x wired %d access %x\n", + pmap, v, p, prot, wired, flags & VM_PROT_ALL)); RECURSESTART; /* Find address of correct pte */ @@ -738,17 +1078,15 @@ if (startpmapdebug) newpte = (p>>VAX_PGSHIFT)|(prot&VM_PROT_WRITE?PG_KW:PG_KR); } else { if (v < 0x40000000) { - patch = (int *)pmap->pm_p0br; - i = (v >> VAX_PGSHIFT); + i = vax_btop(v); if (i >= (pmap->pm_p0lr & ~AST_MASK)) - panic("P0 too small in pmap_enter"); + grow_p0(pmap, i); + patch = (int *)pmap->pm_p0br; } else { - patch = (int *)pmap->pm_p1br; - i = (v - 0x40000000) >> VAX_PGSHIFT; + i = vax_btop(v - 0x40000000); if (i < pmap->pm_p1lr) - panic("pmap_enter: must expand P1"); - if (v < pmap->pm_stack) - pmap->pm_stack = v; + grow_p1(pmap, i); + patch = (int *)pmap->pm_p1br; } newpte = (p >> VAX_PGSHIFT) | (prot & VM_PROT_WRITE ? PG_RW : PG_RO); @@ -756,12 +1094,11 @@ if (startpmapdebug) /* * Check if a pte page must be mapped in. */ - index = ((u_int)&patch[i] - (u_int)pmap->pm_p0br) >> PGSHIFT; -#ifdef DIAGNOSTIC - if ((index < 0) || (index >= NPTEPGS)) - panic("pmap_enter: bad index %d", index); -#endif - if (pmap->pm_refcnt[index] == 0) { + if (pmap->pm_pref == NULL) + panic("pmap->pm_pref"); + idx = (v >> PGSHIFT)/NPTEPG; + + if (pmap->pm_pref[idx] == 0) { vaddr_t ptaddr = trunc_page((vaddr_t)&patch[i]); paddr_t phys; struct vm_page *pg; @@ -808,7 +1145,7 @@ if (startpmapdebug) patch[i+6] = newpte+6; patch[i+7] = newpte+7; if (pmap != pmap_kernel()) - pmap->pm_refcnt[index]++; /* New mapping */ + pmap->pm_pref[idx]++; /* New mapping */ RECURSEEND; return 0; } @@ -854,16 +1191,16 @@ if (startpmapdebug) (struct pte *)&patch[i]); RECURSESTART; } else if (pmap != pmap_kernel()) - pmap->pm_refcnt[index]++; /* New mapping */ + pmap->pm_pref[idx]++; /* New mapping */ s = splvm(); PVTABLE_LOCK; - if (pv->pv_pte == 0) { - pv->pv_pte = (struct pte *)&patch[i]; + if (pv->pv_pmap == NULL) { + pv->pv_vaddr = v; pv->pv_pmap = pmap; } else { tmp = get_pventry(); - tmp->pv_pte = (struct pte *)&patch[i]; + tmp->pv_vaddr = v; tmp->pv_pmap = pmap; tmp->pv_next = pv->pv_next; pv->pv_next = tmp; @@ -899,8 +1236,8 @@ if (startpmapdebug) RECURSEEND; #ifdef DEBUG if (pmap != pmap_kernel()) - if (pmap->pm_refcnt[index] > VAX_NBPG/sizeof(struct pte)) - panic("pmap_enter: refcnt %d", pmap->pm_refcnt[index]); + if (pmap->pm_pref[idx] > VAX_NBPG/sizeof(struct pte)) + panic("pmap_enter: refcnt %d", pmap->pm_pref[idx]); #endif if (pventries < 10) more_pventries(); @@ -912,17 +1249,14 @@ if (startpmapdebug) vaddr_t pmap_map(virtuell, pstart, pend, prot) vaddr_t virtuell; - paddr_t pstart, pend; + paddr_t pstart, pend; int prot; { vaddr_t count; int *pentry; -#ifdef PMAPDEBUG -if(startpmapdebug) - printf("pmap_map: virt %lx, pstart %lx, pend %lx, Sysmap %p\n", - virtuell, pstart, pend, Sysmap); -#endif + PMDEBUG(("pmap_map: virt %lx, pstart %lx, pend %lx, Sysmap %p\n", + virtuell, pstart, pend, Sysmap)); pstart=(uint)pstart &0x7fffffff; pend=(uint)pend &0x7fffffff; @@ -945,9 +1279,7 @@ pmap_extract(pmap, va, pap) paddr_t pa = 0; int *pte, sva; -#ifdef PMAPDEBUG -if(startpmapdebug)printf("pmap_extract: pmap %p, va %lx\n",pmap, va); -#endif + PMDEBUG(("pmap_extract: pmap %p, va %lx\n",pmap, va)); if (va & KERNBASE) { pa = kvtophys(va); /* Is 0 if not mapped */ @@ -984,16 +1316,14 @@ if(startpmapdebug)printf("pmap_extract: pmap %p, va %lx\n",pmap, va); void pmap_protect(pmap, start, end, prot) pmap_t pmap; - vaddr_t start, end; + vaddr_t start, end; vm_prot_t prot; { struct pte *pt, *pts, *ptd; - int pr; + int pr, off, idx; -#ifdef PMAPDEBUG -if(startpmapdebug) printf("pmap_protect: pmap %p, start %lx, end %lx, prot %x\n", - pmap, start, end,prot); -#endif + PMDEBUG(("pmap_protect: pmap %p, start %lx, end %lx, prot %x\n", + pmap, start, end,prot)); if (pmap == 0) return; @@ -1010,25 +1340,28 @@ if(startpmapdebug) printf("pmap_protect: pmap %p, start %lx, end %lx, prot %x\n" pr = (prot & VM_PROT_WRITE ? PROT_KW : PROT_KR); } else { if (start & 0x40000000) { /* P1 space */ - if (end <= pmap->pm_stack) { + if (vax_btop(end - 0x40000000) <= pmap->pm_p1lr) { RECURSEEND; return; } - if (start < pmap->pm_stack) - start = pmap->pm_stack; + if (vax_btop(start - 0x40000000) < pmap->pm_p1lr) + start = pmap->pm_p1lr * VAX_NBPG; pt = pmap->pm_p1br; -#ifdef DIAGNOSTIC - if (((start & 0x3fffffff) >> VAX_PGSHIFT) < pmap->pm_p1lr) - panic("pmap_protect: outside P1LR"); -#endif start &= 0x3fffffff; end = (end == KERNBASE ? end >> 1 : end & 0x3fffffff); + off = 0x800; } else { /* P0 space */ + int lr = pmap->pm_p0lr & ~AST_MASK; + + /* Anything to care about at all? */ + if (vax_btop(start) > lr) { + RECURSEEND; + return; + } + if (vax_btop(end) > lr) + end = lr * VAX_NBPG; pt = pmap->pm_p0br; -#ifdef DIAGNOSTIC - if ((end >> VAX_PGSHIFT) > (pmap->pm_p0lr & ~AST_MASK)) - panic("pmap_protect: outside P0LR"); -#endif + off = 0; } pr = (prot & VM_PROT_WRITE ? PROT_RW : PROT_RO); } @@ -1049,7 +1382,16 @@ if(startpmapdebug) printf("pmap_protect: pmap %p, start %lx, end %lx, prot %x\n" rensa(pts->pg_pfn >> LTOHPS, pts); RECURSESTART; bzero(pts, sizeof(struct pte) * LTOHPN); - pmap_decpteref(pmap, pts); + if (pt != Sysmap) { + idx = ((pts - pt) >> LTOHPS)/NPTEPG + off; + PMDEBUG(("pmap_protect: pmap %p pts %p index %d refcnt %d\n", + pmap, pts, idx, pmap->pm_pref[idx])); + + if (pmap->pm_pref[idx] > 1) + pmap->pm_pref[idx]--; + else + pmap_decpteref(pmap, pts); + } } else { pts[0].pg_prot = pr; pts[1].pg_prot = pr; @@ -1080,13 +1422,11 @@ int pmap_simulref(int bits, int addr) { u_int *pte; - struct pv_entry *pv; - paddr_t pa; + struct pv_entry *pv; + paddr_t pa; + + PMDEBUG(("pmap_simulref: bits %x addr %x\n", bits, addr)); -#ifdef PMAPDEBUG -if (startpmapdebug) - printf("pmap_simulref: bits %x addr %x\n", bits, addr); -#endif #ifdef DEBUG if (bits & 1) panic("pte trans len"); @@ -1144,10 +1484,7 @@ pmap_is_referenced(struct vm_page *pg) panic("pmap_is_referenced: called for iospace"); #endif pv = pv_table + (pa >> PGSHIFT); -#ifdef PMAPDEBUG - if (startpmapdebug) - printf("pmap_is_referenced: pa %lx pv_entry %p ", pa, pv); -#endif + PMDEBUG(("pmap_is_referenced: pa %lx pv_entry %p ", pa, pv)); if (pv->pv_attr & PG_V) return 1; @@ -1161,6 +1498,7 @@ pmap_is_referenced(struct vm_page *pg) boolean_t pmap_clear_reference(struct vm_page *pg) { + struct pte *pte; paddr_t pa = VM_PAGE_TO_PHYS(pg); struct pv_entry *pv; int ref = 0; @@ -1170,10 +1508,8 @@ pmap_clear_reference(struct vm_page *pg) panic("pmap_clear_reference: called for iospace"); #endif pv = pv_table + (pa >> PGSHIFT); -#ifdef PMAPDEBUG - if (startpmapdebug) - printf("pmap_clear_reference: pa %lx pv_entry %p\n", pa, pv); -#endif + + PMDEBUG(("pmap_clear_reference: pa %lx pv_entry %p\n", pa, pv)); if (pv->pv_attr & PG_V) ref++; @@ -1182,23 +1518,29 @@ pmap_clear_reference(struct vm_page *pg) RECURSESTART; PVTABLE_LOCK; - if (pv->pv_pte && (pv->pv_pte[0].pg_w == 0)) - pv->pv_pte[0].pg_v = pv->pv_pte[1].pg_v = - pv->pv_pte[2].pg_v = pv->pv_pte[3].pg_v = - pv->pv_pte[4].pg_v = pv->pv_pte[5].pg_v = - pv->pv_pte[6].pg_v = pv->pv_pte[7].pg_v = 0; + if (pv->pv_pmap != NULL) { + pte = vaddrtopte(pv); + if (pte->pg_w == 0) { + pte[0].pg_v = pte[1].pg_v = pte[2].pg_v = + pte[3].pg_v = pte[4].pg_v = pte[5].pg_v = + pte[6].pg_v = pte[7].pg_v = 0; + } + } - while ((pv = pv->pv_next)) - if (pv->pv_pte[0].pg_w == 0) - pv->pv_pte[0].pg_v = pv->pv_pte[1].pg_v = - pv->pv_pte[2].pg_v = pv->pv_pte[3].pg_v = - pv->pv_pte[4].pg_v = pv->pv_pte[5].pg_v = - pv->pv_pte[6].pg_v = pv->pv_pte[7].pg_v = 0; + while ((pv = pv->pv_next)) { + pte = vaddrtopte(pv); + if (pte[0].pg_w == 0) { + pte[0].pg_v = pte[1].pg_v = + pte[2].pg_v = pte[3].pg_v = + pte[4].pg_v = pte[5].pg_v = + pte[6].pg_v = pte[7].pg_v = 0; + } + } PVTABLE_UNLOCK; RECURSEEND; #ifdef MULTIPROCESSOR cpu_send_ipi(IPI_DEST_ALL, IPI_TBIA); -#endif +#endif mtpr(0, PR_TBIA); return ref; } @@ -1209,6 +1551,7 @@ pmap_clear_reference(struct vm_page *pg) boolean_t pmap_is_modified(struct vm_page *pg) { + struct pte *pte; paddr_t pa = VM_PAGE_TO_PHYS(pg); struct pv_entry *pv; @@ -1217,48 +1560,36 @@ pmap_is_modified(struct vm_page *pg) panic("pmap_is_modified: called for iospace"); #endif pv = pv_table + (pa >> PGSHIFT); -#ifdef PMAPDEBUG - if (startpmapdebug) - printf("pmap_is_modified: pa %lx pv_entry %p ", pa, pv); -#endif + + PMDEBUG(("pmap_is_modified: pa %lx pv_entry %p ", pa, pv)); if (pv->pv_attr & PG_M) { -#ifdef PMAPDEBUG - if (startpmapdebug) - printf("Yes: (0)\n"); -#endif + PMDEBUG(("Yes: (0)\n")); return 1; } PVTABLE_LOCK; - if (pv->pv_pte) - if ((pv->pv_pte[0].pg_m | pv->pv_pte[1].pg_m - | pv->pv_pte[2].pg_m | pv->pv_pte[3].pg_m - | pv->pv_pte[4].pg_m | pv->pv_pte[5].pg_m - | pv->pv_pte[6].pg_m | pv->pv_pte[7].pg_m)) { -#ifdef PMAPDEBUG - if (startpmapdebug) printf("Yes: (1)\n"); -#endif + if (pv->pv_pmap != NULL) { + pte = vaddrtopte(pv); + if ((pte[0].pg_m | pte[1].pg_m | pte[2].pg_m | pte[3].pg_m | + pte[4].pg_m | pte[5].pg_m | pte[6].pg_m | pte[7].pg_m)) { + PMDEBUG(("Yes: (1)\n")); PVTABLE_UNLOCK; return 1; } + } while ((pv = pv->pv_next)) { - if ((pv->pv_pte[0].pg_m | pv->pv_pte[1].pg_m - | pv->pv_pte[2].pg_m | pv->pv_pte[3].pg_m - | pv->pv_pte[4].pg_m | pv->pv_pte[5].pg_m - | pv->pv_pte[6].pg_m | pv->pv_pte[7].pg_m)) { -#ifdef PMAPDEBUG - if (startpmapdebug) printf("Yes: (2)\n"); -#endif + pte = vaddrtopte(pv); + if ((pte[0].pg_m | pte[1].pg_m | pte[2].pg_m | pte[3].pg_m + | pte[4].pg_m | pte[5].pg_m | pte[6].pg_m | pte[7].pg_m)) { + PMDEBUG(("Yes: (2)\n")); PVTABLE_UNLOCK; return 1; } } PVTABLE_UNLOCK; -#ifdef PMAPDEBUG - if (startpmapdebug) printf("No\n"); -#endif + PMDEBUG(("No\n")); return 0; } @@ -1268,6 +1599,7 @@ pmap_is_modified(struct vm_page *pg) boolean_t pmap_clear_modify(struct vm_page *pg) { + struct pte *pte; paddr_t pa = VM_PAGE_TO_PHYS(pg); struct pv_entry *pv; boolean_t rv = FALSE; @@ -1278,40 +1610,31 @@ pmap_clear_modify(struct vm_page *pg) #endif pv = pv_table + (pa >> PGSHIFT); -#ifdef PMAPDEBUG - if (startpmapdebug) - printf("pmap_clear_modify: pa %lx pv_entry %p\n", pa, pv); -#endif + PMDEBUG(("pmap_clear_modify: pa %lx pv_entry %p\n", pa, pv)); PVTABLE_LOCK; if (pv->pv_attr & PG_M) { rv = TRUE; } pv->pv_attr &= ~PG_M; - if (pv->pv_pte) { - if (pv->pv_pte[0].pg_m | pv->pv_pte[1].pg_m | - pv->pv_pte[2].pg_m | pv->pv_pte[3].pg_m | - pv->pv_pte[4].pg_m | pv->pv_pte[5].pg_m | - pv->pv_pte[6].pg_m | pv->pv_pte[7].pg_m) { + if (pv->pv_pmap != NULL) { + pte = vaddrtopte(pv); + if (pte[0].pg_m | pte[1].pg_m | pte[2].pg_m | pte[3].pg_m | + pte[4].pg_m | pte[5].pg_m | pte[6].pg_m | pte[7].pg_m) { rv = TRUE; } - pv->pv_pte[0].pg_m = pv->pv_pte[1].pg_m = - pv->pv_pte[2].pg_m = pv->pv_pte[3].pg_m = - pv->pv_pte[4].pg_m = pv->pv_pte[5].pg_m = - pv->pv_pte[6].pg_m = pv->pv_pte[7].pg_m = 0; + pte[0].pg_m = pte[1].pg_m = pte[2].pg_m = pte[3].pg_m = + pte[4].pg_m = pte[5].pg_m = pte[6].pg_m = pte[7].pg_m = 0; } while ((pv = pv->pv_next)) { - if (pv->pv_pte[0].pg_m | pv->pv_pte[1].pg_m | - pv->pv_pte[2].pg_m | pv->pv_pte[3].pg_m | - pv->pv_pte[4].pg_m | pv->pv_pte[5].pg_m | - pv->pv_pte[6].pg_m | pv->pv_pte[7].pg_m) { + pte = vaddrtopte(pv); + if (pte[0].pg_m | pte[1].pg_m | pte[2].pg_m | pte[3].pg_m | + pte[4].pg_m | pte[5].pg_m | pte[6].pg_m | pte[7].pg_m) { rv = TRUE; } - pv->pv_pte[0].pg_m = pv->pv_pte[1].pg_m = - pv->pv_pte[2].pg_m = pv->pv_pte[3].pg_m = - pv->pv_pte[4].pg_m = pv->pv_pte[5].pg_m = - pv->pv_pte[6].pg_m = pv->pv_pte[7].pg_m = 0; + pte[0].pg_m = pte[1].pg_m = pte[2].pg_m = pte[3].pg_m = + pte[4].pg_m = pte[5].pg_m = pte[6].pg_m = pte[7].pg_m = 0; } PVTABLE_UNLOCK; return rv; @@ -1328,21 +1651,20 @@ pmap_page_protect(struct vm_page *pg, vm_prot_t prot) struct pte *pt; struct pv_entry *pv, *opv, *pl; int s, *g; - paddr_t pa; -#ifdef PMAPDEBUG -if(startpmapdebug) printf("pmap_page_protect: pg %p, prot %x, ",pg, prot); -#endif + paddr_t pa; + + PMDEBUG(("pmap_page_protect: pg %p, prot %x, ",pg, prot)); + pa = VM_PAGE_TO_PHYS(pg); -#ifdef PMAPDEBUG -if(startpmapdebug) printf("pa %lx\n",pa); -#endif + + PMDEBUG(("pa %lx\n",pa)); #ifdef DEBUG if (IOSPACE(pa)) panic("pmap_page_protect: called for iospace"); #endif pv = pv_table + (pa >> PGSHIFT); - if (pv->pv_pte == 0 && pv->pv_next == 0) + if (pv->pv_pmap == NULL && pv->pv_next == NULL) return; if (prot == VM_PROT_ALL) /* 'cannot happen' */ @@ -1352,8 +1674,10 @@ if(startpmapdebug) printf("pa %lx\n",pa); PVTABLE_LOCK; if (prot == VM_PROT_NONE) { s = splvm(); - g = (int *)pv->pv_pte; + g = (int *)vaddrtopte(pv); if (g) { + int idx; + simple_lock(&pv->pv_pmap->pm_lock); pv->pv_pmap->pm_stats.resident_count--; if (g[0] & PG_W) { @@ -1364,14 +1688,25 @@ if(startpmapdebug) printf("pa %lx\n",pa); pv->pv_attr |= g[0]|g[1]|g[2]|g[3]|g[4]|g[5]|g[6]|g[7]; bzero(g, sizeof(struct pte) * LTOHPN); - pmap_decpteref(pv->pv_pmap, pv->pv_pte); - pv->pv_pte = 0; + if (pv->pv_pmap != pmap_kernel()) { + idx = pv->pv_vaddr/(VAX_NBPG*NPTEPG*LTOHPN); + PMDEBUG(("pmap_page_protect: pmap %p pts %p index %d refcnt %d\n", + pv->pv_pmap, g, idx, pv->pv_pmap->pm_pref[idx])); + if (pv->pv_pmap->pm_pref[idx] > 1) + pv->pv_pmap->pm_pref[idx]--; + else + pmap_decpteref(pv->pv_pmap, (void *)g); + } + pv->pv_vaddr = NOVADDR; + pv->pv_pmap = NULL; } pl = pv->pv_next; pv->pv_pmap = 0; pv->pv_next = 0; while (pl) { - g = (int *)pl->pv_pte; + int idx; + + g = (int *)vaddrtopte(pl); simple_lock(&pl->pv_pmap->pm_lock); pl->pv_pmap->pm_stats.resident_count--; if (g[0] & PG_W) { @@ -1382,7 +1717,15 @@ if(startpmapdebug) printf("pa %lx\n",pa); pv->pv_attr |= g[0]|g[1]|g[2]|g[3]|g[4]|g[5]|g[6]|g[7]; bzero(g, sizeof(struct pte) * LTOHPN); - pmap_decpteref(pl->pv_pmap, pl->pv_pte); + if (pl->pv_pmap != pmap_kernel()) { + idx = pl->pv_vaddr/(VAX_NBPG*NPTEPG*LTOHPN); + PMDEBUG(("pmap_page_protect: pmap %p pts %p index %d refcnt %d\n", + pl->pv_pmap, g, idx, pl->pv_pmap->pm_pref[idx])); + if (pl->pv_pmap->pm_pref[idx] > 1) + pl->pv_pmap->pm_pref[idx]--; + else + pmap_decpteref(pl->pv_pmap, (void *)g); + } opv = pl; pl = pl->pv_next; free_pventry(opv); @@ -1390,15 +1733,14 @@ if(startpmapdebug) printf("pa %lx\n",pa); splx(s); } else { /* read-only */ do { - pt = pv->pv_pte; + pt = vaddrtopte(pv); if (pt == 0) continue; pt[0].pg_prot = pt[1].pg_prot = pt[2].pg_prot = pt[3].pg_prot = pt[4].pg_prot = pt[5].pg_prot = pt[6].pg_prot = pt[7].pg_prot = - ((vaddr_t)pv->pv_pte < ptemapstart ? - PROT_KR : PROT_RO); + ((vaddr_t)pt < ptemapstart ? PROT_KR : PROT_RO); } while ((pv = pv->pv_next)); } PVTABLE_UNLOCK; @@ -1418,28 +1760,65 @@ if(startpmapdebug) printf("pa %lx\n",pa); void pmap_activate(struct proc *p) { + struct pm_share *ps; pmap_t pmap; struct pcb *pcb; -#ifdef PMAPDEBUG -if(startpmapdebug) printf("pmap_activate: p %p\n", p); -#endif + PMDEBUG(("pmap_activate: p %p\n", p)); pmap = p->p_vmspace->vm_map.pmap; pcb = &p->p_addr->u_pcb; pcb->P0BR = pmap->pm_p0br; - pcb->P0LR = pmap->pm_p0lr; + pcb->P0LR = pmap->pm_p0lr|AST_PCB; pcb->P1BR = pmap->pm_p1br; pcb->P1LR = pmap->pm_p1lr; + ps = (struct pm_share *)get_pventry(); + ps->ps_next = pmap->pm_share; + pmap->pm_share = ps; + ps->ps_pcb = pcb; + if (p == curproc) { mtpr(pmap->pm_p0br, PR_P0BR); - mtpr(pmap->pm_p0lr, PR_P0LR); + mtpr(pmap->pm_p0lr|AST_PCB, PR_P0LR); mtpr(pmap->pm_p1br, PR_P1BR); mtpr(pmap->pm_p1lr, PR_P1LR); } - mtpr(0, PR_TBIA); +} + +void +pmap_deactivate(struct proc *p) +{ + struct pm_share *ps, *ops; + pmap_t pmap; + struct pcb *pcb; + + PMDEBUG(("pmap_deactivate: p %p\n", p)); + + pmap = p->p_vmspace->vm_map.pmap; + pcb = &p->p_addr->u_pcb; + + ps = pmap->pm_share; + if (ps->ps_pcb == pcb) { + pmap->pm_share = ps->ps_next; + free_pventry((struct pv_entry *)ps); + return; + } + ops = ps; + ps = ps->ps_next; + while (ps != NULL) { + if (ps->ps_pcb == pcb) { + ops->ps_next = ps->ps_next; + free_pventry((struct pv_entry *)ps); + return; + } + ops = ps; + ps = ps->ps_next; + } +#ifdef DEBUG + panic("pmap_deactivate: not in list"); +#endif } /* @@ -1450,9 +1829,9 @@ pmap_unwire(pmap_t pmap, vaddr_t v) { int *pte; -#ifdef PMAPDEBUG -if(startpmapdebug) printf("pmap_unwire: pmap %p v %lx\n", pmap, v); -#endif + PMDEBUG(("pmap_unwire: pmap %p v %lx\n", pmap, v)); + + RECURSESTART; if (v & KERNBASE) { pte = (int *)kvtopte(v); } else { @@ -1462,6 +1841,7 @@ if(startpmapdebug) printf("pmap_unwire: pmap %p v %lx\n", pmap, v); pte = (int *)&pmap->pm_p1br[PG_PFNUM(v)]; } pte[0] &= ~PG_W; + RECURSEEND; pmap->pm_stats.wired_count--; } @@ -1532,3 +1912,39 @@ more_pventries() PVTABLE_UNLOCK; splx(s); } + + +/* + * Called when a process is about to be swapped, to remove the page tables. + */ +void +cpu_swapout(struct proc *p) +{ + pmap_t pm; + + PMDEBUG(("Swapout pid %d\n", p->p_pid)); + + pm = p->p_vmspace->vm_map.pmap; + rmspace(pm); + pmap_deactivate(p); +} + +/* + * Kernel stack red zone need to be set when a process is swapped in. + * Be sure that all pages are valid. + */ +void +cpu_swapin(struct proc *p) +{ + struct pte *pte; + int i; + + PMDEBUG(("Swapin pid %d\n", p->p_pid)); + + pte = kvtopte((vaddr_t)p->p_addr); + for (i = 0; i < (USPACE/VAX_NBPG); i ++) + pte[i].pg_v = 1; + kvtopte((vaddr_t)p->p_addr + REDZONEADDR)->pg_v = 0; + pmap_activate(p); +} + diff --git a/sys/arch/vax/vax/trap.c b/sys/arch/vax/vax/trap.c index d210431c06d6..747c9cd0200c 100644 --- a/sys/arch/vax/vax/trap.c +++ b/sys/arch/vax/vax/trap.c @@ -1,4 +1,4 @@ -/* $NetBSD: trap.c,v 1.67 2002/02/14 07:08:18 chs Exp $ */ +/* $NetBSD: trap.c,v 1.68 2002/03/10 22:32:31 ragge Exp $ */ /* * Copyright (c) 1994 Ludd, University of Lule}, Sweden. @@ -194,11 +194,15 @@ fram: #ifdef nohwbug panic("translation fault"); #endif + + case T_PTELEN|T_USER: /* Page table length exceeded */ case T_ACCFLT|T_USER: if (frame->code < 0) { /* Check for kernel space */ sig = SIGSEGV; break; } + + case T_PTELEN: case T_ACCFLT: #ifdef TRAPDEBUG if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n", @@ -260,16 +264,6 @@ if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n", KERNEL_UNLOCK(); break; - case T_PTELEN: - if (p && p->p_addr) - FAULTCHK; - panic("ptelen fault in system space: addr %lx pc %lx", - frame->code, frame->pc); - - case T_PTELEN|T_USER: /* Page table length exceeded */ - sig = SIGSEGV; - break; - case T_BPTFLT|T_USER: case T_TRCTRAP|T_USER: sig = SIGTRAP; diff --git a/sys/arch/vax/vax/vm_machdep.c b/sys/arch/vax/vax/vm_machdep.c index ed48ab4f5e57..936abdda14db 100644 --- a/sys/arch/vax/vax/vm_machdep.c +++ b/sys/arch/vax/vax/vm_machdep.c @@ -1,4 +1,4 @@ -/* $NetBSD: vm_machdep.c,v 1.76 2002/03/04 02:43:25 simonb Exp $ */ +/* $NetBSD: vm_machdep.c,v 1.77 2002/03/10 22:32:31 ragge Exp $ */ /* * Copyright (c) 1994 Ludd, University of Lule}, Sweden. @@ -260,23 +260,6 @@ cpu_coredump(p, vp, cred, chdr) return error; } -/* - * Kernel stack red zone need to be set when a process is swapped in. - * Be sure that all pages are valid. - */ -void -cpu_swapin(p) - struct proc *p; -{ - struct pte *pte; - int i; - - pte = kvtopte((vaddr_t)p->p_addr); - for (i = 0; i < (USPACE/VAX_NBPG); i ++) - pte[i].pg_v = 1; - kvtopte((vaddr_t)p->p_addr + REDZONEADDR)->pg_v = 0; -} - /* * Map in a bunch of pages read/writeable for the kernel. */