Module Name: src Committed By: matt Date: Wed Dec 30 04:51:26 UTC 2009
Modified Files: src/sys/arch/mips/conf [matt-nb5-mips64]: files.mips src/sys/arch/mips/include [matt-nb5-mips64]: cpu.h locore.h pmap.h proc.h pte.h vmparam.h src/sys/arch/mips/mips [matt-nb5-mips64]: locore.S mips_machdep.c pmap.c trap.c Added Files: src/sys/arch/mips/mips [matt-nb5-mips64]: pmap_segtab.c Log Message: Please segtab lookups into separate file. Add mips_add_physload Add mips_init_lwp0_uarea cleanup lwp0/cpu_info_store initialization. To generate a diff of this commit: cvs rdiff -u -r1.58.24.3 -r1.58.24.4 src/sys/arch/mips/conf/files.mips cvs rdiff -u -r1.90.16.8 -r1.90.16.9 src/sys/arch/mips/include/cpu.h cvs rdiff -u -r1.78.36.1.2.6 -r1.78.36.1.2.7 \ src/sys/arch/mips/include/locore.h cvs rdiff -u -r1.54.26.1 -r1.54.26.2 src/sys/arch/mips/include/pmap.h cvs rdiff -u -r1.21.36.3 -r1.21.36.4 src/sys/arch/mips/include/proc.h cvs rdiff -u -r1.19 -r1.19.18.1 src/sys/arch/mips/include/pte.h cvs rdiff -u -r1.41.28.7 -r1.41.28.8 src/sys/arch/mips/include/vmparam.h cvs rdiff -u -r1.167.38.3 -r1.167.38.4 src/sys/arch/mips/mips/locore.S cvs rdiff -u -r1.205.4.1.2.1.2.17 -r1.205.4.1.2.1.2.18 \ src/sys/arch/mips/mips/mips_machdep.c cvs rdiff -u -r1.179.16.6 -r1.179.16.7 src/sys/arch/mips/mips/pmap.c cvs rdiff -u -r0 -r1.1.2.1 src/sys/arch/mips/mips/pmap_segtab.c cvs rdiff -u -r1.217.12.11 -r1.217.12.12 src/sys/arch/mips/mips/trap.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/mips/conf/files.mips diff -u src/sys/arch/mips/conf/files.mips:1.58.24.3 src/sys/arch/mips/conf/files.mips:1.58.24.4 --- src/sys/arch/mips/conf/files.mips:1.58.24.3 Sun Sep 13 03:28:51 2009 +++ src/sys/arch/mips/conf/files.mips Wed Dec 30 04:51:25 2009 @@ -1,4 +1,4 @@ -# $NetBSD: files.mips,v 1.58.24.3 2009/09/13 03:28:51 cliff Exp $ +# $NetBSD: files.mips,v 1.58.24.4 2009/12/30 04:51:25 matt Exp $ # defflag opt_cputype.h NOFPU @@ -34,6 +34,7 @@ file arch/mips/mips/kgdb_machdep.c kgdb file arch/mips/mips/mem.c file arch/mips/mips/pmap.c +file arch/mips/mips/pmap_segtab.c file arch/mips/mips/trap.c # trap handlers file arch/mips/mips/syscall.c # syscall entries file arch/mips/mips/mips_machdep.c Index: src/sys/arch/mips/include/cpu.h diff -u src/sys/arch/mips/include/cpu.h:1.90.16.8 src/sys/arch/mips/include/cpu.h:1.90.16.9 --- src/sys/arch/mips/include/cpu.h:1.90.16.8 Mon Nov 23 23:48:58 2009 +++ src/sys/arch/mips/include/cpu.h Wed Dec 30 04:51:26 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: cpu.h,v 1.90.16.8 2009/11/23 23:48:58 cliff Exp $ */ +/* $NetBSD: cpu.h,v 1.90.16.9 2009/12/30 04:51:26 matt Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -393,7 +393,8 @@ struct lwp; struct user; -extern struct segtab *segbase; /* current segtab base */ +extern struct segtab *segbase; /* current segtab base */ +extern int mips_poolpage_vmfreelist; /* freelist to allocate poolpages */ /* copy.S */ int8_t ufetch_int8(void *); @@ -477,9 +478,15 @@ int kdbpeek(vaddr_t); /* mips_machdep.c */ +struct mips_vmfreelist; +struct phys_ram_seg; void dumpsys(void); int savectx(struct user *); void mips_init_msgbuf(void); +void mips_init_lwp0_uarea(void); +void mips_page_physload(vaddr_t, vaddr_t, + const struct phys_ram_seg *, size_t, + const struct mips_vmfreelist *, size_t); void savefpregs(struct lwp *); void loadfpregs(struct lwp *); Index: src/sys/arch/mips/include/locore.h diff -u src/sys/arch/mips/include/locore.h:1.78.36.1.2.6 src/sys/arch/mips/include/locore.h:1.78.36.1.2.7 --- src/sys/arch/mips/include/locore.h:1.78.36.1.2.6 Sun Dec 13 00:25:30 2009 +++ src/sys/arch/mips/include/locore.h Wed Dec 30 04:51:26 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: locore.h,v 1.78.36.1.2.6 2009/12/13 00:25:30 matt Exp $ */ +/* $NetBSD: locore.h,v 1.78.36.1.2.7 2009/12/30 04:51:26 matt Exp $ */ /* * Copyright 1996 The Board of Trustees of The Leland Stanford @@ -307,6 +307,12 @@ uintptr_t lsw_setfunc_trampoline; }; +struct mips_vmfreelist { + paddr_t fl_start; + paddr_t fl_end; + int fl_freelist; +}; + /* * The "active" locore-fuction vector, and */ Index: src/sys/arch/mips/include/pmap.h diff -u src/sys/arch/mips/include/pmap.h:1.54.26.1 src/sys/arch/mips/include/pmap.h:1.54.26.2 --- src/sys/arch/mips/include/pmap.h:1.54.26.1 Mon Sep 7 21:42:17 2009 +++ src/sys/arch/mips/include/pmap.h Wed Dec 30 04:51:26 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.h,v 1.54.26.1 2009/09/07 21:42:17 matt Exp $ */ +/* $NetBSD: pmap.h,v 1.54.26.2 2009/12/30 04:51:26 matt Exp $ */ /* * Copyright (c) 1992, 1993 @@ -75,6 +75,7 @@ #define _MIPS_PMAP_H_ #include <mips/cpuregs.h> /* for KSEG0 below */ +#include <mips/pte.h> /* * The user address space is 2Gb (0x0 - 0x80000000). @@ -100,7 +101,6 @@ #define mips_trunc_seg(x) ((vaddr_t)(x) & ~SEGOFSET) #define mips_round_seg(x) (((vaddr_t)(x) + SEGOFSET) & ~SEGOFSET) -#define pmap_segmap(m, v) ((m)->pm_segtab->seg_tab[((v) >> SEGSHIFT)]) #define PMAP_SEGTABSIZE (1 << (31 - SEGSHIFT)) @@ -110,6 +110,17 @@ union pt_entry *seg_tab[PMAP_SEGTABSIZE]; }; +struct pmap; +typedef bool (*pte_callback_t)(struct pmap *, vaddr_t, vaddr_t, pt_entry_t *, + uintptr_t); +pt_entry_t *pmap_pte_lookup(struct pmap *, vaddr_t); +pt_entry_t *pmap_pte_reserve(struct pmap *, vaddr_t, int); +void pmap_pte_process(struct pmap *, vaddr_t, vaddr_t, pte_callback_t, + uintptr_t); +void pmap_segtab_activate(struct lwp *); +void pmap_segtab_alloc(struct pmap *); +void pmap_segtab_free(struct pmap *); + /* * Machine dependent pmap structure. */ @@ -183,8 +194,10 @@ */ vaddr_t mips_pmap_map_poolpage(paddr_t); paddr_t mips_pmap_unmap_poolpage(vaddr_t); -#define PMAP_MAP_POOLPAGE(pa) mips_pmap_map_poolpage(pa) -#define PMAP_UNMAP_POOLPAGE(va) mips_pmap_unmap_poolpage(va) +struct vm_page *mips_pmap_alloc_poolpage(int); +#define PMAP_ALLOC_POOLPAGE(flags) mips_pmap_alloc_poolpage(flags) +#define PMAP_MAP_POOLPAGE(pa) mips_pmap_map_poolpage(pa) +#define PMAP_UNMAP_POOLPAGE(va) mips_pmap_unmap_poolpage(va) /* * Other hooks for the pool allocator. Index: src/sys/arch/mips/include/proc.h diff -u src/sys/arch/mips/include/proc.h:1.21.36.3 src/sys/arch/mips/include/proc.h:1.21.36.4 --- src/sys/arch/mips/include/proc.h:1.21.36.3 Sat Sep 5 03:16:23 2009 +++ src/sys/arch/mips/include/proc.h Wed Dec 30 04:51:26 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: proc.h,v 1.21.36.3 2009/09/05 03:16:23 matt Exp $ */ +/* $NetBSD: proc.h,v 1.21.36.4 2009/12/30 04:51:26 matt Exp $ */ /* * Copyright (c) 1992, 1993 @@ -76,6 +76,8 @@ #ifdef _KERNEL /* kernel single-step emulation */ int mips_singlestep(struct lwp *l); + +#define LWP0_CPU_INFO &cpu_info_store /* staticly set in lwp0 */ #endif /* _KERNEL */ #endif /* _MIPS_PROC_H_ */ Index: src/sys/arch/mips/include/pte.h diff -u src/sys/arch/mips/include/pte.h:1.19 src/sys/arch/mips/include/pte.h:1.19.18.1 --- src/sys/arch/mips/include/pte.h:1.19 Mon Apr 28 20:23:28 2008 +++ src/sys/arch/mips/include/pte.h Wed Dec 30 04:51:26 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: pte.h,v 1.19 2008/04/28 20:23:28 martin Exp $ */ +/* $NetBSD: pte.h,v 1.19.18.1 2009/12/30 04:51:26 matt Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -67,7 +67,7 @@ #define mips_pg_nv_bit() (MIPS1_PG_NV) /* same on mips1 and mips3 */ -int pmap_is_page_ro(pmap_t, vaddr_t, int); +int pmap_is_page_ro(struct pmap *pmap, vaddr_t, int); /* MIPS1-only */ Index: src/sys/arch/mips/include/vmparam.h diff -u src/sys/arch/mips/include/vmparam.h:1.41.28.7 src/sys/arch/mips/include/vmparam.h:1.41.28.8 --- src/sys/arch/mips/include/vmparam.h:1.41.28.7 Fri Dec 11 20:22:15 2009 +++ src/sys/arch/mips/include/vmparam.h Wed Dec 30 04:51:26 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: vmparam.h,v 1.41.28.7 2009/12/11 20:22:15 matt Exp $ */ +/* $NetBSD: vmparam.h,v 1.41.28.8 2009/12/30 04:51:26 matt Exp $ */ /* * Copyright (c) 1992, 1993 @@ -222,10 +222,7 @@ #ifndef VM_NFREELIST #define VM_NFREELIST 16 /* 16 distinct memory segments */ #define VM_FREELIST_DEFAULT 0 -#define VM_FREELIST_FIRST16M 1 /* ISA DMA range */ -#define VM_FREELIST_FIRST512M 2 /* KSEG0/1 */ -#define VM_FREELIST_FIRST4G 3 /* 32bit addrs */ -#define VM_FREELIST_MAX 4 +#define VM_FREELIST_MAX 1 #endif #endif /* ! _MIPS_VMPARAM_H_ */ Index: src/sys/arch/mips/mips/locore.S diff -u src/sys/arch/mips/mips/locore.S:1.167.38.3 src/sys/arch/mips/mips/locore.S:1.167.38.4 --- src/sys/arch/mips/mips/locore.S:1.167.38.3 Fri Sep 11 23:51:25 2009 +++ src/sys/arch/mips/mips/locore.S Wed Dec 30 04:51:26 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: locore.S,v 1.167.38.3 2009/09/11 23:51:25 matt Exp $ */ +/* $NetBSD: locore.S,v 1.167.38.4 2009/12/30 04:51:26 matt Exp $ */ /* * Copyright (c) 1992, 1993 @@ -138,10 +138,7 @@ #endif INT_S t0, _C_LABEL(cpu_id) # save PRID register INT_S t1, _C_LABEL(fpu_id) # save FPU ID register - PTR_LA MIPS_CURLWP, _C_LABEL(lwp0) # set curlwp, curcpu - PTR_LA t0, _C_LABEL(cpu_info_store) - PTR_S MIPS_CURLWP, CPU_INFO_CURLWP(t0) - PTR_S t0, L_CPU(MIPS_CURLWP) + PTR_LA MIPS_CURLWP, _C_LABEL(lwp0) # set curlwp jal _C_LABEL(mach_init) # mach_init(a0, a1, a2, a3) nop Index: src/sys/arch/mips/mips/mips_machdep.c diff -u src/sys/arch/mips/mips/mips_machdep.c:1.205.4.1.2.1.2.17 src/sys/arch/mips/mips/mips_machdep.c:1.205.4.1.2.1.2.18 --- src/sys/arch/mips/mips/mips_machdep.c:1.205.4.1.2.1.2.17 Fri Nov 13 05:25:49 2009 +++ src/sys/arch/mips/mips/mips_machdep.c Wed Dec 30 04:51:26 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: mips_machdep.c,v 1.205.4.1.2.1.2.17 2009/11/13 05:25:49 cliff Exp $ */ +/* $NetBSD: mips_machdep.c,v 1.205.4.1.2.1.2.18 2009/12/30 04:51:26 matt Exp $ */ /* * Copyright 2002 Wasabi Systems, Inc. @@ -112,7 +112,7 @@ #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ -__KERNEL_RCSID(0, "$NetBSD: mips_machdep.c,v 1.205.4.1.2.1.2.17 2009/11/13 05:25:49 cliff Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mips_machdep.c,v 1.205.4.1.2.1.2.18 2009/12/30 04:51:26 matt Exp $"); #include "opt_cputype.h" #include "opt_compat_netbsd32.h" @@ -226,6 +226,11 @@ uint32_t mips3_tlb_pg_mask; #endif +struct cpu_info cpu_info_store = { + .ci_curlwp = &lwp0, + .ci_fpcurlwp = &lwp0, +}; + struct user *proc0paddr; struct segtab *segbase = (void *)(MIPS_KSEG2_START + 0x1eadbeef); @@ -832,6 +837,7 @@ { const struct pridtab *ct; +#if 0 /* * XXX Set-up curlwp/curcpu again. They may have been clobbered * beween verylocore and here. @@ -839,7 +845,10 @@ lwp0.l_cpu = &cpu_info_store; cpu_info_store.ci_curlwp = &lwp0; cpu_info_store.ci_fpcurlwp = &lwp0; - curlwp = &lwp0; +#endif +#if 0 + curlwp = &lwp0; /* handled in locore.S */ +#endif mycpu = NULL; for (ct = cputab; ct->cpu_name != NULL; ct++) { @@ -1623,6 +1632,173 @@ } void +mips_init_lwp0_uarea(void) +{ + vaddr_t v = uvm_pageboot_alloc(USPACE); + lwp0.l_addr = proc0paddr = (struct user *)v; + lwp0.l_md.md_regs = (struct frame *)(v + USPACE) - 1; +#ifdef _LP64 + lwp0.l_md.md_regs->f_regs[_R_SR] = MIPS_SR_KX; +#endif + lwp0.l_addr->u_pcb.pcb_context.val[_L_SR] = +#ifdef _LP64 + MIPS_SR_KX | +#endif + MIPS_INT_MASK | MIPS_SR_INT_IE; /* SR */ +} + +int mips_poolpage_vmfreelist = VM_FREELIST_DEFAULT; + +#define HALFGIG ((paddr_t)512 * 1024 * 1024) +#define FOURGIG ((paddr_t)4 * 1024 * 1024 * 1024) + +void +mips_page_physload(vaddr_t vkernstart, vaddr_t vkernend, + const phys_ram_seg_t *segs, size_t nseg, + const struct mips_vmfreelist *flp, size_t nfl) +{ + const paddr_t kernstart = MIPS_KSEG0_TO_PHYS(vkernstart); + const paddr_t kernend = MIPS_KSEG0_TO_PHYS(vkernend); +#if defined(VM_FREELIST_FIRST4G) || defined(VM_FREELIST_FIRST512M) +#ifdef VM_FREELIST_FIRST512M + bool need512m = false; +#endif +#ifdef VM_FREELIST_FIRST4G + bool need4g = false; +#endif + + /* + * Do a first pass and see what ranges memory we have to deal with. + */ + for (size_t i = 0; i < nseg; i++) { +#ifdef VM_FREELIST_FIRST4G + if (segs[i].last > FOURGIG) + need4g = true; +#endif +#ifdef VM_FREELIST_FIRST512M + if (segs[i].last > HALFGIG) { + need512m = true; + mips_poolpage_vmfreelist = VM_FREELIST_FIRST512M; + } +#endif + } +#endif /* VM_FREELIST_FIRST512M || VM_FREELIST_FIRST4G */ + + while (nseg-- > 0) { + /* + * Copy this segment since we may have to deal with it + * piecemeal. + */ + phys_ram_seg_t tmp = *segs++; + printf("phys segment: %#"PRIxPADDR"@%#"PRIxPADDR"\n", tmp.size, tmp.start); + while (tmp.size > 0) { + int freelist = -1; /* unknown freelist */ + psize_t segsize = tmp.size; + for (size_t i = 0; i < nfl; i++) { + /* + * If this segment doesn't overlap the freelist + * at all, skip it. + */ + if (tmp.start >= flp[i].fl_end + || tmp.start + tmp.size <= flp[i].fl_start) + continue; + /* + * If the start of this segment starts before + * the start of the freelist, then limit the + * segment to loaded to the part that doesn't + * match this freelist and fall back to normal + * freelist matching. + */ + if (tmp.start < flp[i].fl_start) { + segsize = flp[i].fl_start - tmp.start; + break; + } + + /* + * We've matched this freelist so remember it. + */ + freelist = flp->fl_freelist; + + /* + * If this segment extends past the end of this + * freelist, bound to segment to the freelist. + */ + if (tmp.start + tmp.size > flp[i].fl_end) + segsize = flp[i].fl_end - tmp.start; + break; + } + /* + * If we didn't match one of the port dependent + * freelists, let's try the common ones. + */ + if (freelist == -1) { +#ifdef VM_FREELIST_FIRST512M + if (need512m && tmp.start < HALFGIG) { + freelist = VM_FREELIST_FIRST512M; + if (tmp.start + tmp.size > HALFGIG) + segsize = HALFGIG - tmp.start; + } else +#endif +#ifdef VM_FREELIST_FIRST4G + if (need4g && tmp.start < FOURGIG) { + freelist = VM_FREELIST_FIRST4G; + if (tmp.start + tmp.size > FOURGIG) + segsize = FOURGIG - tmp.start; + } else +#endif + freelist = VM_FREELIST_DEFAULT; + } + + /* + * Make sure the memory we provide to uvm doesn't + * include the kernel. + */ + if (tmp.start < kernend + && tmp.start + segsize > kernstart) { + if (tmp.start < kernstart) { + /* + * Only add the memory before the + * kernel. + */ + segsize -= kernstart - tmp.start; + } else if (tmp.start + segsize > kernend) { + /* + * Only add the memory after the + * kernel. + */ + segsize -= (kernend - tmp.start); + tmp.size -= (kernend - tmp.start); + tmp.start = kernend; + } else { + /* + * Just skip the segment entirely since + * it's inside the kernel. + */ + tmp.start += segsize; + tmp.size -= segsize; + continue; + } + } + + /* + * Now we give this segment to uvm. + */ + paddr_t first = atop(tmp.start); + paddr_t last = first + atop(segsize); + printf("adding %#"PRIxPADDR"@%#"PRIxPADDR" to freelist %d\n", + tmp.start, tmp.start + segsize, freelist); + uvm_page_physload(first, last, first, last, freelist); + + /* + * Remove from tmp the segment we just loaded. + */ + tmp.start += segsize; + tmp.size -= segsize; + } + } +} + +void savefpregs(struct lwp *l) { #ifndef NOFPU Index: src/sys/arch/mips/mips/pmap.c diff -u src/sys/arch/mips/mips/pmap.c:1.179.16.6 src/sys/arch/mips/mips/pmap.c:1.179.16.7 --- src/sys/arch/mips/mips/pmap.c:1.179.16.6 Sat Dec 19 06:58:30 2009 +++ src/sys/arch/mips/mips/pmap.c Wed Dec 30 04:51:26 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.c,v 1.179.16.6 2009/12/19 06:58:30 matt Exp $ */ +/* $NetBSD: pmap.c,v 1.179.16.7 2009/12/30 04:51:26 matt Exp $ */ /*- * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. @@ -67,7 +67,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.179.16.6 2009/12/19 06:58:30 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.179.16.7 2009/12/30 04:51:26 matt Exp $"); /* * Manages physical address maps. @@ -150,7 +150,6 @@ CTASSERT(MIPS_KSEG0_P(MIPS_PHYS_TO_KSEG0(0))); CTASSERT(MIPS_KSEG1_P(MIPS_PHYS_TO_KSEG1(0))); -CTASSERT(NBPG >= sizeof(struct segtab)); #ifdef DEBUG struct { int kernel; /* entering kernel mapping */ @@ -203,13 +202,12 @@ struct pv_entry *pv_table; int pv_table_npages; -struct segtab *free_segtab; /* free list kept locally */ pt_entry_t *Sysmap; /* kernel pte table */ unsigned int Sysmapsize; /* number of pte's in Sysmap */ -unsigned pmap_max_asid; /* max ASID supported by the system */ -unsigned pmap_next_asid; /* next free ASID to use */ -unsigned pmap_asid_generation; /* current ASID generation */ +unsigned int pmap_asid_max; /* max ASID supported by the system */ +unsigned int pmap_asid_next; /* next free ASID to use */ +unsigned int pmap_asid_generation; /* current ASID generation */ #define PMAP_ASID_RESERVED 0 /* @@ -379,8 +377,8 @@ pmap_kernel()->pm_asidgen = 0; pmap_kernel()->pm_segtab = (void *)(MIPS_KSEG2_START + 0x1eadbeef); - pmap_max_asid = MIPS_TLB_NUM_PIDS; - pmap_next_asid = 1; + pmap_asid_max = MIPS_TLB_NUM_PIDS; + pmap_asid_next = 1; pmap_asid_generation = 0; MachSetPID(0); @@ -584,7 +582,6 @@ pmap_create(void) { pmap_t pmap; - int i; #ifdef DEBUG if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) @@ -595,50 +592,11 @@ memset(pmap, 0, sizeof(*pmap)); pmap->pm_count = 1; - if (free_segtab) { - pmap->pm_segtab = free_segtab; - free_segtab = *(struct segtab **)free_segtab; - pmap->pm_segtab->seg_tab[0] = NULL; - } else { - struct segtab *stp; - struct vm_page *stp_pg; - paddr_t stp_pa; - - for (;;) { - stp_pg = uvm_pagealloc(NULL, 0, NULL, - UVM_PGA_USERESERVE|UVM_PGA_ZERO); - if (stp_pg != NULL) - break; - /* - * XXX What else can we do? Could we - * XXX deadlock here? - */ - uvm_wait("pmap_create"); - } - - stp_pa = VM_PAGE_TO_PHYS(stp_pg); -#ifdef _LP64 - KASSERT(mips3_xkphys_cached); - stp = (struct segtab *)MIPS_PHYS_TO_XKPHYS_CACHED(stp_pa); -#else - stp = (struct segtab *)MIPS_PHYS_TO_KSEG0(stp_pa); -#endif - pmap->pm_segtab = stp; - i = NBPG / sizeof(struct segtab); - while (--i != 0) { - stp++; - *(struct segtab **)stp = free_segtab; - free_segtab = stp; - } - } -#ifdef PARANOIADIAG - for (i = 0; i < PMAP_SEGTABSIZE; i++) - if (pmap->pm_segtab->seg_tab[i] != 0) - panic("pmap_create: pm_segtab != 0"); -#endif pmap->pm_asid = PMAP_ASID_RESERVED; pmap->pm_asidgen = pmap_asid_generation; + pmap_segtab_alloc(pmap); + return pmap; } @@ -660,52 +618,7 @@ if (count > 0) return; - if (pmap->pm_segtab) { - pt_entry_t *pte; - int i; -#ifdef PARANOIADIAG - int j; -#endif - - for (i = 0; i < PMAP_SEGTABSIZE; i++) { - paddr_t pa; - /* get pointer to segment map */ - pte = pmap->pm_segtab->seg_tab[i]; - if (!pte) - continue; -#ifdef PARANOIADIAG - for (j = 0; j < NPTEPG; j++) { - if ((pte + j)->pt_entry) - panic("pmap_destroy: segmap not empty"); - } -#endif - -#ifdef MIPS3_PLUS /* XXX mmu XXX */ - /* - * The pica pmap.c flushed the segmap pages here. I'm - * not sure why, but I suspect it's because the page(s) - * were being accessed by KSEG0 (cached) addresses and - * may cause cache coherency problems when the page - * is reused with KSEG2 (mapped) addresses. This may - * cause problems on machines without VCED/VCEI. - */ - if (mips_cache_virtual_alias) - mips_dcache_inv_range((vaddr_t)pte, PAGE_SIZE); -#endif /* MIPS3_PLUS */ -#ifdef _LP64 - KASSERT(MIPS_XKPHYS_P(pte)); - pa = MIPS_XKPHYS_TO_PHYS(pte); -#else - pa = MIPS_KSEG0_TO_PHYS(pte); -#endif - uvm_pagefree(PHYS_TO_VM_PAGE(pa)); - - pmap->pm_segtab->seg_tab[i] = NULL; - } - *(struct segtab **)pmap->pm_segtab = free_segtab; - free_segtab = pmap->pm_segtab; - pmap->pm_segtab = NULL; - } + pmap_segtab_free(pmap); pool_put(&pmap_pmap_pool, pmap); } @@ -736,7 +649,7 @@ pmap_asid_alloc(pmap); if (l == curlwp) { - segbase = pmap->pm_segtab; + pmap_segtab_activate(l); MachSetPID(pmap->pm_asid); } } @@ -757,14 +670,50 @@ * It is assumed that the start and end are properly * rounded to the page size. */ + +static bool +pmap_pte_remove(pmap_t pmap, vaddr_t sva, vaddr_t eva, pt_entry_t *pte, + uintptr_t flags) +{ + const uint32_t asid = pmap->pm_asid << MIPS_TLB_PID_SHIFT; + const bool needflush = (pmap->pm_asidgen == pmap_asid_generation); + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) { + printf("%s: %p, %"PRIxVADDR", %"PRIxVADDR", %p, %"PRIxPTR"\n", + __func__, pmap, sva, eva, pte, flags); + } +#endif + + for (; sva < eva; sva += NBPG, pte++) { + struct vm_page *pg; + uint32_t entry = pte->pt_entry; + if (!mips_pg_v(entry)) + continue; + if (mips_pg_wired(entry)) + pmap->pm_stats.wired_count--; + pmap->pm_stats.resident_count--; + pg = PHYS_TO_VM_PAGE(mips_tlbpfn_to_paddr(entry)); + if (pg) + pmap_remove_pv(pmap, sva, pg); + pte->pt_entry = mips_pg_nv_bit(); + /* + * Flush the TLB for the given address. + */ + if (needflush) { + MIPS_TBIS(sva | asid); +#ifdef DEBUG + remove_stats.flushes++; +#endif + } + } + return false; +} + void pmap_remove(pmap_t pmap, vaddr_t sva, vaddr_t eva) { struct vm_page *pg; - vaddr_t nssva; - pt_entry_t *pte; - unsigned entry; - unsigned asid, needflush; #ifdef DEBUG if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) @@ -777,9 +726,9 @@ if (sva < VM_MIN_KERNEL_ADDRESS || eva >= virtual_end) panic("pmap_remove: kva not in range"); #endif - pte = kvtopte(sva); + pt_entry_t *pte = kvtopte(sva); for (; sva < eva; sva += NBPG, pte++) { - entry = pte->pt_entry; + uint32_t entry = pte->pt_entry; if (!mips_pg_v(entry)) continue; if (mips_pg_wired(entry)) @@ -800,7 +749,6 @@ MIPS_TBIS(sva); #ifdef DEBUG remove_stats.flushes++; - #endif } return; @@ -820,46 +768,7 @@ } } #endif - asid = pmap->pm_asid << MIPS_TLB_PID_SHIFT; - needflush = (pmap->pm_asidgen == pmap_asid_generation); - while (sva < eva) { - nssva = mips_trunc_seg(sva) + NBSEG; - if (nssva == 0 || nssva > eva) - nssva = eva; - /* - * If VA belongs to an unallocated segment, - * skip to the next segment boundary. - */ - if (!(pte = pmap_segmap(pmap, sva))) { - sva = nssva; - continue; - } - /* - * Invalidate every valid mapping within this segment. - */ - pte += (sva >> PGSHIFT) & (NPTEPG - 1); - for (; sva < nssva; sva += NBPG, pte++) { - entry = pte->pt_entry; - if (!mips_pg_v(entry)) - continue; - if (mips_pg_wired(entry)) - pmap->pm_stats.wired_count--; - pmap->pm_stats.resident_count--; - pg = PHYS_TO_VM_PAGE(mips_tlbpfn_to_paddr(entry)); - if (pg) - pmap_remove_pv(pmap, sva, pg); - pte->pt_entry = mips_pg_nv_bit(); - /* - * Flush the TLB for the given address. - */ - if (needflush) { - MIPS_TBIS(sva | asid); -#ifdef DEBUG - remove_stats.flushes++; -#endif - } - } - } + pmap_pte_process(pmap, sva, eva, pmap_pte_remove, 0); } /* @@ -912,6 +821,34 @@ } } +static bool +pmap_pte_protect(pmap_t pmap, vaddr_t sva, vaddr_t eva, pt_entry_t *pte, + uintptr_t flags) +{ + const uint32_t asid = pmap->pm_asid << MIPS_TLB_PID_SHIFT; + const bool needupdate = (pmap->pm_asidgen == pmap_asid_generation); + const uint32_t p = flags; + + /* + * Change protection on every valid mapping within this segment. + */ + for (; sva < eva; sva += NBPG, pte++) { + uint32_t entry = pte->pt_entry; + if (!mips_pg_v(entry)) + continue; + if (MIPS_HAS_R4K_MMU && entry & mips_pg_m_bit()) + mips_dcache_wbinv_range_index(sva, PAGE_SIZE); + entry = (entry & ~(mips_pg_m_bit() | mips_pg_ro_bit())) | p; + pte->pt_entry = entry; + /* + * Update the TLB if the given address is in the cache. + */ + if (needupdate) + MachTLBUpdate(sva | asid, entry); + } + return false; +} + /* * Set the physical protection on the * specified range of this map as requested. @@ -919,11 +856,8 @@ void pmap_protect(pmap_t pmap, vaddr_t sva, vaddr_t eva, vm_prot_t prot) { - vaddr_t nssva; pt_entry_t *pte; - unsigned entry; u_int p; - unsigned asid, needupdate; #ifdef DEBUG if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) @@ -952,7 +886,7 @@ #endif pte = kvtopte(sva); for (; sva < eva; sva += NBPG, pte++) { - entry = pte->pt_entry; + uint32_t entry = pte->pt_entry; if (!mips_pg_v(entry)) continue; if (MIPS_HAS_R4K_MMU && entry & mips_pg_m_bit()) @@ -979,40 +913,11 @@ } } #endif - asid = pmap->pm_asid << MIPS_TLB_PID_SHIFT; - needupdate = (pmap->pm_asidgen == pmap_asid_generation); - while (sva < eva) { - nssva = mips_trunc_seg(sva) + NBSEG; - if (nssva == 0 || nssva > eva) - nssva = eva; - /* - * If VA belongs to an unallocated segment, - * skip to the next segment boundary. - */ - if (!(pte = pmap_segmap(pmap, sva))) { - sva = nssva; - continue; - } - /* - * Change protection on every valid mapping within this segment. - */ - pte += (sva >> PGSHIFT) & (NPTEPG - 1); - for (; sva < nssva; sva += NBPG, pte++) { - entry = pte->pt_entry; - if (!mips_pg_v(entry)) - continue; - if (MIPS_HAS_R4K_MMU && entry & mips_pg_m_bit()) - mips_dcache_wbinv_range_index(sva, PAGE_SIZE); - entry = (entry & ~(mips_pg_m_bit() | - mips_pg_ro_bit())) | p; - pte->pt_entry = entry; - /* - * Update the TLB if the given address is in the cache. - */ - if (needupdate) - MachTLBUpdate(sva | asid, entry); - } - } + + /* + * Change protection on every valid mapping within this segment. + */ + pmap_pte_process(pmap, sva, eva, pmap_pte_protect, p); } /* @@ -1048,10 +953,7 @@ if (pmap == pmap_kernel()) { pte = kvtopte(va); } else { - if (!(pte = pmap_segmap(pmap, va))) { - return; - } - pte += (va >> PGSHIFT) & (NPTEPG - 1); + pte = pmap_pte_lookup(pmap, va); } entry = pte->pt_entry; if (!mips_pg_v(entry)) @@ -1118,10 +1020,9 @@ } } else { - pte = pmap_segmap(pv->pv_pmap, pv->pv_va); + pte = pmap_pte_lookup(pv->pv_pmap, pv->pv_va); if (pte == NULL) continue; - pte += (pv->pv_va >> PGSHIFT) & (NPTEPG - 1); entry = pte->pt_entry; if (entry & MIPS3_PG_V) { entry = (entry & ~MIPS3_PG_CACHEMODE) | newmode; @@ -1152,7 +1053,7 @@ { pt_entry_t *pte; u_int npte; - struct vm_page *pg, *mem; + struct vm_page *pg; unsigned asid; #if defined(_MIPS_PADDR_T_64BIT) || defined(_LP64) int cached = 1; @@ -1308,41 +1209,15 @@ return 0; } - if (!(pte = pmap_segmap(pmap, va))) { - paddr_t phys; - mem = uvm_pagealloc(NULL, 0, NULL, - UVM_PGA_USERESERVE|UVM_PGA_ZERO); - if (mem == NULL) { - if (flags & PMAP_CANFAIL) - return ENOMEM; - panic("pmap_enter: cannot allocate segmap"); - } - - phys = VM_PAGE_TO_PHYS(mem); -#ifdef _LP64 - KASSERT(mips3_xkphys_cached); - pte = (pt_entry_t *)MIPS_PHYS_TO_XKPHYS_CACHED(phys); -#else - pte = (pt_entry_t *)MIPS_PHYS_TO_KSEG0(phys); -#endif - pmap_segmap(pmap, va) = pte; -#ifdef PARANOIADIAG - { - int i; - for (i = 0; i < NPTEPG; i++) { - if ((pte+i)->pt_entry) - panic("pmap_enter: new segmap not empty"); - } - } -#endif + pte = pmap_pte_reserve(pmap, va, flags); + if (__predict_false(pte == NULL)) { + return ENOMEM; } /* Done after case that may sleep/return. */ if (pg) pmap_enter_pv(pmap, va, pg, &npte); - pte += (va >> PGSHIFT) & (NPTEPG - 1); - /* * Now validate mapping with desired protection/wiring. * Assume uniform modified and referenced status for all @@ -1514,13 +1389,12 @@ #endif pte = kvtopte(va); } else { - pte = pmap_segmap(pmap, va); + pte = pmap_pte_lookup(pmap, va); #ifdef DIAGNOSTIC if (pte == NULL) panic("pmap_unwire: pmap %p va %#"PRIxVADDR" invalid STE", pmap, va); #endif - pte += (va >> PGSHIFT) & (NPTEPG - 1); } #ifdef DIAGNOSTIC @@ -1575,14 +1449,13 @@ else pte = kvtopte(va); } else { - if (!(pte = pmap_segmap(pmap, va))) { + if (!(pte = pmap_pte_lookup(pmap, va))) { #ifdef DEBUG if (pmapdebug & PDB_FOLLOW) printf("not in segmap\n"); #endif return false; } - pte += (va >> PGSHIFT) & (NPTEPG - 1); } if (!mips_pg_v(pte->pt_entry)) { #ifdef DEBUG @@ -1844,9 +1717,8 @@ pte = kvtopte(va); asid = 0; } else { - pte = pmap_segmap(pmap, va); + pte = pmap_pte_lookup(pmap, va); KASSERT(pte); - pte += ((va >> PGSHIFT) & (NPTEPG - 1)); asid = pmap->pm_asid << MIPS_TLB_PID_SHIFT; } if ((pte->pt_entry & mips_pg_m_bit()) == 0) { @@ -1910,12 +1782,12 @@ if (pmap->pm_asid == PMAP_ASID_RESERVED || pmap->pm_asidgen != pmap_asid_generation) { - if (pmap_next_asid == pmap_max_asid) { + if (pmap_asid_next == pmap_asid_max) { MIPS_TBIAP(); pmap_asid_generation++; /* ok to wrap to 0 */ - pmap_next_asid = 1; /* 0 means invalid */ + pmap_asid_next = 1; /* 0 means invalid */ } - pmap->pm_asid = pmap_next_asid++; + pmap->pm_asid = pmap_asid_next++; pmap->pm_asidgen = pmap_asid_generation; } @@ -2044,10 +1916,8 @@ if (pmap == pmap_kernel()) entry = kvtopte(va)->pt_entry; else { - pte = pmap_segmap(pmap, va); + pte = pmap_pte_lookup(pmap, va); if (pte) { - pte += (va >> PGSHIFT) & - (NPTEPG - 1); entry = pte->pt_entry; } else entry = 0; @@ -2120,7 +1990,6 @@ * Copy current modified and referenced status to * the following entry before copying. */ - npv->pv_flags |= pv->pv_flags & (PV_MODIFIED | PV_REFERENCED); *pv = *npv; @@ -2176,28 +2045,20 @@ void * pmap_pv_page_alloc(struct pool *pp, int flags) { - struct vm_page *pg; - paddr_t phys; -#if defined(MIPS3_PLUS) - pv_entry_t pv; -#endif - vaddr_t va; - - pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_USERESERVE); + const struct vm_page *pg = PMAP_ALLOC_POOLPAGE(UVM_PGA_USERESERVE); if (pg == NULL) return NULL; - phys = VM_PAGE_TO_PHYS(pg); + const paddr_t pa = VM_PAGE_TO_PHYS(pg); #ifdef _LP64 KASSERT(mips3_xkphys_cached); - va = MIPS_PHYS_TO_XKPHYS_CACHED(phys); + const vaddr_t va = MIPS_PHYS_TO_XKPHYS_CACHED(pa); #else - va = MIPS_PHYS_TO_KSEG0(phys); + const vaddr_t va = MIPS_PHYS_TO_KSEG0(pa); #endif #if defined(MIPS3_PLUS) if (mips_cache_virtual_alias) { - pg = PHYS_TO_VM_PAGE(phys); - pv = pg->mdpage.pvh_list; + pv_entry_t pv = pg->mdpage.pvh_list; if ((pv->pv_flags & PV_UNCACHED) == 0 && mips_cache_indexof(pv->pv_va) != mips_cache_indexof(va)) mips_dcache_wbinv_range_index(pv->pv_va, PAGE_SIZE); @@ -2232,12 +2093,12 @@ pt_entry_t * pmap_pte(pmap_t pmap, vaddr_t va) { - pt_entry_t *pte = NULL; + pt_entry_t *pte; if (pmap == pmap_kernel()) pte = kvtopte(va); - else if ((pte = pmap_segmap(pmap, va)) != NULL) - pte += (va >> PGSHIFT) & (NPTEPG - 1); + else + pte = pmap_pte_lookup(pmap, va); return pte; } @@ -2264,6 +2125,22 @@ } #endif /* MIPS3_PLUS */ +struct vm_page * +mips_pmap_alloc_poolpage(int flags) +{ +#ifndef _LP64 + /* + * On 32bit kernels, we must make sure that we only allocate pages that + * can be mapped via KSEG0. If all memory is in KSEG0, then we can just + * use the default freelist otherwise we must use the pool page list. + */ + if (mips_poolpage_vmfreelist != VM_FREELIST_DEFAULT) + return uvm_pagealloc_strat(NULL, 0, NULL, flags, + UVM_PGA_STRAT_ONLY, mips_poolpage_vmfreelist); +#endif + return uvm_pagealloc(NULL, 0, NULL, flags); +} + vaddr_t mips_pmap_map_poolpage(paddr_t pa) { @@ -2277,11 +2154,11 @@ KASSERT(mips3_xkphys_cached); va = MIPS_PHYS_TO_XKPHYS_CACHED(pa); #else - if (pa <= MIPS_PHYS_MASK) - va = MIPS_PHYS_TO_KSEG0(pa); - else + if (pa > MIPS_PHYS_MASK) panic("mips_pmap_map_poolpage: " "pa #%"PRIxPADDR" can not be mapped into KSEG0", pa); + + va = MIPS_PHYS_TO_KSEG0(pa); #endif #if defined(MIPS3_PLUS) if (mips_cache_virtual_alias) { Index: src/sys/arch/mips/mips/trap.c diff -u src/sys/arch/mips/mips/trap.c:1.217.12.11 src/sys/arch/mips/mips/trap.c:1.217.12.12 --- src/sys/arch/mips/mips/trap.c:1.217.12.11 Sat Nov 14 21:52:08 2009 +++ src/sys/arch/mips/mips/trap.c Wed Dec 30 04:51:26 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: trap.c,v 1.217.12.11 2009/11/14 21:52:08 matt Exp $ */ +/* $NetBSD: trap.c,v 1.217.12.12 2009/12/30 04:51:26 matt Exp $ */ /* * Copyright (c) 1992, 1993 @@ -78,7 +78,7 @@ #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ -__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.217.12.11 2009/11/14 21:52:08 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.217.12.12 2009/12/30 04:51:26 matt Exp $"); #include "opt_cputype.h" /* which mips CPU levels do we support? */ #include "opt_ddb.h" @@ -308,9 +308,8 @@ pmap_t pmap; pmap = p->p_vmspace->vm_map.pmap; - if (!(pte = pmap_segmap(pmap, vaddr))) + if (!(pte = pmap_pte_lookup(pmap, vaddr))) panic("utlbmod: invalid segmap"); - pte += (vaddr >> PGSHIFT) & (NPTEPG - 1); entry = pte->pt_entry; if (!mips_pg_v(entry) || (entry & mips_pg_m_bit())) panic("utlbmod: invalid pte"); @@ -381,7 +380,7 @@ #ifdef VMFAULT_TRACE printf( "uvm_fault(%p (pmap %p), %#"PRIxVADDR - " (0x%x), %d) -> %d at pc %#"PRIxVADDR"\n", + " (%"PRIxVADDR"), %d) -> %d at pc %#"PRIxVADDR"\n", map, vm->vm_map.pmap, va, vaddr, ftype, rv, opc); #endif /* Added files: Index: src/sys/arch/mips/mips/pmap_segtab.c diff -u /dev/null src/sys/arch/mips/mips/pmap_segtab.c:1.1.2.1 --- /dev/null Wed Dec 30 04:51:27 2009 +++ src/sys/arch/mips/mips/pmap_segtab.c Wed Dec 30 04:51:26 2009 @@ -0,0 +1,395 @@ +/* $NetBSD: pmap_segtab.c,v 1.1.2.1 2009/12/30 04:51:26 matt Exp $ */ + +/*- + * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center and by Chris G. Demetriou. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department and Ralph Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)pmap.c 8.4 (Berkeley) 1/26/94 + */ + +#include <sys/cdefs.h> + +__KERNEL_RCSID(0, "$NetBSD: pmap_segtab.c,v 1.1.2.1 2009/12/30 04:51:26 matt Exp $"); + +/* + * Manages physical address maps. + * + * In addition to hardware address maps, this + * module is called upon to provide software-use-only + * maps which may or may not be stored in the same + * form as hardware maps. These pseudo-maps are + * used to store intermediate results from copy + * operations to and from address spaces. + * + * Since the information managed by this module is + * also stored by the logical address mapping module, + * this module may throw away valid virtual-to-physical + * mappings at almost any time. However, invalidations + * of virtual-to-physical mappings must be done as + * requested. + * + * In order to cope with hardware architectures which + * make virtual-to-physical map invalidates expensive, + * this module may delay invalidate or reduced protection + * operations until such time as they are actually + * necessary. This module is given full information as + * to which processors are currently using which maps, + * and to when physical maps must be made correct. + */ + +/* XXX simonb 2002/02/26 + * + * MIPS3_PLUS is used to conditionally compile the r4k MMU support. + * This is bogus - for example, some IDT MIPS-II CPUs have r4k style + * MMUs (and 32-bit ones at that). + * + * On the other hand, it's not likely that we'll ever support the R6000 + * (is it?), so maybe that can be an "if MIPS2 or greater" check. + * + * Also along these lines are using totally separate functions for + * r3k-style and r4k-style MMUs and removing all the MIPS_HAS_R4K_MMU + * checks in the current functions. + * + * These warnings probably applies to other files under sys/arch/mips. + */ + +#include "opt_sysv.h" +#include "opt_cputype.h" +#include "opt_mips_cache.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/buf.h> +#include <sys/pool.h> +#include <sys/mutex.h> +#include <sys/atomic.h> +#ifdef SYSVSHM +#include <sys/shm.h> +#endif +#include <sys/socketvar.h> /* XXX: for sock_loan_thresh */ + +#include <uvm/uvm.h> + +#include <mips/cache.h> +#include <mips/cpuregs.h> +#include <mips/locore.h> +#include <mips/pte.h> + +CTASSERT(NBPG >= sizeof(struct segtab)); + +struct segtab *free_segtab; /* free list kept locally */ + +static inline struct vm_page * +pmap_pte_pagealloc(void) +{ + return mips_pmap_alloc_poolpage(UVM_PGA_ZERO|UVM_PGA_USERESERVE); +} + +static inline pt_entry_t * +pmap_segmap(struct pmap *pmap, vaddr_t va) +{ + struct segtab *stp = pmap->pm_segtab; + return stp->seg_tab[va >> SEGSHIFT]; +} + +pt_entry_t * +pmap_pte_lookup(pmap_t pmap, vaddr_t va) +{ + pt_entry_t *pte = pmap_segmap(pmap, va); + if (pte == NULL) + return NULL; + + return pte + ((va >> PGSHIFT) & (NPTEPG - 1)); +} + +/* + * Create and return a physical map. + * + * If the size specified for the map + * is zero, the map is an actual physical + * map, and may be referenced by the + * hardware. + * + * If the size specified is non-zero, + * the map will be used in software only, and + * is bounded by that size. + */ +void +pmap_segtab_alloc(pmap_t pmap) +{ + struct segtab *stp; + + stp = NULL; + while (__predict_true(free_segtab != NULL)) { + struct segtab *next_stp; + stp = free_segtab; + next_stp = (struct segtab *)stp->seg_tab[0]; + if (stp == atomic_cas_ptr(&free_segtab, stp, next_stp)) + break; + } + + if (__predict_true(stp != NULL)) { + stp->seg_tab[0] = NULL; + } else { + paddr_t stp_pa; + + for (;;) { + struct vm_page * const stp_pg = pmap_pte_pagealloc(); + if (stp_pg != NULL) { + stp_pa = VM_PAGE_TO_PHYS(stp_pg); + break; + } + /* + * XXX What else can we do? Could we + * XXX deadlock here? + */ + uvm_wait("pmap_create"); + } + +#ifdef _LP64 + KASSERT(mips3_xkphys_cached); + stp = (struct segtab *)MIPS_PHYS_TO_XKPHYS_CACHED(stp_pa); +#else + stp = (struct segtab *)MIPS_PHYS_TO_KSEG0(stp_pa); +#endif + const size_t n = NBPG / sizeof(struct segtab); + if (n > 1) { + /* + * link all the segtabs in this page together + */ + for (size_t i = 1; i < n - 1; i++) { + stp[i].seg_tab[0] = (void *)&stp[i+1]; + } + /* + * Now link the new segtabs into the free segtab list. + */ + for (;;) { + void *tmp = free_segtab; + stp[n-1].seg_tab[0] = tmp; + if (tmp == atomic_cas_ptr(&free_segtab, tmp, stp+1)) + break; + } + } + } + +#ifdef PARANOIADIAG + for (i = 0; i < PMAP_SEGTABSIZE; i++) { + if (stp->seg_tab[i] != 0) + panic("pmap_create: pm_segtab.seg_tab[%zu] != 0"); + } +#endif + + pmap->pm_segtab = stp; +} + +/* + * Retire the given physical map from service. + * Should only be called if the map contains + * no valid mappings. + */ +void +pmap_segtab_free(pmap_t pmap) +{ + struct segtab *stp = pmap->pm_segtab; + + if (stp == NULL) + return; + + for (size_t i = 0; i < PMAP_SEGTABSIZE; i++) { + paddr_t pa; + /* get pointer to segment map */ + pt_entry_t *pte = stp->seg_tab[i]; + if (pte == NULL) + continue; +#ifdef PARANOIADIAG + for (size_t j = 0; j < NPTEPG; j++) { + if ((pte + j)->pt_entry) + panic("pmap_destroy: segmap not empty"); + } +#endif + +#ifdef MIPS3_PLUS /* XXX mmu XXX */ + /* + * The pica pmap.c flushed the segmap pages here. I'm + * not sure why, but I suspect it's because the page(s) + * were being accessed by KSEG0 (cached) addresses and + * may cause cache coherency problems when the page + * is reused with KSEG2 (mapped) addresses. This may + * cause problems on machines without VCED/VCEI. + */ + if (mips_cache_virtual_alias) + mips_dcache_inv_range((vaddr_t)pte, PAGE_SIZE); +#endif /* MIPS3_PLUS */ +#ifdef _LP64 + KASSERT(MIPS_XKPHYS_P(pte)); + pa = MIPS_XKPHYS_TO_PHYS(pte); +#else + pa = MIPS_KSEG0_TO_PHYS(pte); +#endif + uvm_pagefree(PHYS_TO_VM_PAGE(pa)); + + stp->seg_tab[i] = NULL; + } + + /* + * Insert the the segtab into the segtab freelist. + */ + for (;;) { + void *tmp = free_segtab; + stp->seg_tab[0] = tmp; + if (tmp == atomic_cas_ptr(&free_segtab, tmp, stp)) + break; + } +} + +/* + * Make a new pmap (vmspace) active for the given process. + */ +void +pmap_segtab_activate(struct lwp *l) +{ + if (l == curlwp) { + pmap_t pmap = l->l_proc->p_vmspace->vm_map.pmap; + segbase = pmap->pm_segtab; /* XXX needs to be in curcpu() */ + } +} + +/* + * Act on the given range of addresses from the specified map. + * + * It is assumed that the start and end are properly rounded to + * the page size. + */ +void +pmap_pte_process(pmap_t pmap, vaddr_t sva, vaddr_t eva, + pte_callback_t callback, uintptr_t flags) +{ +#if 0 + printf("%s: %p, %"PRIxVADDR", %"PRIxVADDR", %p, %"PRIxPTR"\n", + __func__, pmap, sva, eva, callback, flags); +#endif + while (sva < eva) { + vaddr_t lastseg_va = mips_trunc_seg(sva) + NBSEG; + KASSERT(lastseg_va != 0); + if (lastseg_va > eva) + lastseg_va = eva; + + /* + * If VA belongs to an unallocated segment, + * skip to the next segment boundary. + */ + pt_entry_t * const pte = pmap_pte_lookup(pmap, sva); + if (pte != NULL) { + /* + * Callback to deal with the ptes for this segment. + */ + (*callback)(pmap, sva, lastseg_va, pte, flags); + } + /* + * In theory we could release pages with no entries, + * but that takes more effort than we want here. + */ + sva = lastseg_va; + } +} + +/* + * Return a pointer for the pte that corresponds to the specified virtual + * address (va) in the target physical map, allocating if needed. + */ +pt_entry_t * +pmap_pte_reserve(pmap_t pmap, vaddr_t va, int flags) +{ + struct segtab *stp = pmap->pm_segtab; + pt_entry_t *pte; + + pte = pmap_pte_lookup(pmap, va); + if (__predict_false(pte == NULL)) { + struct vm_page * const pg = pmap_pte_pagealloc(); + if (pg == NULL) { + if (flags & PMAP_CANFAIL) + return NULL; + panic("%s: cannot allocate page table page " + "for va %" PRIxVADDR, __func__, va); + } + + const paddr_t pa = VM_PAGE_TO_PHYS(pg); +#ifdef _LP64 + KASSERT(mips3_xkphys_cached); + pte = (pt_entry_t *)MIPS_PHYS_TO_XKPHYS_CACHED(pa); +#else + pte = (pt_entry_t *)MIPS_PHYS_TO_KSEG0(pa); +#endif + stp->seg_tab[va >> SEGSHIFT] = pte; + + pte += (va >> PGSHIFT) & (NPTEPG - 1); +#ifdef PARANOIADIAG + for (size_t i = 0; i < NPTEPG; i++) { + if ((pte+i)->pt_entry) + panic("pmap_enter: new segmap not empty"); + } +#endif + } + + return pte; +}