diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2001-12-20 19:02:30 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2001-12-20 19:02:30 +0000 |
commit | 664a880e367bbf984dbe49922fdace0ca00a5d91 (patch) | |
tree | 90d4583eb879ff0136c57ac9586aa724fb4f3add /sys | |
parent | 6743d0464c802e3119c4632471d95b000cfa0d89 (diff) |
Temporarily revert the pmap_motorola changes, as they may account for
some problems as well.
Requested by deraadt@
Diffstat (limited to 'sys')
31 files changed, 8904 insertions, 999 deletions
diff --git a/sys/arch/amiga/amiga/amiga_init.c b/sys/arch/amiga/amiga/amiga_init.c index 0e9c0f56f2f..23fc823257a 100644 --- a/sys/arch/amiga/amiga/amiga_init.c +++ b/sys/arch/amiga/amiga/amiga_init.c @@ -1,4 +1,4 @@ -/* $OpenBSD: amiga_init.c,v 1.23 2001/12/06 22:33:57 miod Exp $ */ +/* $OpenBSD: amiga_init.c,v 1.24 2001/12/20 19:02:23 miod Exp $ */ /* $NetBSD: amiga_init.c,v 1.56 1997/06/10 18:22:24 veego Exp $ */ /* @@ -174,6 +174,8 @@ alloc_z2mem(amount) * */ +int kernel_copyback = 1; + void start_c(id, fphystart, fphysize, cphysize, esym_addr, flags, inh_sync) int id; @@ -567,12 +569,15 @@ start_c(id, fphystart, fphysize, cphysize, esym_addr, flags, inh_sync) * recommended by Motorola; for the 68060 mandatory) */ if (RELOC(mmutype, int) <= MMU_68040) { + + if (RELOC(kernel_copyback, int)) + pg_proto |= PG_CCB; + /* * ASSUME: segment table and statically allocated page tables * of the kernel are contiguously allocated, start at * Sysseg and end at the current value of vstart. */ - pg_proto |= PG_CCB; for (; i<RELOC(Sysseg, u_int); i+= NBPG, pg_proto += NBPG) *pg++ = pg_proto; @@ -581,7 +586,8 @@ start_c(id, fphystart, fphysize, cphysize, esym_addr, flags, inh_sync) *pg++ = pg_proto; pg_proto = (pg_proto & ~PG_CI); - pg_proto |= PG_CCB; + if (RELOC(kernel_copyback, int)) + pg_proto |= PG_CCB; } #endif /* diff --git a/sys/arch/amiga/amiga/locore.s b/sys/arch/amiga/amiga/locore.s index 9d1442dac5a..6b1da1e1365 100644 --- a/sys/arch/amiga/amiga/locore.s +++ b/sys/arch/amiga/amiga/locore.s @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.s,v 1.34 2001/12/06 21:13:28 millert Exp $ */ +/* $OpenBSD: locore.s,v 1.35 2001/12/20 19:02:24 miod Exp $ */ /* $NetBSD: locore.s,v 1.89 1997/07/17 16:22:54 is Exp $ */ /* @@ -1288,7 +1288,7 @@ Lsw2: moveml #0xFCFC,a1@(PCB_REGS) | save non-scratch registers movl usp,a2 | grab USP (a2 has been saved) movl a2,a1@(PCB_USP) | and save it - movl _caddr2_pte,a1@(PCB_CMAP2) | save temporary map PTE + movl _CMAP2,a1@(PCB_CMAP2) | save temporary map PTE #ifdef FPU_EMULATE tstl _fputype | do we have any FPU? jeq Lswnofpsave | no, dont save @@ -1342,7 +1342,7 @@ Lswnofpsave: lea tmpstk,sp | now goto a tmp stack for NMI - movl a1@(PCB_CMAP2),_caddr2_pte | reload tmp map + movl a1@(PCB_CMAP2),_CMAP2 | reload tmp map moveml a1@(PCB_REGS),#0xFCFC | and registers movl a1@(PCB_USP),a0 movl a0,usp | and USP @@ -1396,7 +1396,7 @@ ENTRY(savectx) movl usp,a0 | grab USP movl a0,a1@(PCB_USP) | and save it moveml #0xFCFC,a1@(PCB_REGS) | save non-scratch registers - movl _caddr2_pte,a1@(PCB_CMAP2) | save temporary map PTE + movl _CMAP2,a1@(PCB_CMAP2) | save temporary map PTE #ifdef FPU_EMULATE tstl _fputype jeq Lsavedone @@ -1431,12 +1431,95 @@ Lsavedone: rts /* + * Copy 1 relocation unit (NBPG bytes) + * from user virtual address to physical address + */ +ENTRY(copyseg) + movl _curpcb,a1 | current pcb + movl #Lcpydone,a1@(PCB_ONFAULT) | where to return to on a fault + movl sp@(8),d0 | destination page number + moveq #PGSHIFT,d1 + lsll d1,d0 | convert to address + orl #PG_CI+PG_RW+PG_V,d0 | make sure valid and writable + movl _CMAP2,a0 + movl _CADDR2,sp@- | destination kernel VA + movl d0,a0@ | load in page table + jbsr _TBIS | invalidate any old mapping + addql #4,sp + movl _CADDR2,a1 | destination addr + movl sp@(4),a0 | source addr + movl #NBPG/4-1,d0 | count +Lcpyloop: + movsl a0@+,d1 | read longword + movl d1,a1@+ | write longword + dbf d0,Lcpyloop | continue until done +Lcpydone: + movl _curpcb,a1 | current pcb + clrl a1@(PCB_ONFAULT) | clear error catch + rts + +/* + * Copy 1 relocation unit (NBPG bytes) + * from physical address to physical address + */ +ENTRY(physcopyseg) + movl sp@(4),d0 | source page number + moveq #PGSHIFT,d1 + lsll d1,d0 | convert to address + orl #PG_CI+PG_RW+PG_V,d0 | make sure valid and writable + movl _CMAP1,a0 + movl d0,a0@ | load in page table + movl _CADDR1,sp@- | destination kernel VA + jbsr _TBIS | invalidate any old mapping + addql #4,sp + + movl sp@(8),d0 | destination page number + moveq #PGSHIFT,d1 + lsll d1,d0 | convert to address + orl #PG_CI+PG_RW+PG_V,d0 | make sure valid and writable + movl _CMAP2,a0 + movl d0,a0@ | load in page table + movl _CADDR2,sp@- | destination kernel VA + jbsr _TBIS | invalidate any old mapping + addql #4,sp + + movl _CADDR1,a0 | source addr + movl _CADDR2,a1 | destination addr + movl #NBPG/4-1,d0 | count +Lpcpy: + movl a0@+,a1@+ | copy longword + dbf d0,Lpcpy | continue until done + rts + +/* + * zero out physical memory + * specified in relocation units (NBPG bytes) + */ +ENTRY(clearseg) + movl sp@(4),d0 | destination page number + moveq #PGSHIFT,d1 + lsll d1,d0 | convert to address + orl #PG_CI+PG_RW+PG_V,d0 | make sure valid and writable + movl _CMAP1,a0 + movl _CADDR1,sp@- | destination kernel VA + movl d0,a0@ | load in page map + jbsr _TBIS | invalidate any old mapping + addql #4,sp + movl _CADDR1,a1 | destination addr + movl #NBPG/4-1,d0 | count +/* simple clear loop is fastest on 68020 */ +Lclrloop: + clrl a1@+ | clear a longword + dbf d0,Lclrloop | continue til done + rts + +/* * Invalidate entire TLB. */ ENTRY(TBIA) __TBIA: cmpl #MMU_68040,_mmutype - jle Ltbia040 + jeq Ltbia040 pflusha | flush entire TLB tstl _mmutype jpl Lmc68851a | 68851 implies no d-cache diff --git a/sys/arch/amiga/amiga/pmap.c b/sys/arch/amiga/amiga/pmap.c new file mode 100644 index 00000000000..49a25744307 --- /dev/null +++ b/sys/arch/amiga/amiga/pmap.c @@ -0,0 +1,2586 @@ +/* $OpenBSD: pmap.c,v 1.45 2001/12/20 19:02:24 miod Exp $ */ +/* $NetBSD: pmap.c,v 1.68 1999/06/19 19:44:09 is Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 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) 1991 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. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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 7.5 (Berkeley) 5/10/91 + */ + +/* + * AMIGA physical map management code. + * For 68020/68030 machines with 68551, or 68030 MMUs + * Don't even pay lip service to multiprocessor support. + * + * will only work for PAGE_SIZE == NBPG + * right now because of the assumed one-to-one relationship of PT + * pages to STEs. + */ + +/* + * 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/msgbuf.h> +#include <sys/user.h> +#include <uvm/uvm.h> +#include <machine/pte.h> +#include <machine/cpu.h> +#include <machine/vmparam.h> +#include <amiga/amiga/memlist.h> +/* + * Allocate various and sundry SYSMAPs used in the days of old VM + * and not yet converted. XXX. + */ + +#ifdef DEBUG +struct kpt_stats { + int collectscans; + int collectpages; + int kpttotal; + int kptinuse; + int kptmaxuse; +}; +struct enter_stats { + int kernel; /* entering kernel mapping */ + int user; /* entering user mapping */ + int ptpneeded; /* needed to allocate a PT page */ + int pwchange; /* no mapping change, just wiring or protection */ + int wchange; /* no mapping change, just wiring */ + int mchange; /* was mapped but mapping to different page */ + int managed; /* a managed page */ + int firstpv; /* first mapping for this PA */ + int secondpv; /* second mapping for this PA */ + int ci; /* cache inhibited */ + int unmanaged; /* not a managed page */ + int flushes; /* cache flushes */ +}; +struct remove_stats { + int calls; + int removes; + int pvfirst; + int pvsearch; + int ptinvalid; + int uflushes; + int sflushes; +}; + +struct remove_stats remove_stats; +struct enter_stats enter_stats; +struct kpt_stats kpt_stats; + +#define PDB_FOLLOW 0x0001 +#define PDB_INIT 0x0002 +#define PDB_ENTER 0x0004 +#define PDB_REMOVE 0x0008 +#define PDB_CREATE 0x0010 +#define PDB_PTPAGE 0x0020 +#define PDB_CACHE 0x0040 +#define PDB_BITS 0x0080 +#define PDB_COLLECT 0x0100 +#define PDB_PROTECT 0x0200 +#define PDB_SEGTAB 0x0400 +#define PDB_PARANOIA 0x2000 +#define PDB_WIRING 0x4000 +#define PDB_PVDUMP 0x8000 +int debugmap = 0; +int pmapdebug = PDB_PARANOIA; + +static void pmap_check_wiring __P((char *, vaddr_t)); +static void pmap_pvdump __P((paddr_t)); +#endif + +/* + * Get STEs and PTEs for user/kernel address space + */ +#if defined(M68040) || defined(M68060) +#define pmap_ste(m, v) (&((m)->pm_stab[(vaddr_t)(v) >> pmap_ishift])) +#define pmap_ste1(m, v) (&((m)->pm_stab[(vaddr_t)(v) >> SG4_SHIFT1])) +/* XXX assumes physically contiguous ST pages (if more than one) */ +#define pmap_ste2(m, v) \ + (&((m)->pm_stab[(u_int *)(*(u_int *)pmap_ste1(m,v) & SG4_ADDR1) \ + - (m)->pm_stpa + (((v) & SG4_MASK2) >> SG4_SHIFT2)])) +#define pmap_ste_v(m, v) \ + (mmutype == MMU_68040 \ + ? ((*pmap_ste1(m, v) & SG_V) && \ + (*pmap_ste2(m, v) & SG_V)) \ + : (*pmap_ste(m, v) & SG_V)) +#else /* defined(M68040) || defined(M68060) */ +#define pmap_ste(m, v) (&((m)->pm_stab[(vaddr_t)(v) >> SG_ISHIFT])) +#define pmap_ste_v(m, v) (*pmap_ste(m, v) & SG_V) +#endif /* defined(M68040) || defined(M68060) */ + +#define pmap_pte(m, v) (&((m)->pm_ptab[(vaddr_t)(v) >> PG_SHIFT])) + +#define pmap_pte_pa(pte) (*(u_int *)(pte) & PG_FRAME) + +#define pmap_pte_w(pte) (*(u_int *)(pte) & PG_W) +#define pmap_pte_ci(pte) (*(u_int *)(pte) & PG_CI) +#define pmap_pte_m(pte) (*(u_int *)(pte) & PG_M) +#define pmap_pte_u(pte) (*(u_int *)(pte) & PG_U) +#define pmap_pte_prot(pte) (*(u_int *)(pte) & PG_PROT) +#define pmap_pte_v(pte) (*(u_int *)(pte) & PG_V) + +#define pmap_pte_set_w(pte, v) \ + do { if (v) *(u_int *)(pte) |= PG_W; else *(u_int *)(pte) &= ~PG_W; \ + } while (0) +#define pmap_pte_set_prot(pte, v) \ + do { if (v) *(u_int *)(pte) |= PG_PROT; else *(u_int *)(pte) &= ~PG_PROT; \ + } while (0) +#define pmap_pte_w_chg(pte, nw) ((nw) ^ pmap_pte_w(pte)) +#define pmap_pte_prot_chg(pte, np) ((np) ^ pmap_pte_prot(pte)) + +#define active_pmap(pm) \ + ((pm) == pmap_kernel() || (pm) == curproc->p_vmspace->vm_map.pmap) + +/* + * Given a map and a machine independent protection code, + * convert to a vax protection code. + */ +#define pte_prot(m, p) (protection_codes[p]) +int protection_codes[8]; + +/* + * Kernel page table page management. + * + * One additional page of KPT allows for 16 MB of virtual buffer cache. + * A GENERIC kernel allocates this for 2 MB of real buffer cache, + * which in turn is allocated for 38 MB of RAM. + * We add one per 16 MB of RAM to allow for tuning the machine-independent + * options. + */ +#ifndef NKPTADDSHIFT +#define NKPTADDSHIFT 24 +#endif + +struct kpt_page { + struct kpt_page *kpt_next; /* link on either used or free list */ + vaddr_t kpt_va; /* always valid kernel VA */ + paddr_t kpt_pa; /* PA of this page (for speed) */ +}; +struct kpt_page *kpt_free_list, *kpt_used_list; +struct kpt_page *kpt_pages; + +/* + * Kernel segment/page table and page table map. + * The page table map gives us a level of indirection we need to dynamically + * expand the page table. It is essentially a copy of the segment table + * with PTEs instead of STEs. All are initialized in locore at boot time. + * Sysmap will initially contain VM_KERNEL_PT_PAGES pages of PTEs. + * Segtabzero is an empty segment table which all processes share til they + * reference something. + */ +u_int *Sysseg, *Sysseg_pa; +u_int *Sysmap, *Sysptmap; +u_int *Segtabzero, *Segtabzeropa; +vsize_t Sysptsize = VM_KERNEL_PT_PAGES; + +struct pmap kernel_pmap_store; +struct vm_map *pt_map; +struct vm_map pt_map_store; + +vsize_t mem_size; /* memory size in bytes */ +vaddr_t virtual_avail; /* VA of first avail page (after kernel bss)*/ +vaddr_t virtual_end; /* VA of last avail page (end of kernel AS) */ +int page_cnt; /* number of pages managed by the VM system */ +boolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */ +char *pmap_attributes; /* reference and modify bits */ +TAILQ_HEAD(pv_page_list, pv_page) pv_page_freelist; +int pv_nfree; +#if defined(M68040) || defined(M68060) +static int pmap_ishift; /* segment table index shift */ +int protostfree; /* prototype (default) free ST map */ +#endif +extern paddr_t msgbufpa; /* physical address of the msgbuf */ + +u_long noncontig_enable; +extern vaddr_t amiga_uptbase; + +extern paddr_t z2mem_start; + +extern vaddr_t reserve_dumppages __P((vaddr_t)); + +boolean_t pmap_testbit __P((paddr_t, int)); +void pmap_enter_ptpage __P((pmap_t, vaddr_t)); +static void pmap_ptpage_addref __P((vaddr_t)); +static int pmap_ptpage_delref __P((vaddr_t)); +static void pmap_changebit __P((vaddr_t, int, boolean_t)); + struct pv_entry * pmap_alloc_pv __P((void)); +void pmap_free_pv __P((struct pv_entry *)); +void pmap_pinit __P((pmap_t)); +void pmap_release __P((pmap_t)); +static void pmap_remove_mapping __P((pmap_t, vaddr_t, pt_entry_t *, int)); + +static void amiga_protection_init __P((void)); +void pmap_collect1 __P((pmap_t, paddr_t, paddr_t)); + +/* pmap_remove_mapping flags */ +#define PRM_TFLUSH 0x01 +#define PRM_CFLUSH 0x02 +#define PRM_KEEPPTPAGE 0x04 + + +/* + * All those kernel PT submaps that BSD is so fond of + */ +caddr_t CADDR1, CADDR2, vmmap; +u_int *CMAP1, *CMAP2, *vmpte, *msgbufmap; + +#define PAGE_IS_MANAGED(pa) (pmap_initialized \ + && vm_physseg_find(atop((pa)), NULL) != -1) + +#define pa_to_pvh(pa) \ +({ \ + int bank_, pg_; \ + bank_ = vm_physseg_find(atop((pa)), &pg_); \ + &vm_physmem[bank_].pmseg.pvent[pg_]; \ +}) + +#define pa_to_attribute(pa) \ +({ \ + int bank_, pg_; \ + bank_ = vm_physseg_find(atop((pa)), &pg_); \ + &vm_physmem[bank_].pmseg.attrs[pg_]; \ +}) + +/* + * Bootstrap the system enough to run with virtual memory. + * Map the kernel's code and data, and allocate the system page table. + * + * On the HP this is called after mapping has already been enabled + * and just syncs the pmap module with what has already been done. + * [We can't call it easily with mapping off since the kernel is not + * mapped with PA == VA, hence we would have to relocate every address + * from the linked base (virtual) address 0 to the actual (physical) + * address of 0xFFxxxxxx.] + */ +void +pmap_bootstrap(firstaddr, loadaddr) + paddr_t firstaddr; + paddr_t loadaddr; +{ + vaddr_t va; + u_int *pte; + int i; + struct boot_memseg *sp, *esp; + paddr_t fromads, toads; + + fromads = firstaddr; + toads = maxmem << PGSHIFT; + + uvmexp.pagesize = NBPG; + uvm_setpagesize(); + + /* XXX: allow for msgbuf */ + toads -= m68k_round_page(MSGBUFSIZE); + msgbufpa = toads; + /* + * first segment of memory is always the one loadbsd found + * for loading the kernel into. + */ + uvm_page_physload(atop(fromads), atop(toads), + atop(fromads), atop(toads), VM_FREELIST_DEFAULT); + + sp = memlist->m_seg; + esp = sp + memlist->m_nseg; + i = 1; + for (; noncontig_enable && sp < esp; sp++) { + if ((sp->ms_attrib & MEMF_FAST) == 0) + continue; /* skip if not FastMem */ + if (firstaddr >= sp->ms_start && + firstaddr < sp->ms_start + sp->ms_size) + continue; /* skip kernel segment */ + if (sp->ms_size == 0) + continue; /* skip zero size segments */ + fromads = sp->ms_start; + toads = sp->ms_start + sp->ms_size; +#ifdef DEBUG_A4000 + /* + * My A4000 doesn't seem to like Zorro II memory - this + * hack is to skip the motherboard memory and use the + * Zorro II memory. Only for trying to debug the problem. + * Michael L. Hitch + */ + if (toads == 0x08000000) + continue; /* skip A4000 motherboard mem */ +#endif + /* + * Deal with Zorro II memory stolen for DMA bounce buffers. + * This needs to be handled better. + * + * XXX is: disabled. This is handled now in amiga_init.c + * by removing the stolen memory from the memlist. + * + * XXX is: enabled again, but check real size and position. + * We check z2mem_start is in this segment, and set its end + * to the z2mem_start. + * + */ + if ((fromads <= z2mem_start) && (toads > z2mem_start)) + toads = z2mem_start; + + uvm_page_physload(atop(fromads), atop(toads), + atop(fromads), atop(toads), (fromads & 0xff000000) ? + VM_FREELIST_DEFAULT : VM_FREELIST_ZORROII); + physmem += (toads - fromads) / NBPG; + ++i; + if (noncontig_enable == 1) + break; /* Only two segments enabled */ + } + + mem_size = physmem << PGSHIFT; + virtual_avail = VM_MIN_KERNEL_ADDRESS + (firstaddr - loadaddr); + virtual_end = VM_MAX_KERNEL_ADDRESS; + + /* + * Initialize protection array. + */ + amiga_protection_init(); + + /* + * Kernel page/segment table allocated in locore, + * just initialize pointers. + */ + pmap_kernel()->pm_stpa = Sysseg_pa; + pmap_kernel()->pm_stab = Sysseg; + pmap_kernel()->pm_ptab = Sysmap; +#if defined(M68040) || defined(M68060) + if (mmutype == MMU_68040) { + pmap_ishift = SG4_SHIFT1; + pmap_kernel()->pm_stfree = protostfree; + } else + pmap_ishift = SG_ISHIFT; +#endif + + simple_lock_init(&pmap_kernel()->pm_lock); + pmap_kernel()->pm_count = 1; + + /* + * Allocate all the submaps we need + */ +#define SYSMAP(c, p, v, n) \ + v = (c)va; va += ((n)*NBPG); p = pte; pte += (n); + + va = virtual_avail; + pte = pmap_pte(pmap_kernel(), va); + + SYSMAP(caddr_t ,CMAP1 ,CADDR1 ,1 ) + SYSMAP(caddr_t ,CMAP2 ,CADDR2 ,1 ) + SYSMAP(caddr_t ,vmpte ,vmmap ,1 ) + SYSMAP(struct msgbuf * ,msgbufmap ,msgbufp ,btoc(MSGBUFSIZE)) + + DCIS(); + virtual_avail = reserve_dumppages(va); +} + +/* + * Initialize the pmap module. + * Called by vm_init, to initialize any structures that the pmap + * system needs to map virtual memory. + */ +void +pmap_init() +{ + extern vaddr_t amigahwaddr; + extern u_int namigahwpg; + vaddr_t addr, addr2; + paddr_t paddr; + vsize_t s; + u_int npg; + struct pv_entry *pv; + char *attr; + int rv, bank; +#if defined(M68060) + struct kpt_page *kptp; +#endif + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_init()\n"); +#endif + /* + * Now that kernel map has been allocated, we can mark as + * unavailable regions which we have mapped in locore. + * XXX in pmap_boostrap() ??? + */ + addr = (vaddr_t) amigahwaddr; + if (uvm_map(kernel_map, &addr, + ptoa(namigahwpg), + NULL, UVM_UNKNOWN_OFFSET, 0, + UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, + UVM_INH_NONE, UVM_ADV_RANDOM, + UVM_FLAG_FIXED))) + goto bogons; + addr = (vaddr_t) Sysmap; + if (uvm_map(kernel_map, &addr, AMIGA_KPTSIZE, + NULL, UVM_UNKNOWN_OFFSET, 0, + UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, + UVM_INH_NONE, UVM_ADV_RANDOM, + UVM_FLAG_FIXED))) { + /* + * If this fails, it is probably because the static + * portion of the kernel page table isn't big enough + * and we overran the page table map. + */ +bogons: + panic("pmap_init: bogons in the VM system!\n"); + } +#ifdef DEBUG + if (pmapdebug & PDB_INIT) { + printf("pmap_init: Sysseg %p, Sysmap %p, Sysptmap %p\n", + Sysseg, Sysmap, Sysptmap); + printf(" vstart %lx, vend %lx\n", virtual_avail, virtual_end); + } +#endif + + /* + * Allocate memory for random pmap data structures. Includes the + * initial segment table, pv_head_table and pmap_attributes. + */ + for (page_cnt = 0, bank = 0; bank < vm_nphysseg; bank++) { + page_cnt += vm_physmem[bank].end - vm_physmem[bank].start; +#ifdef DEBUG + printf("pmap_init: %2d: %08lx - %08lx (%10d)\n", bank, + vm_physmem[bank].start << PGSHIFT, + vm_physmem[bank].end << PGSHIFT, page_cnt << PGSHIFT); +#endif + } + s = AMIGA_STSIZE; /* Segtabzero */ + s += page_cnt * sizeof(struct pv_entry); /* pv table */ + s += page_cnt * sizeof(char); /* attribute table */ + + s = round_page(s); + addr = uvm_km_zalloc(kernel_map, s); + Segtabzero = (u_int *)addr; + pmap_extract(pmap_kernel(), addr, (paddr_t *)&Segtabzeropa); + + addr += AMIGA_STSIZE; + + pv_table = (pv_entry_t)addr; + addr += page_cnt * sizeof(struct pv_entry); + + pmap_attributes = (char *)addr; +#ifdef DEBUG + if (pmapdebug & PDB_INIT) + printf("pmap_init: %lx bytes: page_cnt %x s0 %p(%p) " + "tbl %p atr %p\n", + s, page_cnt, Segtabzero, Segtabzeropa, + pv_table, pmap_attributes); +#endif + + /* + * Now that the pv and attribute tables have been allocated, + * assign them to the memory segments. + */ + pv = pv_table; + attr = pmap_attributes; + for (bank = 0; bank < vm_nphysseg; bank++) { + npg = vm_physmem[bank].end - vm_physmem[bank].start; + vm_physmem[bank].pmseg.pvent = pv; + vm_physmem[bank].pmseg.attrs = attr; + pv += npg; + attr += npg; + } + + /* + * Allocate physical memory for kernel PT pages and their management. + * we need enough pages to map the page tables for each process + * plus some slop. + */ + npg = howmany(((maxproc + 16) * AMIGA_UPTSIZE / NPTEPG), NBPG); +#ifdef NKPTADD + npg += NKPTADD; +#else + npg += mem_size >> NKPTADDSHIFT; +#endif +#if 1/*def DEBUG*/ + printf("Maxproc %d, mem_size %ld MB: allocating %d KPT pages\n", + maxproc, mem_size>>20, npg); +#endif + s = ptoa(npg) + round_page(npg * sizeof (struct kpt_page)); + + /* + * Verify that space will be allocated in region for which + * we already have kernel PT pages. + */ + addr = 0; + rv = uvm_map(kernel_map, &addr, s, NULL, UVM_UNKNOWN_OFFSET, 0, + UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, + UVM_ADV_RANDOM, UVM_FLAG_NOMERGE)); + if (rv || (addr + s) >= (vaddr_t)Sysmap) + panic("pmap_init: kernel PT too small"); + uvm_unmap(kernel_map, addr, addr + s); + /* + * Now allocate the space and link the pages together to + * form the KPT free list. + */ + addr = uvm_km_zalloc(kernel_map, s); + if (addr == 0) + panic("pmap_init: cannot allocate KPT free list"); + s = ptoa(npg); + addr2 = addr + s; + kpt_pages = &((struct kpt_page *)addr2)[npg]; + kpt_free_list = (struct kpt_page *)0; + do { + addr2 -= NBPG; + (--kpt_pages)->kpt_next = kpt_free_list; + kpt_free_list = kpt_pages; + kpt_pages->kpt_va = addr2; + pmap_extract(pmap_kernel(), addr2, &kpt_pages->kpt_pa); + } while (addr != addr2); + +#ifdef DEBUG + kpt_stats.kpttotal = atop(s); + if (pmapdebug & PDB_INIT) + printf("pmap_init: KPT: %ld pages from %lx to %lx\n", atop(s), + addr, addr + s); +#endif + + /* + * Allocate the segment table map and the page table map. + */ + addr = amiga_uptbase; + if ((AMIGA_UPTMAXSIZE / AMIGA_UPTSIZE) < maxproc) { + s = AMIGA_UPTMAXSIZE; + /* + * XXX We don't want to hang when we run out of + * page tables, so we lower maxproc so that fork() + * will fail instead. Note that root could still raise + * this value via sysctl(2). + */ + maxproc = AMIGA_UPTMAXSIZE / AMIGA_UPTSIZE; + } else + s = (maxproc * AMIGA_UPTSIZE); + + pt_map = uvm_km_suballoc(kernel_map, &addr, &addr2, s, VM_MAP_PAGEABLE, + TRUE, &pt_map_store); + +#if defined(M68040) || defined(M68060) + if (mmutype == MMU_68040) + protostfree = ~1 & ~(-1 << MAXUL2SIZE); +#endif /* defined(M68040) || defined(M68060) */ + + /* + * Now it is safe to enable pv_table recording. + */ + pmap_initialized = TRUE; + /* + * Now that this is done, mark the pages shared with the + * hardware page table search as non-CCB (actually, as CI). + * + * XXX Hm. Given that this is in the kernel map, can't we just + * use the va's? + */ +#ifdef M68060 + if (machineid & AMIGA_68060) { + kptp = kpt_free_list; + while (kptp) { + pmap_changebit(kptp->kpt_pa, PG_CCB, 0); + pmap_changebit(kptp->kpt_pa, PG_CI, 1); + kptp = kptp->kpt_next; + } + + paddr = (paddr_t)Segtabzeropa; + while (paddr < (paddr_t)Segtabzeropa + AMIGA_STSIZE) { + pmap_changebit(paddr, PG_CCB, 0); + pmap_changebit(paddr, PG_CI, 1); + paddr += NBPG; + } + + DCIS(); + } +#endif +} + +struct pv_entry * +pmap_alloc_pv() +{ + struct pv_page *pvp; + struct pv_entry *pv; + int i; + + if (pv_nfree == 0) { + pvp = (struct pv_page *)uvm_km_zalloc(kernel_map, NBPG); + if (pvp == 0) + panic("pmap_alloc_pv: uvm_km_zalloc() failed"); + pvp->pvp_pgi.pgi_freelist = pv = &pvp->pvp_pv[1]; + for (i = NPVPPG - 2; i; i--, pv++) + pv->pv_next = pv + 1; + pv->pv_next = 0; + pv_nfree += pvp->pvp_pgi.pgi_nfree = NPVPPG - 1; + TAILQ_INSERT_HEAD(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + pv = &pvp->pvp_pv[0]; + } else { + --pv_nfree; + pvp = pv_page_freelist.tqh_first; + if (--pvp->pvp_pgi.pgi_nfree == 0) { + TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + } + pv = pvp->pvp_pgi.pgi_freelist; +#ifdef DIAGNOSTIC + if (pv == 0) + panic("pmap_alloc_pv: pgi_nfree inconsistent"); +#endif + pvp->pvp_pgi.pgi_freelist = pv->pv_next; + } + return pv; +} + +void +pmap_free_pv(pv) + struct pv_entry *pv; +{ + struct pv_page *pvp; + + pvp = (struct pv_page *)trunc_page((vaddr_t)pv); + switch (++pvp->pvp_pgi.pgi_nfree) { + case 1: + TAILQ_INSERT_TAIL(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + default: + pv->pv_next = pvp->pvp_pgi.pgi_freelist; + pvp->pvp_pgi.pgi_freelist = pv; + ++pv_nfree; + break; + case NPVPPG: + pv_nfree -= NPVPPG - 1; + TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + uvm_km_free(kernel_map, (vaddr_t)pvp, NBPG); + break; + } +} + +/* + * Used to map a range of physical addresses into kernel + * virtual address space. + * + * For now, VM is already on, we only need to map the + * specified memory. + */ +vaddr_t +pmap_map(virt, start, end, prot) + vaddr_t virt; + paddr_t start; + paddr_t end; + int prot; +{ +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_map(%lx, %lx, %lx, %x)\n", virt, start, end, + prot); +#endif + while (start < end) { + pmap_enter(pmap_kernel(), virt, start, prot, 0); + virt += PAGE_SIZE; + start += PAGE_SIZE; + } + return(virt); +} + +/* + * 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. + */ +struct pmap * +pmap_create(void) +{ + struct pmap *pmap; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) + printf("pmap_create(%lx)\n", size); +#endif + + pmap = (struct pmap *)malloc(sizeof *pmap, M_VMPMAP, M_WAITOK); + bzero(pmap, sizeof(*pmap)); + pmap_pinit(pmap); + return (pmap); +} + +/* + * Initialize a preallocated and zeroed pmap structure, + * such as one in a vmspace structure. + */ +void +pmap_pinit(pmap) + pmap_t pmap; +{ + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) + printf("pmap_pinit(%p)\n", pmap); +#endif + /* + * No need to allocate page table space yet but we do need a + * valid segment table. Initially, we point everyone at the + * "null" segment table. On the first pmap_enter, a real + * segment table will be allocated. + */ + pmap->pm_stab = Segtabzero; + pmap->pm_stpa = Segtabzeropa; +#if defined(M68040) || defined(M68060) + if (mmutype == MMU_68040) + pmap->pm_stfree = protostfree; +#endif + pmap->pm_count = 1; + simple_lock_init(&pmap->pm_lock); +} + +/* + * Retire the given physical map from service. + * Should only be called if the map contains + * no valid mappings. + */ +void +pmap_destroy(pmap) + pmap_t pmap; +{ + int count; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_destroy(%p)\n", pmap); +#endif + if (pmap == NULL) + return; + + simple_lock(&pmap->pm_lock); + count = --pmap->pm_count; + simple_unlock(&pmap->pm_lock); + if (count == 0) { + pmap_release(pmap); + free((caddr_t)pmap, M_VMPMAP); + } +} + +/* + * Release any resources held by the given physical map. + * Called when a pmap initialized by pmap_pinit is being released. + * Should only be called if the map contains no valid mappings. + */ +void +pmap_release(pmap) + pmap_t pmap; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_release(%p)\n", pmap); +#endif +#ifdef notdef /* DIAGNOSTIC */ + /* count would be 0 from pmap_destroy... */ + simple_lock(&pmap->pm_lock); + if (pmap->pm_count != 1) + panic("pmap_release count"); +#endif + if (pmap->pm_ptab) + uvm_km_free_wakeup(pt_map, (vaddr_t)pmap->pm_ptab, + AMIGA_UPTSIZE); + if (pmap->pm_stab != Segtabzero) + uvm_km_free_wakeup(kernel_map, (vaddr_t)pmap->pm_stab, + AMIGA_STSIZE); +} + +/* + * Add a reference to the specified pmap. + */ +void +pmap_reference(pmap) + pmap_t pmap; +{ +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_reference(%p)\n", pmap); +#endif + if (pmap != NULL) { + simple_lock(&pmap->pm_lock); + pmap->pm_count++; + simple_unlock(&pmap->pm_lock); + } +} + +/* + * Remove 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_remove(pmap, sva, eva) + pmap_t pmap; + vaddr_t sva, eva; +{ + paddr_t pa; + vaddr_t va; + u_int *pte; + int flags; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) + printf("pmap_remove(%p, %lx, %lx)\n", pmap, sva, eva); +#endif + + if (pmap == NULL) + return; + +#ifdef DEBUG + remove_stats.calls++; +#endif + flags = active_pmap(pmap) ? PRM_TFLUSH : 0; + for (va = sva; va < eva; va += PAGE_SIZE) { + /* + * Weed out invalid mappings. + * Note: we assume that the segment table is always allocated. + */ + if (!pmap_ste_v(pmap, va)) { + /* XXX: avoid address wrap around */ + if (va >= m68k_trunc_seg((vaddr_t)-1)) + break; + va = m68k_round_seg(va + PAGE_SIZE) - PAGE_SIZE; + continue; + } + pte = pmap_pte(pmap, va); + pa = pmap_pte_pa(pte); + if (pa == 0) + continue; + pmap_remove_mapping(pmap, va, pte, flags); + } +} + +/* + * pmap_page_protect: + * + * Lower the permission for all mappings to a given page. + */ +void +pmap_page_protect(struct vm_page *pg, vm_prot_t prot) +{ + paddr_t pa; + pv_entry_t pv; + int s; + + pa = VM_PAGE_TO_PHYS(pg); + +#ifdef DEBUG + if ((pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) || + (prot == VM_PROT_NONE && (pmapdebug & PDB_REMOVE))) + printf("pmap_page_protect(%lx, %x)\n", pa, prot); +#endif + if (!PAGE_IS_MANAGED(pa)) + return; + + switch (prot) { + case VM_PROT_ALL: + break; + /* copy_on_write */ + case VM_PROT_READ: + case VM_PROT_READ|VM_PROT_EXECUTE: + pmap_changebit(pa, PG_RO, TRUE); + break; + /* remove_all */ + default: + pv = pa_to_pvh(pa); + s = splimp(); + while (pv->pv_pmap != NULL) { + pt_entry_t *pte; + + pte = pmap_pte(pv->pv_pmap, pv->pv_va); +#ifdef DEBUG + if (!pmap_ste_v(pv->pv_pmap,pv->pv_va) || + pmap_pte_pa(pte) != pa) +{ + printf("pmap_page_protect: va %lx, pmap_ste_v %d pmap_pte_pa %08x/%lx\n", + pv->pv_va, pmap_ste_v(pv->pv_pmap,pv->pv_va), + pmap_pte_pa(pmap_pte(pv->pv_pmap,pv->pv_va)), pa); + printf(" pvh %p pv %p pv_next %p\n", pa_to_pvh(pa), pv, pv->pv_next); + panic("pmap_page_protect: bad mapping"); +} +#endif + if (!pmap_pte_w(pte)) + pmap_remove_mapping(pv->pv_pmap, pv->pv_va, + pte, PRM_TFLUSH|PRM_CFLUSH); + else { + pv = pv->pv_next; +#ifdef DEBUG + if (pmapdebug & PDB_PARANOIA) + printf("%s wired mapping for %lx not removed\n", + "pmap_page_protect:", pa); +#endif + if (pv == NULL) + break; + } + } + splx(s); + break; + } +} + +/* + * Set the physical protection on the + * specified range of this map as requested. + */ +void +pmap_protect(pmap, sva, eva, prot) + pmap_t pmap; + vaddr_t sva, eva; + vm_prot_t prot; +{ + u_int *pte; + vaddr_t va; + boolean_t needtflush; + int isro; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) + printf("pmap_protect(%p, %lx, %lx, %x)\n", pmap, sva, eva, + prot); +#endif + if (pmap == NULL) + return; + + if ((prot & VM_PROT_READ) == VM_PROT_NONE) { + pmap_remove(pmap, sva, eva); + return; + } + if (prot & VM_PROT_WRITE) + return; + + pte = pmap_pte(pmap, sva); + isro = pte_prot(pmap, prot) == PG_RO ? 1 : 0; + needtflush = active_pmap(pmap); + for (va = sva; va < eva; va += PAGE_SIZE) { + /* + * Page table page is not allocated. + * Skip it, we don't want to force allocation + * of unnecessary PTE pages just to set the protection. + */ + if (!pmap_ste_v(pmap, va)) { + /* XXX: avoid address wrap around */ + if (va >= m68k_trunc_seg((vaddr_t)-1)) + break; + va = m68k_round_seg(va + PAGE_SIZE) - PAGE_SIZE; + pte = pmap_pte(pmap, va); + pte++; + continue; + } + /* + * skip if page not valid or protection is same + */ + if (!pmap_pte_v(pte) || !pmap_pte_prot_chg(pte, isro)) { + pte++; + continue; + } +#if defined(M68040) || defined(M68060) + /* + * Clear caches if making RO (see section + * "7.3 Cache Coherency" in the manual). + */ + if (isro && mmutype == MMU_68040) { + paddr_t pa = pmap_pte_pa(pte); + + DCFP(pa); + ICPP(pa); + } +#endif + pmap_pte_set_prot(pte, isro); + if (needtflush) + TBIS(va); + pte++; + } +} + +/* + * Insert the given physical page (p) at + * the specified virtual address (v) in the + * target physical map with the protection requested. + * + * If specified, the page will be wired down, meaning + * that the related pte can not be reclaimed. + * + * NB: This is the only routine which MAY NOT lazy-evaluate + * or lose information. That is, this routine must actually + * insert this page into the given map NOW. + */ +extern int kernel_copyback; + +int +pmap_enter(pmap, va, pa, prot, flags) + pmap_t pmap; + vaddr_t va; + paddr_t pa; + vm_prot_t prot; + int flags; +{ + u_int *pte; + int npte; + paddr_t opa; + boolean_t cacheable = TRUE; + boolean_t checkpv = TRUE; + boolean_t wired = (flags & PMAP_WIRED) != 0; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_ENTER)) + printf("pmap_enter(%p, %lx, %lx, %x, %x)\n", pmap, va, pa, + prot, wired); +#endif + +#ifdef DEBUG + if (pmap == pmap_kernel()) + enter_stats.kernel++; + else + enter_stats.user++; +#endif + /* + * For user mapping, allocate kernel VM resources if necessary. + */ + if (pmap->pm_ptab == NULL) + pmap->pm_ptab = (pt_entry_t *) + uvm_km_valloc_wait(pt_map, AMIGA_UPTSIZE); + + /* + * Segment table entry not valid, we need a new PT page + */ + if (!pmap_ste_v(pmap, va)) + pmap_enter_ptpage(pmap, va); + + pte = pmap_pte(pmap, va); + opa = pmap_pte_pa(pte); +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: pte %p, *pte %x\n", pte, *(int *)pte); +#endif + + /* + * Mapping has not changed, must be protection or wiring change. + */ + if (opa == pa) { +#ifdef DEBUG + enter_stats.pwchange++; +#endif + /* + * Wiring change, just update stats. + * We don't worry about wiring PT pages as they remain + * resident as long as there are valid mappings in them. + * Hence, if a user page is wired, the PT page will be also. + */ + if ((wired && !pmap_pte_w(pte)) || (!wired && pmap_pte_w(pte))){ +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: wiring change -> %x\n", wired); +#endif + if (wired) + pmap->pm_stats.wired_count++; + else + pmap->pm_stats.wired_count--; +#ifdef DEBUG + enter_stats.wchange++; +#endif + } + /* + * Retain cache inhibition status + */ + checkpv = FALSE; + if (pmap_pte_ci(pte)) + cacheable = FALSE; + goto validate; + } + + /* + * Mapping has changed, invalidate old range and fall through to + * handle validating new mapping. + */ + if (opa) { +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: removing old mapping %lx\n", va); +#endif + pmap_remove_mapping(pmap, va, pte, + PRM_TFLUSH|PRM_CFLUSH|PRM_KEEPPTPAGE); +#ifdef DEBUG + enter_stats.mchange++; +#endif + } + + /* + * If this is a new user mapping, increment the wiring count + * on this PT page. PT pages are wired down as long as there + * is a valid mapping in the page. + */ + if (pmap != pmap_kernel()) + pmap_ptpage_addref(trunc_page((vaddr_t)pte)); + + /* + * Enter on the PV list if part of our managed memory + * Note that we raise IPL while manipulating pv_table + * since pmap_enter can be called at interrupt time. + */ + if (PAGE_IS_MANAGED(pa)) { + pv_entry_t pv, npv; + int s; + +#ifdef DEBUG + enter_stats.managed++; +#endif + pv = pa_to_pvh(pa); + s = splimp(); +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: pv at %p: %lx/%p/%p\n", pv, pv->pv_va, + pv->pv_pmap, pv->pv_next); +#endif + /* + * No entries yet, use header as the first entry + */ + if (pv->pv_pmap == NULL) { +#ifdef DEBUG + enter_stats.firstpv++; +#endif + pv->pv_va = va; + pv->pv_pmap = pmap; + pv->pv_next = NULL; + pv->pv_ptste = NULL; + pv->pv_ptpmap = NULL; + pv->pv_flags = 0; + } + /* + * There is at least one other VA mapping this page. + * Place this entry after the header. + */ + else { +#ifdef DEBUG + for (npv = pv; npv; npv = npv->pv_next) + if (pmap == npv->pv_pmap && va == npv->pv_va) + panic("pmap_enter: already in pv_tab"); +#endif + npv = pmap_alloc_pv(); + npv->pv_va = va; + npv->pv_pmap = pmap; + npv->pv_next = pv->pv_next; + npv->pv_ptste = NULL; + npv->pv_ptpmap = NULL; + pv->pv_next = npv; +#ifdef DEBUG + if (!npv->pv_next) + enter_stats.secondpv++; +#endif + } + splx(s); + } + /* + * Assumption: if it is not part of our managed memory + * then it must be device memory which may be volitile. + */ + else if (pmap_initialized) { + checkpv = cacheable = FALSE; +#ifdef DEBUG + enter_stats.unmanaged++; +#endif + } + + /* + * Increment counters + */ + pmap->pm_stats.resident_count++; + if (wired) + pmap->pm_stats.wired_count++; + +validate: + /* + * Now validate mapping with desired protection/wiring. + * Assume uniform modified and referenced status for all + * AMIGA pages in a MACH page. + */ +#if defined(M68040) || defined(M68060) +#if DEBUG + if (pmapdebug & 0x10000 && mmutype == MMU_68040 && + pmap == pmap_kernel()) { + char *s; + if (va >= amiga_uptbase && + va < (amiga_uptbase + AMIGA_UPTMAXSIZE)) + s = "UPT"; + else if (va >= (u_int)Sysmap && + va < ((u_int)Sysmap + AMIGA_KPTSIZE)) + s = "KPT"; + else if (va >= (u_int)pmap->pm_stab && + va < ((u_int)pmap->pm_stab + AMIGA_STSIZE)) + s = "KST"; + else if (curproc && + va >= (u_int)curproc->p_vmspace->vm_map.pmap->pm_stab && + va < ((u_int)curproc->p_vmspace->vm_map.pmap->pm_stab + + AMIGA_STSIZE)) + s = "UST"; + else + s = "other"; + printf("pmap_init: validating %s kernel page at %lx -> %lx\n", + s, va, pa); + + } +#endif + if (mmutype == MMU_68040 && pmap == pmap_kernel() && + ((va >= amiga_uptbase && va < (amiga_uptbase + AMIGA_UPTMAXSIZE)) || + (va >= (u_int)Sysmap && va < ((u_int)Sysmap + AMIGA_KPTSIZE)))) + cacheable = FALSE; /* don't cache user page tables */ + + /* Don't cache if process can't take it, like SunOS ones. */ + if (mmutype == MMU_68040 && pmap != pmap_kernel() && + (curproc->p_md.md_flags & MDP_UNCACHE_WX) && + (prot & VM_PROT_EXECUTE) && (prot & VM_PROT_WRITE)) + checkpv = cacheable = FALSE; +#endif + npte = (pa & PG_FRAME) | pte_prot(pmap, prot) | PG_V; + npte |= (*(int *)pte & (PG_M|PG_U)); + if (wired) + npte |= PG_W; + if (!checkpv && !cacheable) +#if defined(M68060) && defined(NO_SLOW_CIRRUS) +#if defined(M68040) || defined(M68030) || defined(M68020) + npte |= (cputype == CPU_68060 ? PG_CIN : PG_CI); +#else + npte |= PG_CIN; +#endif +#else + npte |= PG_CI; +#endif +#if defined(M68040) || defined(M68060) + else if (mmutype == MMU_68040 && (npte & PG_PROT) == PG_RW && + (kernel_copyback || pmap != pmap_kernel())) + npte |= PG_CCB; /* cache copyback */ +#endif + /* + * Remember if this was a wiring-only change. + * If so, we need not flush the TLB and caches. + */ + wired = ((*(int *)pte ^ npte) == PG_W); +#if defined(M68040) || defined(M68060) + if (mmutype == MMU_68040 && !wired) { + DCFP(pa); + ICPP(pa); + } +#endif +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: new pte value %x\n", npte); +#endif + *(int *)pte++ = npte; + if (!wired && active_pmap(pmap)) + TBIS(va); +#ifdef DEBUG + if ((pmapdebug & PDB_WIRING) && pmap != pmap_kernel()) { + va -= PAGE_SIZE; + pmap_check_wiring("enter", trunc_page((vaddr_t)pmap_pte(pmap, va))); + } +#endif + + return (0); +} + +/* + * Routine: pmap_unwire + * Function: Change the wiring attribute for a map/virtual-address + * pair. + * In/out conditions: + * The mapping must already exist in the pmap. + */ +void +pmap_unwire(pmap, va) + pmap_t pmap; + vaddr_t va; +{ + u_int *pte; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_unwire(%p, %lx)\n", pmap, va); +#endif + if (pmap == NULL) + return; + + pte = pmap_pte(pmap, va); +#ifdef DEBUG + /* + * Page table page is not allocated. + * Should this ever happen? Ignore it for now, + * we don't want to force allocation of unnecessary PTE pages. + */ + if (!pmap_ste_v(pmap, va)) { + if (pmapdebug & PDB_PARANOIA) + printf("pmap_unwire: invalid STE for %lx\n", + va); + return; + } + /* + * Page not valid. Should this ever happen? + * Just continue and change wiring anyway. + */ + if (!pmap_pte_v(pte)) { + if (pmapdebug & PDB_PARANOIA) + printf("pmap_unwire: invalid PTE for %lx\n", + va); + } +#endif + if (pmap_pte_w(pte)) { + pmap->pm_stats.wired_count--; + } + /* + * Wiring is not a hardware characteristic so there is no need + * to invalidate TLB. + */ + pmap_pte_set_w(pte, 0); +} + +/* + * Routine: pmap_extract + * Function: + * Extract the physical page address associated + * with the given map/virtual_address pair. + */ + +boolean_t +pmap_extract(pmap, va, pap) + pmap_t pmap; + vaddr_t va; + paddr_t *pap; +{ + paddr_t pa; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_extract(%p, %lx) -> ", pmap, va); +#endif + if (pmap && pmap_ste_v(pmap, va)) + pa = *(int *)pmap_pte(pmap, va); + else + return (FALSE); + *pap = (pa & PG_FRAME) | (va & ~PG_FRAME); +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("%lx\n", *pap); +#endif + return (TRUE); +} + +/* + * Copy the range specified by src_addr/len + * from the source map to the range dst_addr/len + * in the destination map. + * + * This routine is only advisory and need not do anything. + */ +void pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr) + pmap_t dst_pmap; + pmap_t src_pmap; + vaddr_t dst_addr; + vsize_t len; + vaddr_t src_addr; +{ +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_copy(%p, %p, %lx, %lx, %lx)\n", dst_pmap, + src_pmap, dst_addr, len, src_addr); +#endif +} + +/* + * Routine: pmap_collect + * Function: + * Garbage collects the physical map system for + * pages which are no longer used. + * Success need not be guaranteed -- that is, there + * may well be pages which are not referenced, but + * others may be collected. + * Usage: + * Called by the pageout daemon when pages are scarce. + */ +void +pmap_collect(pmap) + pmap_t pmap; +{ + int bank, s; + + if (pmap != pmap_kernel()) + return; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_collect(%p)\n", pmap); + kpt_stats.collectscans++; +#endif + s = splimp(); + + for (bank = 0; bank < vm_nphysseg; bank++) + pmap_collect1(pmap, ptoa(vm_physmem[bank].start), + ptoa(vm_physmem[bank].end)); + +#ifdef notyet + /* Go compact and garbage-collect the pv_table. */ + pmap_collect_pv(); +#endif + splx(s); +} + +/* + * Routine: pmap_collect1() + * + * Function: + * Helper function for pmap_collect(). Do the actual + * garbage-collection of range of physical addresses. + */ +void +pmap_collect1(pmap, startpa, endpa) + pmap_t pmap; + paddr_t startpa, endpa; +{ + paddr_t pa; + struct pv_entry *pv; + pt_entry_t *pte; + paddr_t kpa; +#ifdef DEBUG + int *ste; + int opmapdebug = 0; +#endif + + for (pa = startpa; pa < endpa; pa += NBPG) { + struct kpt_page *kpt, **pkpt; + + /* + * Locate physical pages which are being used as kernel + * page table pages. + */ + pv = pa_to_pvh(pa); + if (pv->pv_pmap != pmap_kernel() || + !(pv->pv_flags & PV_PTPAGE)) + continue; + do { + if (pv->pv_ptste && pv->pv_ptpmap == pmap_kernel()) + break; + } while ((pv = pv->pv_next) > 0); + if (pv == NULL) + continue; +#ifdef DEBUG + if (pv->pv_va < (vaddr_t)Sysmap || + pv->pv_va >= (vaddr_t)Sysmap + AMIGA_KPTSIZE) + printf("collect: kernel PT VA out of range\n"); + else + goto ok; + pmap_pvdump(pa); + continue; +ok: +#endif + pte = (int *)(pv->pv_va + NBPG); + while (--pte >= (pt_entry_t *)pv->pv_va && *pte == PG_NV) + ; + if (pte >= (pt_entry_t *)pv->pv_va) + continue; + +#ifdef DEBUG + if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) { + printf( + "collect: freeing KPT page at %lx (ste %x@%p)\n", + pv->pv_va, *(int *)pv->pv_ptste, pv->pv_ptste); + opmapdebug = pmapdebug; + pmapdebug |= PDB_PTPAGE; + } + + ste = (int *)pv->pv_ptste; +#endif + /* + * If all entries were invalid we can remove the page. + * We call pmap_remove to take care of invalidating ST + * and Sysptmap entries. + */ + pmap_extract(pmap, pv->pv_va, &kpa); + pmap_remove_mapping(pmap, pv->pv_va, PT_ENTRY_NULL, + PRM_TFLUSH|PRM_CFLUSH); + + /* + * Use the physical address to locate the original + * (kmem_alloc assigned) address for the page and put + * that page back on the free list. + */ + for (pkpt = &kpt_used_list, kpt = *pkpt; + kpt != (struct kpt_page *)0; + pkpt = &kpt->kpt_next, kpt = *pkpt) + if (kpt->kpt_pa == kpa) + break; +#ifdef DEBUG + if (kpt == (struct kpt_page *)0) + panic("pmap_collect: lost a KPT page"); + if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) + printf("collect: %lx (%lx) to free list\n", + kpt->kpt_va, kpa); +#endif + *pkpt = kpt->kpt_next; + kpt->kpt_next = kpt_free_list; + kpt_free_list = kpt; +#ifdef DEBUG + kpt_stats.kptinuse--; + kpt_stats.collectpages++; + if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) + pmapdebug = opmapdebug; + + if (*ste) + printf("collect: kernel STE at %p still valid (%x)\n", + ste, *ste); + ste = + (int *)&Sysptmap[(u_int *)ste-pmap_ste(pmap_kernel(), 0)]; + if (*ste) + printf( + "collect: kernel PTmap at %p still valid (%x)\n", + ste, *ste); +#endif + } +} + +/* + * Mark that a processor is about to be used by a given pmap. + */ +void +pmap_activate(p) + struct proc *p; +{ + pmap_t pmap = p->p_vmspace->vm_map.pmap; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_SEGTAB)) + printf("pmap_activate(%p)\n", p); +#endif + PMAP_ACTIVATE(pmap, p == curproc); +} + +/* + * Mark that a processor is no longer in use by a given pmap. + */ +void +pmap_deactivate(p) + struct proc *p; +{ +} + +/* + * pmap_zero_page zeros the specified (machine independent) + * page by mapping the page into virtual memory and using + * bzero to clear its contents, one machine dependent page + * at a time. + */ +void +pmap_zero_page(phys) + paddr_t phys; +{ +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_zero_page(%lx)\n", phys); +#endif + phys >>= PG_SHIFT; + clearseg(phys); +} + +/* + * pmap_copy_page copies the specified (machine independent) + * page by mapping the page into virtual memory and using + * bcopy to copy the page, one machine dependent page at a + * time. + */ +void +pmap_copy_page(src, dst) + paddr_t src, dst; +{ +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_copy_page(%lx, %lx)\n", src, dst); +#endif + src >>= PG_SHIFT; + dst >>= PG_SHIFT; + physcopyseg(src, dst); +} + +/* + * Clear the modify bits on the specified physical page. + */ + +boolean_t +pmap_clear_modify(struct vm_page *pg) +{ + paddr_t pa = VM_PAGE_TO_PHYS(pg); + boolean_t ret; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_clear_modify(%lx)\n", pa); +#endif + ret = pmap_is_modified(pg); + + pmap_changebit(pa, PG_M, FALSE); + + return (ret); +} + +/* + * pmap_clear_reference: + * + * Clear the reference bit on the specified physical page. + */ + +boolean_t +pmap_clear_reference(struct vm_page *pg) +{ + paddr_t pa = VM_PAGE_TO_PHYS(pg); + boolean_t ret; +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_clear_reference(%lx)\n", pa); +#endif + ret = pmap_is_referenced(pg); + pmap_changebit(pa, PG_U, FALSE); + + return (ret); +} + +/* + * pmap_is_referenced: + * + * Return whether or not the specified physical page is referenced + * by any physical maps. + */ + +boolean_t +pmap_is_referenced(struct vm_page *pg) +{ + paddr_t pa = VM_PAGE_TO_PHYS(pg); +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) { + boolean_t rv = pmap_testbit(pa, PG_U); + printf("pmap_is_referenced(%lx) -> %c\n", pa, "FT"[rv]); + return (rv); + } +#endif + return (pmap_testbit(pa, PG_U)); +} + +/* + * pmap_is_modified: + * + * Return whether or not the specified physical page is modified + * by any physical maps. + */ + +boolean_t +pmap_is_modified(struct vm_page *pg) +{ + paddr_t pa = VM_PAGE_TO_PHYS(pg); +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) { + boolean_t rv = pmap_testbit(pa, PG_M); + printf("pmap_is_modified(%lx) -> %c\n", pa, "FT"[rv]); + return (rv); + } +#endif + return (pmap_testbit(pa, PG_M)); +} + +paddr_t +pmap_phys_address(ppn) + int ppn; +{ + return(m68k_ptob(ppn)); +} + +/* + * Miscellaneous support routines follow + */ + +/* + * pmap_remove_mapping: + * + * Invalidate a single page denoted by pmap/va. + * + * If (pte != NULL), it is the already computed PTE for the page. + * + * If (flags & PRM_TFLUSH), we must invalidate any TLB information. + * + * If (flags & PRM_CFLUSH), we must flush/invalidate any cache + * information. + * + * If (flags & PRM_KEEPPTPAGE), we don't free the page table page + * if the reference drops to zero. + */ +static void +pmap_remove_mapping(pmap, va, pte, flags) + pmap_t pmap; + vaddr_t va; + pt_entry_t *pte; + int flags; +{ + paddr_t pa; + struct pv_entry *pv, *npv; + pmap_t ptpmap; + st_entry_t *ste; + int s, bits; +#if defined(M68040) || defined(M68060) + int i; +#endif +#ifdef DEBUG + pt_entry_t opte; +#endif + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) + printf("pmap_remove_mapping(%p, %lx, %p, %x)\n", + pmap, va, pte, flags); +#endif + + /* + * PTE not provided, compute it from pmap and va. + */ + if (pte == PT_ENTRY_NULL) { + pte = pmap_pte(pmap, va); + if (*pte == PG_NV) + return; + } + + pa = pmap_pte_pa(pte); +#ifdef DEBUG + opte = *pte; +#endif + /* + * Update statistics + */ + if (pmap_pte_w(pte)) + pmap->pm_stats.wired_count--; + pmap->pm_stats.resident_count--; + + /* + * Invalidate the PTE after saving the reference modify info. + */ +#ifdef DEBUG + if (pmapdebug & PDB_REMOVE) + printf ("remove: invalidating pte at %p\n", pte); +#endif + + bits = *pte & (PG_U|PG_M); + *pte = PG_NV; + if ((flags & PRM_TFLUSH) && active_pmap(pmap)) + TBIS(va); + /* + * For user mappings decrement the wiring count on + * the PT page. + */ + if (pmap != pmap_kernel()) { + vaddr_t ptpva = trunc_page((vaddr_t)pte); + int refs = pmap_ptpage_delref(ptpva); +#ifdef DEBUG + if (pmapdebug & PDB_WIRING) + pmap_check_wiring("remove", ptpva); +#endif + /* + * If reference count drops to 1, and we're not instructed + * to keep it around, free the PT page. + * + * Note: refcnt == 1 comes from the fact that we allocate + * the page with uvm_fault_wire(), which initially wires + * the page. The first reference we actually add causes + * the refcnt to be 2. + */ + if (refs == 1 && (flags & PRM_KEEPPTPAGE) == 0) { + struct pv_entry *pv; + paddr_t pa; + + pa = pmap_pte_pa(pmap_pte(pmap_kernel(), ptpva)); +#ifdef DIAGNOSTIC + if (PAGE_IS_MANAGED(pa) == 0) + panic("pmap_remove_mapping: unmanaged PT page"); +#endif + pv = pa_to_pvh(pa); +#ifdef DIAGNOSTIC + if (pv->pv_ptste == NULL) + panic("pmap_remove_mapping: ptste == NULL"); + if (pv->pv_pmap != pmap_kernel() || + pv->pv_va != ptpva || + pv->pv_next != NULL) + panic("pmap_remove_mapping: " + "bad PT page pmap %p, va 0x%lx, next %p", + pv->pv_pmap, pv->pv_va, pv->pv_next); +#endif + pmap_remove_mapping(pv->pv_pmap, pv->pv_va, + NULL, PRM_TFLUSH|PRM_CFLUSH); + uvm_pagefree(PHYS_TO_VM_PAGE(pa)); +#ifdef DEBUG + if (pmapdebug & (PDB_REMOVE|PDB_PTPAGE)) + printf("remove: PT page 0x%lx (0x%lx) freed\n", + ptpva, pa); +#endif + } + } + + /* + * If this isn't a managed page, we are all done. + */ + if (PAGE_IS_MANAGED(pa) == 0) + return; + /* + * Otherwise remove it from the PV table + * (raise IPL since we may be called at interrupt time). + */ + pv = pa_to_pvh(pa); + ste = ST_ENTRY_NULL; + s = splimp(); + /* + * If it is the first entry on the list, it is actually + * in the header and we must copy the following entry up + * to the header. Otherwise we must search the list for + * the entry. In either case we free the now unused entry. + */ + if (pmap == pv->pv_pmap && va == pv->pv_va) { + ste = pv->pv_ptste; + ptpmap = pv->pv_ptpmap; + npv = pv->pv_next; + if (npv) { + npv->pv_flags = pv->pv_flags; + *pv = *npv; + pmap_free_pv(npv); + } else + pv->pv_pmap = NULL; +#ifdef DEBUG + remove_stats.pvfirst++; +#endif + } else { + for (npv = pv->pv_next; npv; npv = npv->pv_next) { +#ifdef DEBUG + remove_stats.pvsearch++; +#endif + if (pmap == npv->pv_pmap && va == npv->pv_va) + break; + pv = npv; + } +#ifdef DEBUG + if (npv == NULL) + panic("pmap_remove: PA not in pv_tab"); +#endif + ste = npv->pv_ptste; + ptpmap = npv->pv_ptpmap; + pv->pv_next = npv->pv_next; + pmap_free_pv(npv); + pv = pa_to_pvh(pa); + } + + /* + * If this was a PT page we must also remove the + * mapping from the associated segment table. + */ + if (ste) { +#ifdef DEBUG + remove_stats.ptinvalid++; + if (pmapdebug & (PDB_REMOVE|PDB_PTPAGE)) + printf("remove: ste was %x@%p pte was %x@%p\n", + *ste, ste, opte, pmap_pte(pmap, va)); +#endif +#if defined(M68040) || defined(M68060) + if (mmutype == MMU_68040) { + /* + * On the 68040, the PT page contains NPTEPG/SG4_LEV3SIZE + * page tables, so we need to remove all the associated + * segment table entries + * (This may be incorrect: if a single page table is + * being removed, the whole page should not be + * removed.) + */ + for (i = 0; i < NPTEPG / SG4_LEV3SIZE; ++i) + *ste++ = SG_NV; + ste -= NPTEPG / SG4_LEV3SIZE; +#ifdef DEBUG + if (pmapdebug &(PDB_REMOVE|PDB_SEGTAB|0x10000)) + printf("pmap_remove:PT at %lx removed\n", va); +#endif + } else +#endif /* defined(M68040) || defined(M68060) */ + *ste = SG_NV; + /* + * If it was a user PT page, we decrement the + * reference count on the segment table as well, + * freeing it if it is now empty. + */ + if (ptpmap != pmap_kernel()) { +#ifdef DEBUG + if (pmapdebug & (PDB_REMOVE|PDB_SEGTAB)) + printf("remove: stab %p, refcnt %d\n", + ptpmap->pm_stab, + ptpmap->pm_sref - 1); + if ((pmapdebug & PDB_PARANOIA) && + ptpmap->pm_stab != (st_entry_t *)trunc_page((vaddr_t)ste)) + panic("remove: bogus ste"); +#endif + if (--(ptpmap->pm_sref) == 0) { +#ifdef DEBUG + if (pmapdebug&(PDB_REMOVE|PDB_SEGTAB)) + printf("remove: free stab %p\n", + ptpmap->pm_stab); +#endif + uvm_km_free_wakeup(kernel_map, + (vaddr_t)ptpmap->pm_stab, AMIGA_STSIZE); + ptpmap->pm_stab = Segtabzero; + ptpmap->pm_stpa = Segtabzeropa; +#if defined(M68040) || defined(M68060) + if (mmutype == MMU_68040) + ptpmap->pm_stfree = protostfree; +#endif + /* + * XXX may have changed segment table + * pointer for current process so + * update now to reload hardware. + */ + if (active_user_pmap(ptpmap)) + PMAP_ACTIVATE(ptpmap, 1); + } +#ifdef DEBUG + else if (ptpmap->pm_sref < 0) + panic("remove: sref < 0"); +#endif + } +#if 0 + /* + * XXX this should be unnecessary as we have been + * flushing individual mappings as we go. + */ + if (ptpmap == pmap_kernel()) + TBIAS(); + else + TBIAU(); +#endif + pv->pv_flags &= ~PV_PTPAGE; + ptpmap->pm_ptpages--; + } + /* + * Update saved attributes for managed page + */ + *pa_to_attribute(pa) |= bits; + splx(s); +} + +/* + * pmap_ptpage_addref: + * + * Add a reference to the specified PT page. + */ +void +pmap_ptpage_addref(ptpva) + vaddr_t ptpva; +{ + struct vm_page *m; + + simple_lock(&uvm.kernel_object->vmobjlock); + m = uvm_pagelookup(uvm.kernel_object, ptpva - vm_map_min(kernel_map)); + m->wire_count++; + simple_unlock(&uvm.kernel_object->vmobjlock); +} + +/* + * pmap_ptpage_delref: + * + * Delete a reference to the specified PT page. + */ +int +pmap_ptpage_delref(ptpva) + vaddr_t ptpva; +{ + struct vm_page *m; + int rv; + + simple_lock(&uvm.kernel_object->vmobjlock); + m = uvm_pagelookup(uvm.kernel_object, ptpva - vm_map_min(kernel_map)); + rv = --m->wire_count; + simple_unlock(&uvm.kernel_object->vmobjlock); + return (rv); +} + +static void +amiga_protection_init() +{ + int *kp, prot; + + kp = protection_codes; + for (prot = 0; prot < 8; prot++) { + switch (prot) { + case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE: + *kp++ = 0; + break; + case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE: + case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE: + case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE: + *kp++ = PG_RO; + break; + case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE: + case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE: + case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE: + case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE: + *kp++ = PG_RW; + break; + } + } +} + +/* static */ +boolean_t +pmap_testbit(pa, bit) + paddr_t pa; + int bit; +{ + pv_entry_t pv; + int *pte; + int s; + + if (!PAGE_IS_MANAGED(pa)) + return (FALSE); + + pv = pa_to_pvh(pa); + s = splimp(); + /* + * Check saved info first + */ + if (*pa_to_attribute(pa) & bit) { + splx(s); + return (TRUE); + } + /* + * Not found, check current mappings returning + * immediately if found. + */ + if (pv->pv_pmap != NULL) { + for (; pv; pv = pv->pv_next) { + pte = (int *)pmap_pte(pv->pv_pmap, pv->pv_va); + if (*pte & bit) { + splx(s); + return (TRUE); + } + } + } + splx(s); + return (FALSE); +} + +static void +pmap_changebit(pa, bit, setem) + paddr_t pa; + int bit; + boolean_t setem; +{ + pv_entry_t pv; + int *pte, npte; + vaddr_t va; + boolean_t firstpage; + int s; + + firstpage = TRUE; + +#ifdef DEBUG + if (pmapdebug & PDB_BITS) + printf("pmap_changebit(%lx, %x, %s)\n", pa, bit, + setem ? "set" : "clear"); +#endif + if (!PAGE_IS_MANAGED(pa)) + return; + + pv = pa_to_pvh(pa); + s = splimp(); + /* + * Clear saved attributes (modify, reference) + */ + if (!setem) + *pa_to_attribute(pa) &= ~bit; + /* + * Loop over all current mappings setting/clearing as appropos + * If setting RO do we need to clear the VAC? + */ + if (pv->pv_pmap == NULL) { + splx(s); + return; + } + for (; pv; pv = pv->pv_next) { + va = pv->pv_va; + + /* + * XXX don't write protect pager mappings + */ + if (bit == PG_RO) { + if (va >= uvm.pager_sva && va < uvm.pager_eva) + continue; + } + + pte = (int *)pmap_pte(pv->pv_pmap, va); + if (setem) + npte = *pte | bit; + else + npte = *pte & ~bit; + if (*pte != npte) { + /* + * If we are changing caching status or + * protection make sure the caches are + * flushed (but only once). + */ +#if defined(M68040) || defined(M68060) + if (firstpage && mmutype == MMU_68040 && + ((bit == PG_RO && setem) || (bit & PG_CMASK))) { + firstpage = FALSE; + DCFP(pa); + ICPP(pa); + } +#endif + *pte = npte; + if (active_pmap(pv->pv_pmap)) + TBIS(va); + } + } + splx(s); +} + +/* static */ +void +pmap_enter_ptpage(pmap, va) + pmap_t pmap; + vaddr_t va; +{ + paddr_t ptpa; + pv_entry_t pv; +#ifdef M68060 + u_int stpa; +#endif + u_int *ste; + int s; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_ENTER|PDB_PTPAGE)) + printf("pmap_enter_ptpage: pmap %p, va %lx\n", pmap, va); + enter_stats.ptpneeded++; +#endif + /* + * Allocate a segment table if necessary. Note that it is allocated + * from kernel_map and not pt_map. This keeps user page tables + * aligned on segment boundaries in the kernel address space. + * The segment table is wired down. It will be freed whenever the + * reference count drops to zero. + */ + if (pmap->pm_stab == Segtabzero) { + /* XXX Atari uses kernel_map here: */ + pmap->pm_stab = (st_entry_t *) + uvm_km_zalloc(kernel_map, AMIGA_STSIZE); + pmap_extract(pmap_kernel(), (vaddr_t)pmap->pm_stab, + (paddr_t *)&pmap->pm_stpa); +#if defined(M68040) || defined(M68060) + if (mmutype == MMU_68040) { +#if defined(M68060) + stpa = (u_int)pmap->pm_stpa; + if (machineid & AMIGA_68060) { + while (stpa < (u_int)pmap->pm_stpa + + AMIGA_STSIZE) { + pmap_changebit(stpa, PG_CCB, 0); + pmap_changebit(stpa, PG_CI, 1); + stpa += NBPG; + } + DCIS(); /* XXX */ + } +#endif + pmap->pm_stfree = protostfree; + } +#endif + /* + * XXX may have changed segment table pointer for current + * process so update now to reload hardware. + */ + if (active_user_pmap(pmap)) + PMAP_ACTIVATE(pmap, 1); +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB)) + printf("enter_pt: pmap %p stab %p(%p)\n", pmap, + pmap->pm_stab, pmap->pm_stpa); +#endif + } + + ste = pmap_ste(pmap, va); + +#if defined(M68040) || defined(M68060) + /* + * Allocate level 2 descriptor block if necessary + */ + if (mmutype == MMU_68040) { + if (*ste == SG_NV) { + int ix; + caddr_t addr; + + ix = bmtol2(pmap->pm_stfree); + if (ix == -1) + panic("enter_pt: out of address space"); + pmap->pm_stfree &= ~l2tobm(ix); + addr = (caddr_t)&pmap->pm_stab[ix * SG4_LEV2SIZE]; + bzero(addr, SG4_LEV2SIZE * sizeof(st_entry_t)); + addr = (caddr_t)&pmap->pm_stpa[ix * SG4_LEV2SIZE]; + *ste = (u_int) addr | SG_RW | SG_U | SG_V; +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB)) + printf("enter_pt: alloc ste2 %d(%p)\n", ix, + addr); +#endif + } + ste = pmap_ste2(pmap, va); + /* + * Since a level 2 descriptor maps a block of SG4_LEV3SIZE + * level 3 descriptors, we need a chunk of NPTEPG/SEG4_LEV3SIZE + * (64) such descriptors (NBPG/SG4_LEV3SIZE bytes) to map a + * PT page -- the unit of allocation. We set 'ste' to point + * to the first entry of that chunk which is validated in its + * entirety below. + */ + ste = (u_int *)((int)ste & ~(NBPG / SG4_LEV3SIZE - 1)); +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB)) + printf("enter_pt: ste2 %p (%p)\n", pmap_ste2(pmap, va), + ste); +#endif + } +#endif + va = trunc_page((vaddr_t)pmap_pte(pmap, va)); + + /* + * In the kernel we allocate a page from the kernel PT page + * free list and map it into the kernel page table map (via + * pmap_enter). + */ + if (pmap == pmap_kernel()) { + struct kpt_page *kpt; + + s = splimp(); + if ((kpt = kpt_free_list) == (struct kpt_page *)0) { + /* + * No PT pages available. + * Try once to free up unused ones. + */ +#ifdef DEBUG + if (pmapdebug & PDB_COLLECT) + printf( + "enter_pt: no KPT pages, collecting...\n"); +#endif + pmap_collect(pmap_kernel()); + if ((kpt = kpt_free_list) == (struct kpt_page *)0) + panic("pmap_enter_ptpage: can't get KPT page"); + } +#ifdef DEBUG + if (++kpt_stats.kptinuse > kpt_stats.kptmaxuse) + kpt_stats.kptmaxuse = kpt_stats.kptinuse; +#endif + kpt_free_list = kpt->kpt_next; + kpt->kpt_next = kpt_used_list; + kpt_used_list = kpt; + ptpa = kpt->kpt_pa; + bzero((char *)kpt->kpt_va, NBPG); + pmap_enter(pmap, va, ptpa, VM_PROT_DEFAULT, + VM_PROT_DEFAULT|PMAP_WIRED); +#if defined(M68060) + if (machineid & AMIGA_68060) { + pmap_changebit(ptpa, PG_CCB, 0); + pmap_changebit(ptpa, PG_CI, 1); + DCIS(); + } +#endif +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE)) + printf( + "enter_pt: add &Sysptmap[%d]: %x (KPT page %lx)\n", + ste - pmap_ste(pmap, 0), + *(int *)&Sysptmap[ste - pmap_ste(pmap, 0)], + kpt->kpt_va); +#endif + splx(s); + } + /* + * For user processes we just simulate a fault on that location + * letting the VM system allocate a zero-filled page. + * + * Note we use a wire-fault to keep the page off the paging + * queues. This sets our PT page's reference (wire) count to + * 1, which is what we use to check if the page can be freed. + * See pmap_remove_mapping(). + */ + else { + /* + * Count the segment table reference now so that we won't + * lose the segment table when low on memory. + */ + pmap->pm_sref++; +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE)) + printf("enter_pt: about to fault UPT pg at %lx\n", va); +#endif + s = uvm_fault_wire(pt_map, va, va + PAGE_SIZE, + VM_PROT_READ|VM_PROT_WRITE); + if (s) { + printf("uvm_fault_wire(pt_map, 0x%lx, 0%lx, RW) " + "-> %d\n", va, va + PAGE_SIZE, s); + panic("pmap_enter: uvm_fault_wire failed"); + } + ptpa = pmap_pte_pa(pmap_pte(pmap_kernel(), va)); +#if 0 /* XXXX what is this? XXXX */ + /* + * Mark the page clean now to avoid its pageout (and + * hence creation of a pager) between now and when it + * is wired; i.e. while it is on a paging queue. + */ + PHYS_TO_VM_PAGE(ptpa)->flags |= PG_CLEAN; +#endif + } + +#ifdef M68060 + if (machineid & M68060) { + pmap_changebit(ptpa, PG_CCB, 0); + pmap_changebit(ptpa, PG_CI, 1); + DCIS(); + } +#endif + /* + * Locate the PV entry in the kernel for this PT page and + * record the STE address. This is so that we can invalidate + * the STE when we remove the mapping for the page. + */ + pv = pa_to_pvh(ptpa); + s = splimp(); + if (pv) { + pv->pv_flags |= PV_PTPAGE; + do { + if (pv->pv_pmap == pmap_kernel() && pv->pv_va == va) + break; + } while ((pv = pv->pv_next) > 0); + } +#ifdef DEBUG + if (pv == NULL) { + printf("enter_pt: PV entry for PT page %lx not found\n", ptpa); + panic("pmap_enter_ptpage: PT page not entered"); + } +#endif + pv->pv_ptste = ste; + pv->pv_ptpmap = pmap; +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE)) + printf("enter_pt: new PT page at PA %lx, ste at %p\n", ptpa, + ste); +#endif + + /* + * Map the new PT page into the segment table. + * Also increment the reference count on the segment table if this + * was a user page table page. Note that we don't use vm_map_pageable + * to keep the count like we do for PT pages, this is mostly because + * it would be difficult to identify ST pages in pmap_pageable to + * release them. We also avoid the overhead of vm_map_pageable. + */ +#if defined(M68040) || defined(M68060) + if (mmutype == MMU_68040) { + u_int *este; + + for (este = &ste[NPTEPG / SG4_LEV3SIZE]; ste < este; ++ste) { + *ste = ptpa | SG_U | SG_RW | SG_V; + ptpa += SG4_LEV3SIZE * sizeof(st_entry_t); + } + } + else +#endif + *(int *)ste = (ptpa & SG_FRAME) | SG_RW | SG_V; + if (pmap != pmap_kernel()) { +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB)) + printf("enter_pt: stab %p refcnt %d\n", pmap->pm_stab, + pmap->pm_sref); +#endif + } + /* + * Flush stale TLB info. + */ + if (pmap == pmap_kernel()) + TBIAS(); + else + TBIAU(); + pmap->pm_ptpages++; + splx(s); +} + +#ifdef DEBUG +void +pmap_pvdump(pa) + paddr_t pa; +{ + pv_entry_t pv; + + printf("pa %lx", pa); + for (pv = pa_to_pvh(pa); pv; pv = pv->pv_next) + printf(" -> pmap %p, va %lx, ptste %p, ptpmap %p, flags %x", + pv->pv_pmap, pv->pv_va, pv->pv_ptste, pv->pv_ptpmap, + pv->pv_flags); + printf("\n"); +} + +/* + * pmap_check_wiring: + * + * Count the number of valid mappings in the specified PT page, + * and ensure that it is consistent with the number of wirings + * to that page that the VM system has. + */ +void +pmap_check_wiring(str, va) + char *str; + vaddr_t va; +{ + pt_entry_t *pte; + paddr_t pa; + struct vm_page *m; + int count; + + if (!pmap_ste_v(pmap_kernel(), va) || + !pmap_pte_v(pmap_pte(pmap_kernel(), va))) + return; + + pa = pmap_pte_pa(pmap_pte(pmap_kernel(), va)); + m = PHYS_TO_VM_PAGE(pa); + if (m->wire_count < 1) { + printf("*%s*: 0x%lx: wire count %d\n", str, va, m->wire_count); + return; + } + + count = 0; + for (pte = (pt_entry_t *)va; pte < (pt_entry_t *)(va + NBPG); pte++) + if (*pte) + count++; + if ((m->wire_count - 1) != count) + printf("*%s*: 0x%lx: w%d/a%d\n", + str, va, (m->wire_count-1), count); +} +#endif + +/* + * Routine: pmap_virtual_space + * + * Function: + * Report the range of available kernel virtual address + * space to the VM system during bootstrap. Called by + * vm_bootstrap_steal_memory(). + */ +void +pmap_virtual_space(vstartp, vendp) + vaddr_t *vstartp, *vendp; +{ + + *vstartp = virtual_avail; + *vendp = virtual_end; +} + +void +pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot) +{ + pmap_enter(pmap_kernel(), va, pa, prot, + VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED); +} + +void +pmap_kremove(vaddr_t va, vsize_t len) +{ + for (len >>= PAGE_SHIFT; len > 0; len--, va += PAGE_SIZE) { + pmap_remove(pmap_kernel(), va, va + PAGE_SIZE); + } +} diff --git a/sys/arch/amiga/amiga/pmap_bootstrap.c b/sys/arch/amiga/amiga/pmap_bootstrap.c deleted file mode 100644 index 03636122ba0..00000000000 --- a/sys/arch/amiga/amiga/pmap_bootstrap.c +++ /dev/null @@ -1,248 +0,0 @@ -/* $OpenBSD: pmap_bootstrap.c,v 1.2 2001/12/14 21:44:02 miod Exp $ */ -/* $NetBSD: pmap.c,v 1.68 1999/06/19 19:44:09 is Exp $ */ - -/*- - * Copyright (c) 1999 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Jason R. Thorpe. - * - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation 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 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) 1991 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. - * - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. 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 7.5 (Berkeley) 5/10/91 - */ - -/* - * AMIGA physical map management code, the bootstrap part. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/malloc.h> -#include <sys/msgbuf.h> -#include <sys/user.h> -#include <uvm/uvm.h> -#include <machine/cpu.h> -#include <machine/vmparam.h> -#include <amiga/amiga/memlist.h> - -extern paddr_t msgbufpa; /* physical address of the msgbuf */ -extern paddr_t z2mem_start; - -u_long noncontig_enable; -caddr_t CADDR1, CADDR2, vmmap; -u_int *Sysseg_pa; - -extern vm_offset_t virtual_avail, virtual_end; -extern st_entry_t *Sysseg; -#if defined(M68040) || defined(M68060) -extern int protostfree; -#endif - -extern vaddr_t reserve_dumppages __P((vaddr_t)); - -/* - * Bootstrap the system enough to run with virtual memory. - * Map the kernel's code and data, and allocate the system page table. - * - * On the HP this is called after mapping has already been enabled - * and just syncs the pmap module with what has already been done. - * [We can't call it easily with mapping off since the kernel is not - * mapped with PA == VA, hence we would have to relocate every address - * from the linked base (virtual) address 0 to the actual (physical) - * address of 0xFFxxxxxx.] - */ -void -pmap_bootstrap(firstaddr, loadaddr) - paddr_t firstaddr; - paddr_t loadaddr; -{ - vaddr_t va; - int i; - struct boot_memseg *sp, *esp; - paddr_t fromads, toads; - - fromads = firstaddr; - toads = maxmem << PGSHIFT; - - uvmexp.pagesize = NBPG; - uvm_setpagesize(); - - /* XXX: allow for msgbuf */ - toads -= m68k_round_page(MSGBUFSIZE); - msgbufpa = toads; - - /* - * first segment of memory is always the one loadbsd found - * for loading the kernel into. - */ - uvm_page_physload(atop(fromads), atop(toads), - atop(fromads), atop(toads), VM_FREELIST_DEFAULT); - - sp = memlist->m_seg; - esp = sp + memlist->m_nseg; - i = 1; - for (; noncontig_enable && sp < esp; sp++) { - if ((sp->ms_attrib & MEMF_FAST) == 0) - continue; /* skip if not FastMem */ - if (firstaddr >= sp->ms_start && - firstaddr < sp->ms_start + sp->ms_size) - continue; /* skip kernel segment */ - if (sp->ms_size == 0) - continue; /* skip zero size segments */ - fromads = sp->ms_start; - toads = sp->ms_start + sp->ms_size; -#ifdef DEBUG_A4000 - /* - * My A4000 doesn't seem to like Zorro II memory - this - * hack is to skip the motherboard memory and use the - * Zorro II memory. Only for trying to debug the problem. - * Michael L. Hitch - */ - if (toads == 0x08000000) - continue; /* skip A4000 motherboard mem */ -#endif - /* - * Deal with Zorro II memory stolen for DMA bounce buffers. - * This needs to be handled better. - * - * XXX is: disabled. This is handled now in amiga_init.c - * by removing the stolen memory from the memlist. - * - * XXX is: enabled again, but check real size and position. - * We check z2mem_start is in this segment, and set its end - * to the z2mem_start. - * - */ - if ((fromads <= z2mem_start) && (toads > z2mem_start)) - toads = z2mem_start; - - uvm_page_physload(atop(fromads), atop(toads), - atop(fromads), atop(toads), (fromads & 0xff000000) ? - VM_FREELIST_DEFAULT : VM_FREELIST_ZORROII); - physmem += (toads - fromads) / NBPG; - ++i; - if (noncontig_enable == 1) - break; /* Only two segments enabled */ - } - - mem_size = physmem << PGSHIFT; - virtual_avail = VM_MIN_KERNEL_ADDRESS + (firstaddr - loadaddr); - virtual_end = VM_MAX_KERNEL_ADDRESS; - - /* - * Kernel page/segment table allocated in locore, - * just initialize pointers. - */ - pmap_kernel()->pm_stab = Sysseg; - pmap_kernel()->pm_ptab = Sysmap; - simple_lock_init(&pmap_kernel()->pm_lock); - pmap_kernel()->pm_count = 1; - pmap_kernel()->pm_stpa = Sysseg_pa; -#if defined(M68040) || defined(M68060) - if (mmutype <= MMU_68040) { - pmap_kernel()->pm_stfree = protostfree; - } -#endif - - /* - * Allocate all the submaps we need - */ - va = virtual_avail; - - vmmap = (caddr_t)va; - va += NBPG; - - msgbufp = (struct msgbuf *)va; - va += btoc(MSGBUFSIZE); - - DCIS(); - virtual_avail = reserve_dumppages(va); -} - -void -pmap_init_md() -{ - extern vaddr_t amigahwaddr; - extern u_int namigahwpg; - vaddr_t addr; - - /* - * Now that kernel map has been allocated, we can mark as - * unavailable regions which we have mapped in locore. - * XXX in pmap_boostrap() ??? - */ - addr = (vaddr_t) amigahwaddr; - if (uvm_map(kernel_map, &addr, - ptoa(namigahwpg), - NULL, UVM_UNKNOWN_OFFSET, 0, - UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, - UVM_INH_NONE, UVM_ADV_RANDOM, - UVM_FLAG_FIXED))) - panic("pmap_init: bogons in the VM system!\n"); -} diff --git a/sys/arch/amiga/conf/files.amiga b/sys/arch/amiga/conf/files.amiga index debb4f9e287..e99963f82e4 100644 --- a/sys/arch/amiga/conf/files.amiga +++ b/sys/arch/amiga/conf/files.amiga @@ -1,4 +1,4 @@ -# $OpenBSD: files.amiga,v 1.46 2001/11/30 23:19:27 miod Exp $ +# $OpenBSD: files.amiga,v 1.47 2001/12/20 19:02:26 miod Exp $ # $NetBSD: files.amiga,v 1.62 1997/08/27 19:32:47 is Exp $ @@ -359,8 +359,7 @@ file arch/amiga/amiga/disksubr.c file arch/amiga/amiga/dkbad.c file arch/amiga/amiga/machdep.c file arch/amiga/amiga/mem.c -file arch/m68k/m68k/pmap_motorola.c -file arch/amiga/amiga/pmap_bootstrap.c +file arch/amiga/amiga/pmap.c file arch/amiga/amiga/sys_machdep.c file arch/amiga/amiga/trap.c file arch/amiga/amiga/vm_machdep.c diff --git a/sys/arch/amiga/include/cpu.h b/sys/arch/amiga/include/cpu.h index 1e711202f62..518399a7f95 100644 --- a/sys/arch/amiga/include/cpu.h +++ b/sys/arch/amiga/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.16 2001/12/07 00:59:16 miod Exp $ */ +/* $OpenBSD: cpu.h,v 1.17 2001/12/20 19:02:26 miod Exp $ */ /* $NetBSD: cpu.h,v 1.36 1996/09/11 00:11:42 thorpej Exp $ */ /* @@ -184,10 +184,12 @@ struct fpframe; struct user; struct pcb; +void clearseg __P((vm_offset_t)); void doboot __P((void)) __attribute__((__noreturn__)); void loadustp __P((int)); void m68881_save __P((struct fpframe *)); void m68881_restore __P((struct fpframe *)); +void physcopyseg __P((vm_offset_t, vm_offset_t)); u_int probeva __P((u_int, u_int)); void proc_trampoline __P((void)); void savectx __P((struct pcb *)); diff --git a/sys/arch/amiga/include/param.h b/sys/arch/amiga/include/param.h index c7bb979d23a..656303d5957 100644 --- a/sys/arch/amiga/include/param.h +++ b/sys/arch/amiga/include/param.h @@ -1,4 +1,4 @@ -/* $OpenBSD: param.h,v 1.18 2001/12/05 01:57:14 provos Exp $ */ +/* $OpenBSD: param.h,v 1.19 2001/12/20 19:02:26 miod Exp $ */ /* $NetBSD: param.h,v 1.35 1997/07/10 08:22:36 veego Exp $ */ /* @@ -60,6 +60,15 @@ #define KERNBASE 0x00000000 /* start of kernel virtual */ +#define SEGSHIFT 24 /* LOG2(NBSEG) [68030 value] */ +/* bytes/segment */ +/* (256 * (1 << PGSHIFT)) == (1 << SEGSHIFT) */ +#define NBSEG ((mmutype == MMU_68040) \ + ? (32 * (1 << PGSHIFT)) : (256 * (1 << PGSHIFT))) +#define SEGOFSET (NBSEG-1) /* byte offset into segment */ + +#define UPAGES 2 /* pages of u-area */ + #include <m68k/param.h> #define NPTEPG (NBPG/(sizeof (pt_entry_t))) diff --git a/sys/arch/amiga/include/pmap.h b/sys/arch/amiga/include/pmap.h index 7e40c742b75..a4fa87f48f6 100644 --- a/sys/arch/amiga/include/pmap.h +++ b/sys/arch/amiga/include/pmap.h @@ -1,13 +1,142 @@ -/* $OpenBSD: pmap.h,v 1.10 2001/11/30 23:20:09 miod Exp $ */ +/* $OpenBSD: pmap.h,v 1.11 2001/12/20 19:02:26 miod Exp $ */ +/* $NetBSD: pmap.h,v 1.17 1997/06/10 18:34:52 veego Exp $ */ +/* + * Copyright (c) 1987 Carnegie-Mellon University + * Copyright (c) 1991 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. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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.h 7.6 (Berkeley) 5/10/91 + */ #ifndef _MACHINE_PMAP_H_ #define _MACHINE_PMAP_H_ -#include <m68k/pmap_motorola.h> +/* + * Pmap stuff + */ +struct pmap { + pt_entry_t *pm_ptab; /* KVA of page table */ + st_entry_t *pm_stab; /* KVA of segment table */ + int pm_stfree; /* 040: free lev2 blocks */ + u_int *pm_stpa; /* 040: ST phys addr */ + short pm_sref; /* segment table ref count */ + short pm_count; /* pmap reference count */ + long pm_ptpages; /* more stats: PT pages */ + struct simplelock pm_lock; /* lock on pmap */ + struct pmap_statistics pm_stats; /* pmap statistics */ +}; + +typedef struct pmap *pmap_t; + +/* + * On the 040 we keep track of which level 2 blocks are already in use + * with the pm_stfree mask. Bits are arranged from LSB (block 0) to MSB + * (block 31). For convenience, the level 1 table is considered to be + * block 0. + * + * MAX[KU]L2SIZE control how many pages of level 2 descriptors are allowed. + * for the kernel and users. 16 implies only the initial "segment table" + * page is used. WARNING: don't change MAXUL2SIZE unless you can allocate + * physically contiguous pages for the ST in pmap.c! + */ +#define MAXKL2SIZE 32 +#define MAXUL2SIZE 16 +#define l2tobm(n) (1 << (n)) +#define bmtol2(n) (ffs(n) - 1) + +/* + * Macros for speed + */ +#define PMAP_ACTIVATE(pmap, loadhw) \ +{ \ + if ((loadhw)) \ + loadustp(m68k_btop((pmap)->pm_stpa)); \ +} + +/* + * For each vm_page_t, there is a list of all currently valid virtual + * mappings of that page. An entry is a pv_entry_t, the list is pv_table. + */ +typedef struct pv_entry { + struct pv_entry *pv_next; /* next pv_entry */ + struct pmap *pv_pmap; /* pmap where mapping lies */ + vm_offset_t pv_va; /* virtual address for mapping */ + u_int *pv_ptste; /* non-zero if VA maps a PT page */ + struct pmap *pv_ptpmap; /* if pv_ptste, pmap for PT page */ + int pv_flags; /* flags */ +} *pv_entry_t; + +#define PV_CI 0x01 /* all entries must be cache inhibited */ +#define PV_PTPAGE 0x02 /* entry maps a page table page */ + +struct pv_page; + +struct pv_page_info { + TAILQ_ENTRY(pv_page) pgi_list; + struct pv_entry *pgi_freelist; + int pgi_nfree; +}; + +/* + * This is basically: + * ((NBPG - sizeof(struct pv_page_info)) / sizeof(struct pv_entry)) + */ +#define NPVPPG 340 + +struct pv_page { + struct pv_page_info pvp_pgi; + struct pv_entry pvp_pv[NPVPPG]; +}; #ifdef _KERNEL -void pmap_init_md __P((void)); -#define PMAP_INIT_MD() pmap_init_md() -#endif +pv_entry_t pv_table; /* array of entries, one per page */ +u_int *Sysmap; +char *vmmap; /* map for mem, dumps, etc. */ +struct pmap kernel_pmap_store; + +#define pmap_kernel() (&kernel_pmap_store) +#define active_pmap(pm) \ + ((pm) == pmap_kernel() || (pm) == curproc->p_vmspace->vm_map.pmap) +#define active_user_pmap(pm) \ + (curproc && \ + (pm) != pmap_kernel() && (pm) == curproc->p_vmspace->vm_map.pmap) + +#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count) +#define pmap_wired_count(pmap) ((pmap)->pm_stats.wired_count) +#define pmap_update(pmap) /* nothing */ + +#endif /* _KERNEL */ -#endif /* _MACHINE_PMAP_H_ */ +#endif /* !_MACHINE_PMAP_H_ */ diff --git a/sys/arch/amiga/include/pte.h b/sys/arch/amiga/include/pte.h index 9a6d5d146a8..a5acfc91685 100644 --- a/sys/arch/amiga/include/pte.h +++ b/sys/arch/amiga/include/pte.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pte.h,v 1.4 2001/12/06 22:33:18 miod Exp $ */ +/* $OpenBSD: pte.h,v 1.5 2001/12/20 19:02:26 miod Exp $ */ /* $NetBSD: pte.h,v 1.14 1995/09/29 13:52:09 chopps Exp $ */ /* @@ -45,12 +45,72 @@ #ifndef _MACHINE_PTE_H_ #define _MACHINE_PTE_H_ -#include <m68k/pte_motorola.h> +/* + * AMIGA hardware segment/page table entries + */ + +struct pte { + u_int pte; +}; +typedef u_int pt_entry_t; /* Mach page table entry */ + +struct ste { + u_int ste; +}; +typedef u_int st_entry_t; /* segment table entry */ + +#define PT_ENTRY_NULL ((pt_entry_t *) 0) +#define ST_ENTRY_NULL ((st_entry_t *) 0) + +#define SG_V 0x00000002 /* segment is valid */ +#define SG_NV 0x00000000 +#define SG_PROT 0x00000004 /* access protection mask */ +#define SG_RO 0x00000004 +#define SG_RW 0x00000000 +#define SG_U 0x00000008 /* modified bit (68040) */ +#define SG_FRAME 0xffffe000 +#define SG_IMASK 0xff000000 +#define SG_ISHIFT 24 +#define SG_PMASK 0x00ffe000 +#define SG_PSHIFT 13 + +/* 68040 additions */ +#define SG4_MASK1 0xfe000000 /* pointer table 1 index mask */ +#define SG4_SHIFT1 25 +#define SG4_MASK2 0x01fc0000 /* pointer table 2 index mask */ +#define SG4_SHIFT2 18 +#define SG4_MASK3 0x0003e000 /* page table index mask */ +#define SG4_SHIFT3 13 +#define SG4_ADDR1 0xfffffe00 /* pointer table address mask */ +#define SG4_ADDR2 0xffffff80 /* page table address mask */ +#define SG4_LEV1SIZE 128 /* entries in pointer table 1 */ +#define SG4_LEV2SIZE 128 /* entries in pointer table 2 */ +#define SG4_LEV3SIZE 32 /* entries in page table */ + +#define PG_V 0x00000001 +#define PG_NV 0x00000000 +#define PG_PROT 0x00000004 +#define PG_U 0x00000008 +#define PG_M 0x00000010 +#define PG_W 0x00000100 +#define PG_RO 0x00000004 +#define PG_RW 0x00000000 +#define PG_FRAME 0xffffe000 +#define PG_CI 0x00000040 +#define PG_SHIFT 13 +#define PG_PFNUM(x) (((x) & PG_FRAME) >> PG_SHIFT) + +/* 68040 additions */ +#define PG_CMASK 0x00000060 /* cache mode mask */ +#define PG_CWT 0x00000000 /* writethrough caching */ +#define PG_CCB 0x00000020 /* copyback caching */ +#define PG_CIS 0x00000040 /* cache inhibited serialized */ +#define PG_CIN 0x00000060 /* cache inhibited nonserialized */ +#define PG_SO 0x00000080 /* supervisor only */ #define AMIGA_040RTSIZE 512 /* root (level 1) table size */ #define AMIGA_040STSIZE 512 /* segment (level 2) table size */ #define AMIGA_040PTSIZE 128 /* page (level 3) table size */ - #if 0 #define AMIGA_STSIZE 1024 /* segment table size */ #else @@ -65,10 +125,9 @@ * AMIGA_MAX_KPTSIZE the most number of bytes for kpt pages * AMIGA_MAX_PTSIZE the number of bytes to map everything */ -extern vaddr_t amiga_uptbase; #define AMIGA_MAX_COREUPT 1024 #define AMIGA_UPTSIZE roundup(VM_MAXUSER_ADDRESS / NPTEPG, NBPG) -#define AMIGA_UPTBASE amiga_uptbase +#define AMIGA_UPTBASE 0x10000000 #define AMIGA_UPTMAXSIZE \ roundup((AMIGA_MAX_COREUPT * AMIGA_UPTSIZE), NBPG) #define AMIGA_MAX_KPTSIZE \ @@ -77,10 +136,15 @@ extern vaddr_t amiga_uptbase; roundup((VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) / NPTEPG, NBPG) #define AMIGA_MAX_PTSIZE roundup(0xffffffff / NPTEPG, NBPG) -#define MACHINE_STSIZE AMIGA_STSIZE -#define MACHINE_MAX_PTSIZE AMIGA_MAX_PTSIZE -#define MACHINE_MAX_KPTSIZE AMIGA_MAX_KPTSIZE -#define MACHINE_PTBASE AMIGA_UPTBASE -#define MACHINE_PTMAXSIZE AMIGA_UPTMAXSIZE +/* + * Kernel virtual address to page table entry and to physical address. + */ +#define kvtopte(va) \ + (&Sysmap[((unsigned)(va) - VM_MIN_KERNEL_ADDRESS) >> PGSHIFT]) +#define ptetokv(pt) \ + ((((u_int *)(pt) - Sysmap) << PGSHIFT) + VM_MIN_KERNEL_ADDRESS) +#define kvtophys(va) \ + ((kvtopte(va)->pg_pfnum << PGSHIFT) | ((int)(va) & PGOFSET)) + #endif /* !_MACHINE_PTE_H_ */ diff --git a/sys/arch/hp300/conf/files.hp300 b/sys/arch/hp300/conf/files.hp300 index 135a4fe1ef6..89dc04b6758 100644 --- a/sys/arch/hp300/conf/files.hp300 +++ b/sys/arch/hp300/conf/files.hp300 @@ -1,4 +1,4 @@ -# $OpenBSD: files.hp300,v 1.17 2001/11/30 20:58:14 miod Exp $ +# $OpenBSD: files.hp300,v 1.18 2001/12/20 19:02:27 miod Exp $ # $NetBSD: files.hp300,v 1.28 1997/05/12 08:23:28 thorpej Exp $ # # hp300-specific configuration info @@ -187,7 +187,7 @@ file arch/hp300/hp300/machdep.c file arch/hp300/hp300/intr.c file arch/hp300/hp300/leds.c useleds file arch/hp300/hp300/mem.c -file arch/m68k/m68k/pmap_motorola.c +file arch/hp300/hp300/pmap.c file arch/hp300/hp300/pmap_bootstrap.c file arch/hp300/hp300/sys_machdep.c file arch/hp300/hp300/trap.c diff --git a/sys/arch/m68k/m68k/pmap_motorola.c b/sys/arch/hp300/hp300/pmap.c index 06058c3d402..0fde6c99c88 100644 --- a/sys/arch/m68k/m68k/pmap_motorola.c +++ b/sys/arch/hp300/hp300/pmap.c @@ -1,6 +1,7 @@ -/* $OpenBSD: pmap_motorola.c,v 1.13 2001/12/16 23:06:04 miod Exp $ */ +/* $OpenBSD: pmap.c,v 1.38 2001/12/20 19:02:27 miod Exp $ */ +/* $NetBSD: pmap.c,v 1.80 1999/09/16 14:52:06 chs Exp $ */ -/* +/*- * Copyright (c) 1999 The NetBSD Foundation, Inc. * All rights reserved. * @@ -37,37 +38,6 @@ */ /* - * Copyright (c) 1995 Theo de Raadt - * - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed under OpenBSD by - * Theo de Raadt for Willowglen Singapore. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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) 1991, 1993 * The Regents of the University of California. All rights reserved. * @@ -107,14 +77,13 @@ */ /* - * m68k series physical map management code. + * HP9000/300 series physical map management code. * * Supports: - * 68020 with HP MMU - * 68020 with 68851 MMU - * 68030 with on-chip MMU - * 68040 with on-chip MMU - * 68060 with on-chip MMU + * 68020 with HP MMU models 320, 350 + * 68020 with 68851 MMU models 318, 319, 330 + * 68030 with on-chip MMU models 340, 360, 370, 345, 375, 400 + * 68040 with on-chip MMU models 380, 385, 425, 433 * * Notes: * Don't even pay lip service to multiprocessor support. @@ -171,7 +140,6 @@ #include <machine/pte.h> -/* #define UVM_PAGE_INLINE */ #include <uvm/uvm.h> #include <machine/cpu.h> @@ -192,25 +160,24 @@ #define PDB_PARANOIA 0x2000 #define PDB_WIRING 0x4000 #define PDB_PVDUMP 0x8000 -#define PDB_ALL 0xFFFF int debugmap = 0; int pmapdebug = PDB_PARANOIA; #define PMAP_DPRINTF(l, x) if (pmapdebug & (l)) printf x -#if defined(M68040) || defined(M68060) +#if defined(M68040) int dowriteback = 1; /* 68040: enable writeback caching */ int dokwriteback = 1; /* 68040: enable writeback caching of kernel AS */ #endif -#else +#else /* ! DEBUG */ #define PMAP_DPRINTF(l, x) /* nothing */ -#endif /* DEBUG */ +#endif /* DEBUG */ /* * Get STEs and PTEs for user/kernel address space */ -#if defined(M68040) || defined(M68060) +#if defined(M68040) #define pmap_ste1(m, v) \ (&((m)->pm_stab[(vaddr_t)(v) >> SG4_SHIFT1])) /* XXX assumes physically contiguous ST pages (if more than one) */ @@ -219,9 +186,9 @@ int dokwriteback = 1; /* 68040: enable writeback caching of kernel AS */ - (m)->pm_stpa + (((v) & SG4_MASK2) >> SG4_SHIFT2)])) #define pmap_ste(m, v) \ (&((m)->pm_stab[(vaddr_t)(v) \ - >> (mmutype <= MMU_68040 ? SG4_SHIFT1 : SG_ISHIFT)])) + >> (mmutype == MMU_68040 ? SG4_SHIFT1 : SG_ISHIFT)])) #define pmap_ste_v(m, v) \ - (mmutype <= MMU_68040 \ + (mmutype == MMU_68040 \ ? ((*pmap_ste1(m, v) & SG_V) && \ (*pmap_ste2(m, v) & SG_V)) \ : (*pmap_ste(m, v) & SG_V)) @@ -248,9 +215,10 @@ int dokwriteback = 1; /* 68040: enable writeback caching of kernel AS */ /* * Given a map and a machine independent protection code, - * convert to an m68k protection code. + * convert to an hp300 protection code. */ -#define pte_prot(p) ((p) & VM_PROT_WRITE ? PG_RW : PG_RO) +#define pte_prot(m, p) (protection_codes[p]) +int protection_codes[8]; /* * Kernel page table page management. @@ -277,16 +245,11 @@ pt_entry_t *Sysmap, *Sysptmap; st_entry_t *Segtabzero, *Segtabzeropa; vsize_t Sysptsize = VM_KERNEL_PT_PAGES; -extern caddr_t CADDR1, CADDR2; - -pt_entry_t *caddr1_pte; /* PTE for CADDR1 */ -pt_entry_t *caddr2_pte; /* PTE for CADDR2 */ - struct pmap kernel_pmap_store; struct vm_map *st_map, *pt_map; struct vm_map st_map_store, pt_map_store; -paddr_t avail_start; /* PA of first available physical page */ +paddr_t avail_start; /* PA of first available physical page */ paddr_t avail_end; /* PA of last available physical page */ vsize_t mem_size; /* memory size in bytes */ vaddr_t virtual_avail; /* VA of first avail page (after kernel bss)*/ @@ -299,47 +262,29 @@ char *pmap_attributes; /* reference and modify bits */ TAILQ_HEAD(pv_page_list, pv_page) pv_page_freelist; int pv_nfree; -#if defined(M68K_MMU_HP) -int pmap_aliasmask; /* separation at which VA aliasing is ok */ +#ifdef M68K_MMU_HP +int pmap_aliasmask; /* seperation at which VA aliasing ok */ #endif -#if defined(M68040) || defined(M68060) +#if defined(M68040) int protostfree; /* prototype (default) free ST map */ #endif -struct pool pmap_pmap_pool; /* memory pool for pmap structures */ - -/* - * Internal routines - */ -struct pv_entry *pmap_alloc_pv __P((void)); -void pmap_free_pv __P((struct pv_entry *)); -void pmap_collect_pv __P((void)); -#ifdef COMPAT_HPUX -int pmap_mapmulti __P((pmap_t, vaddr_t)); -#endif -void pmap_remove_mapping __P((pmap_t, vaddr_t, pt_entry_t *, int)); -boolean_t pmap_testbit __P((paddr_t, int)); -void pmap_changebit __P((paddr_t, int, int)); -void pmap_enter_ptpage __P((pmap_t, vaddr_t)); -void pmap_ptpage_addref __P((vaddr_t)); -int pmap_ptpage_delref __P((vaddr_t)); -void pmap_collect1 __P((pmap_t, paddr_t, paddr_t)); -void pmap_pinit __P((pmap_t)); -void pmap_release __P((pmap_t)); +extern caddr_t CADDR1, CADDR2; +pt_entry_t *caddr1_pte; /* PTE for CADDR1 */ +pt_entry_t *caddr2_pte; /* PTE for CADDR2 */ -#ifdef DEBUG -void pmap_pvdump __P((paddr_t)); -void pmap_check_wiring __P((char *, vaddr_t)); -#endif +struct pool pmap_pmap_pool; /* memory pool for pmap structures */ -/* pmap_remove_mapping flags */ -#define PRM_TFLUSH 1 -#define PRM_CFLUSH 2 -#define PRM_KEEPPTPAGE 4 +struct pv_entry *pmap_alloc_pv __P((void)); +void pmap_free_pv __P((struct pv_entry *)); +void pmap_collect_pv __P((void)); +#ifdef COMPAT_HPUX +int pmap_mapmulti __P((pmap_t, vaddr_t)); +#endif /* COMPAT_HPUX */ -#define PAGE_IS_MANAGED(pa) \ - (pmap_initialized && IS_VM_PHYSADDR(pa)) +#define PAGE_IS_MANAGED(pa) (pmap_initialized && \ + vm_physseg_find(atop((pa)), NULL) != -1) #define pa_to_pvh(pa) \ ({ \ @@ -358,6 +303,29 @@ void pmap_check_wiring __P((char *, vaddr_t)); }) /* + * Internal routines + */ +void pmap_remove_mapping __P((pmap_t, vaddr_t, pt_entry_t *, int)); +boolean_t pmap_testbit __P((paddr_t, int)); +void pmap_changebit __P((paddr_t, int, int)); +void pmap_enter_ptpage __P((pmap_t, vaddr_t)); +void pmap_ptpage_addref __P((vaddr_t)); +int pmap_ptpage_delref __P((vaddr_t)); +void pmap_collect1 __P((pmap_t, paddr_t, paddr_t)); +void pmap_pinit __P((pmap_t)); +void pmap_release __P((pmap_t)); + +#ifdef DEBUG +void pmap_pvdump __P((paddr_t)); +void pmap_check_wiring __P((char *, vaddr_t)); +#endif + +/* pmap_remove_mapping flags */ +#define PRM_TFLUSH 0x01 +#define PRM_CFLUSH 0x02 +#define PRM_KEEPPTPAGE 0x04 + +/* * pmap_virtual_space: [ INTERFACE ] * * Report the range of available kernel virtual address @@ -409,9 +377,16 @@ pmap_init() * Now that kernel map has been allocated, we can mark as * unavailable regions which we have mapped in pmap_bootstrap(). */ - PMAP_INIT_MD(); + addr = (vaddr_t) intiobase; + if (uvm_map(kernel_map, &addr, + m68k_ptob(IIOMAPSIZE+EIOMAPSIZE), + NULL, UVM_UNKNOWN_OFFSET, 0, + UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, + UVM_INH_NONE, UVM_ADV_RANDOM, + UVM_FLAG_FIXED))) + goto bogons; addr = (vaddr_t) Sysmap; - if (uvm_map(kernel_map, &addr, MACHINE_MAX_PTSIZE, + if (uvm_map(kernel_map, &addr, HP_MAX_PTSIZE, NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, UVM_ADV_RANDOM, @@ -421,6 +396,7 @@ pmap_init() * portion of the kernel page table isn't big enough * and we overran the page table map. */ + bogons: panic("pmap_init: bogons in the VM system!\n"); } @@ -437,7 +413,7 @@ pmap_init() */ for (page_cnt = 0, bank = 0; bank < vm_nphysseg; bank++) page_cnt += vm_physmem[bank].end - vm_physmem[bank].start; - s = MACHINE_STSIZE; /* Segtabzero */ + s = HP_STSIZE; /* Segtabzero */ s += page_cnt * sizeof(struct pv_entry); /* pv table */ s += page_cnt * sizeof(char); /* attribute table */ s = round_page(s); @@ -446,21 +422,8 @@ pmap_init() panic("pmap_init: can't allocate data structures"); Segtabzero = (st_entry_t *) addr; - pmap_extract(pmap_kernel(), addr, (paddr_t *)&Segtabzeropa); -#ifdef M68060 - if (mmutype == MMU_68060) { - for (addr2 = addr; addr2 < addr + MACHINE_STSIZE; - addr2 += PAGE_SIZE) { - pt_entry_t *pte; - - pte = pmap_pte(pmap_kernel(), addr2); - *pte = (*pte | PG_CI) & ~PG_CCB; - TBIS(addr2); - } - DCIS(); - } -#endif - addr += MACHINE_STSIZE; + pmap_extract(pmap_kernel(), addr, (paddr_t *)Segtabzeropa); + addr += HP_STSIZE; pv_table = (struct pv_entry *) addr; addr += page_cnt * sizeof(struct pv_entry); @@ -490,7 +453,7 @@ pmap_init() * Allocate physical memory for kernel PT pages and their management. * We need 1 PT page per possible task plus some slop. */ - npages = min(atop(MACHINE_MAX_KPTSIZE), maxproc+16); + npages = min(atop(HP_MAX_KPTSIZE), maxproc+16); s = ptoa(npages) + round_page(npages * sizeof(struct kpt_page)); /* @@ -517,25 +480,12 @@ pmap_init() kpt_pages = &((struct kpt_page *)addr2)[npages]; kpt_free_list = NULL; do { - addr2 -= PAGE_SIZE; + addr2 -= NBPG; (--kpt_pages)->kpt_next = kpt_free_list; kpt_free_list = kpt_pages; kpt_pages->kpt_va = addr2; pmap_extract(pmap_kernel(), addr2, &kpt_pages->kpt_pa); -#ifdef M68060 - if (mmutype == MMU_68060) { - pt_entry_t *pte; - - pte = pmap_pte(pmap_kernel(), addr2); - *pte = (*pte | PG_CI) & ~PG_CCB; - TBIS(addr2); - } -#endif } while (addr != addr2); -#ifdef M68060 - if (mmutype == MMU_68060) - DCIS(); -#endif PMAP_DPRINTF(PDB_INIT, ("pmap_init: KPT: %ld pages from %lx to %lx\n", atop(s), addr, addr + s)); @@ -543,27 +493,27 @@ pmap_init() /* * Allocate the segment table map and the page table map. */ - s = maxproc * MACHINE_STSIZE; + s = maxproc * HP_STSIZE; st_map = uvm_km_suballoc(kernel_map, &addr, &addr2, s, 0, FALSE, &st_map_store); - addr = MACHINE_PTBASE; - if ((MACHINE_PTMAXSIZE / MACHINE_MAX_PTSIZE) < maxproc) { - s = MACHINE_PTMAXSIZE; + addr = HP_PTBASE; + if ((HP_PTMAXSIZE / HP_MAX_PTSIZE) < maxproc) { + s = HP_PTMAXSIZE; /* * XXX We don't want to hang when we run out of * page tables, so we lower maxproc so that fork() * will fail instead. Note that root could still raise * this value via sysctl(3). */ - maxproc = (MACHINE_PTMAXSIZE / MACHINE_MAX_PTSIZE); + maxproc = (HP_PTMAXSIZE / HP_MAX_PTSIZE); } else - s = (maxproc * MACHINE_MAX_PTSIZE); - pt_map = uvm_km_suballoc(kernel_map, &addr, &addr2, s, 0, + s = (maxproc * HP_MAX_PTSIZE); + pt_map = uvm_km_suballoc(kernel_map, &addr, &addr2, s, VM_MAP_PAGEABLE, TRUE, &pt_map_store); -#if defined(M68040) || defined(M68060) - if (mmutype <= MMU_68040) { +#if defined(M68040) + if (mmutype == MMU_68040) { protostfree = ~l2tobm(0); for (rv = MAXUL2SIZE; rv < sizeof(protostfree)*NBBY; rv++) protostfree &= ~l2tobm(rv); @@ -595,7 +545,7 @@ pmap_alloc_pv() int i; if (pv_nfree == 0) { - pvp = (struct pv_page *)uvm_km_zalloc(kernel_map, PAGE_SIZE); + pvp = (struct pv_page *)uvm_km_zalloc(kernel_map, NBPG); if (pvp == 0) panic("pmap_alloc_pv: uvm_km_zalloc() failed"); pvp->pvp_pgi.pgi_freelist = pv = &pvp->pvp_pv[1]; @@ -644,7 +594,7 @@ pmap_free_pv(pv) case NPVPPG: pv_nfree -= NPVPPG - 1; TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list); - uvm_km_free(kernel_map, (vaddr_t)pvp, PAGE_SIZE); + uvm_km_free(kernel_map, (vaddr_t)pvp, NBPG); break; } } @@ -709,7 +659,7 @@ pmap_collect_pv() for (pvp = pv_page_collectlist.tqh_first; pvp; pvp = npvp) { npvp = pvp->pvp_pgi.pgi_list.tqe_next; - uvm_km_free(kernel_map, (vaddr_t)pvp, PAGE_SIZE); + uvm_km_free(kernel_map, (vaddr_t)pvp, NBPG); } } @@ -736,8 +686,8 @@ pmap_map(va, spa, epa, prot) while (spa < epa) { pmap_enter(pmap_kernel(), va, spa, prot, 0); - va += PAGE_SIZE; - spa += PAGE_SIZE; + va += NBPG; + spa += NBPG; } pmap_update(pmap_kernel()); return (va); @@ -787,8 +737,8 @@ pmap_pinit(pmap) */ pmap->pm_stab = Segtabzero; pmap->pm_stpa = Segtabzeropa; -#if defined(M68040) || defined(M68060) - if (mmutype <= MMU_68040) +#if defined(M68040) + if (mmutype == MMU_68040) pmap->pm_stfree = protostfree; #endif pmap->pm_count = 1; @@ -840,12 +790,11 @@ pmap_release(pmap) if (pmap->pm_ptab) { pmap_remove(pmap_kernel(), (vaddr_t)pmap->pm_ptab, - (vaddr_t)pmap->pm_ptab + MACHINE_MAX_PTSIZE); - pmap_update(pmap_kernel()); + (vaddr_t)pmap->pm_ptab + HP_MAX_PTSIZE); uvm_km_pgremove(uvm.kernel_object, (vaddr_t)pmap->pm_ptab, - (vaddr_t)pmap->pm_ptab + MACHINE_MAX_PTSIZE); + (vaddr_t)pmap->pm_ptab + HP_MAX_PTSIZE); uvm_km_free_wakeup(pt_map, (vaddr_t)pmap->pm_ptab, - MACHINE_MAX_PTSIZE); + HP_MAX_PTSIZE); } KASSERT(pmap->pm_stab == Segtabzero); } @@ -930,7 +879,7 @@ pmap_remove(pmap, sva, eva) needcflush = FALSE; flags = active_pmap(pmap) ? PRM_TFLUSH : 0; while (sva < eva) { - nssva = m68k_trunc_seg(sva) + NBSEG; + nssva = hp300_trunc_seg(sva) + HP_SEG_SIZE; if (nssva == 0 || nssva > eva) nssva = eva; @@ -975,7 +924,7 @@ pmap_remove(pmap, sva, eva) firstpage = FALSE; } pte++; - sva += PAGE_SIZE; + sva += NBPG; } } /* @@ -1054,9 +1003,11 @@ pmap_page_protect(pg, prot) pte, PRM_TFLUSH|PRM_CFLUSH); else { pv = pv->pv_next; - PMAP_DPRINTF(PDB_PARANOIA, - ("%s wired mapping for %lx not removed\n", - "pmap_page_protect:", pa)); +#ifdef DEBUG + if (pmapdebug & PDB_PARANOIA) + printf("%s wired mapping for %lx not removed\n", + "pmap_page_protect:", pa); +#endif if (pv == NULL) break; } @@ -1090,11 +1041,11 @@ pmap_protect(pmap, sva, eva, prot) return; } - isro = pte_prot(prot); + isro = pte_prot(pmap, prot); needtflush = active_pmap(pmap); firstpage = TRUE; while (sva < eva) { - nssva = m68k_trunc_seg(sva) + NBSEG; + nssva = hp300_trunc_seg(sva) + HP_SEG_SIZE; if (nssva == 0 || nssva > eva) nssva = eva; /* @@ -1124,12 +1075,12 @@ pmap_protect(pmap, sva, eva, prot) if (firstpage && pmap_aliasmask) DCIS(); #endif -#if defined(M68040) || defined(M68060) +#if defined(M68040) /* * Clear caches if making RO (see section * "7.3 Cache Coherency" in the manual). */ - if (isro && mmutype <= MMU_68040) { + if (isro && mmutype == MMU_68040) { paddr_t pa = pmap_pte_pa(pte); DCFP(pa); @@ -1142,7 +1093,7 @@ pmap_protect(pmap, sva, eva, prot) firstpage = FALSE; } pte++; - sva += PAGE_SIZE; + sva += NBPG; } } } @@ -1194,7 +1145,7 @@ pmap_enter(pmap, va, pa, prot, flags) */ if (pmap->pm_ptab == NULL) pmap->pm_ptab = (pt_entry_t *) - uvm_km_valloc_wait(pt_map, MACHINE_MAX_PTSIZE); + uvm_km_valloc_wait(pt_map, HP_MAX_PTSIZE); /* * Segment table entry not valid, we need a new PT page @@ -1360,7 +1311,7 @@ pmap_enter(pmap, va, pa, prot, flags) } /* * Assumption: if it is not part of our managed memory - * then it must be device memory which may be volatile. + * then it must be device memory which may be volitile. */ else if (pmap_initialized) { checkpv = cacheable = FALSE; @@ -1385,13 +1336,13 @@ validate: /* * Build the new PTE. */ - npte = pa | pte_prot(prot) | (*pte & (PG_M|PG_U)) | PG_V; + npte = pa | pte_prot(pmap, prot) | (*pte & (PG_M|PG_U)) | PG_V; if (wired) npte |= PG_W; -#if defined(M68040) || defined(M68060) +#if defined(M68040) /* Don't cache if process can't take it, like SunOS ones. */ - if (mmutype <= MMU_68040 && pmap != pmap_kernel() && + if (mmutype == MMU_68040 && pmap != pmap_kernel() && (curproc->p_md.md_flags & MDP_UNCACHE_WX) && (prot & VM_PROT_EXECUTE) && (prot & VM_PROT_WRITE)) checkpv = cacheable = FALSE; @@ -1399,8 +1350,8 @@ validate: if (!checkpv && !cacheable) npte |= PG_CI; -#if defined(M68040) || defined(M68060) - if (mmutype <= MMU_68040 && (npte & (PG_PROT|PG_CI)) == PG_RW) +#if defined(M68040) + if (mmutype == MMU_68040 && (npte & (PG_PROT|PG_CI)) == PG_RW) #ifdef DEBUG if (dowriteback && (dokwriteback || pmap != pmap_kernel())) #endif @@ -1414,8 +1365,8 @@ validate: * If so, we need not flush the TLB and caches. */ wired = ((*pte ^ npte) == PG_W); -#if defined(M68040) || defined(M68060) - if (mmutype <= MMU_68040 && !wired) { +#if defined(M68040) + if (mmutype == MMU_68040 && !wired) { DCFP(pa); ICPP(pa); } @@ -1472,7 +1423,7 @@ pmap_kenter_pa(va, pa, prot) splx(s); } - pa = trunc_page(pa); + pa = m68k_trunc_page(pa); pte = pmap_pte(pmap, va); PMAP_DPRINTF(PDB_ENTER, ("enter: pte %p, *pte %x\n", pte, *pte)); @@ -1489,15 +1440,15 @@ pmap_kenter_pa(va, pa, prot) * Build the new PTE. */ - npte = pa | pte_prot(prot) | PG_V | PG_W; -#if defined(M68040) || defined(M68060) - if (mmutype <= MMU_68040 && (npte & (PG_PROT)) == PG_RW) + npte = pa | pte_prot(pmap, prot) | PG_V | PG_W; +#if defined(M68040) + if (mmutype == MMU_68040 && (npte & (PG_PROT)) == PG_RW) npte |= PG_CCB; #endif PMAP_DPRINTF(PDB_ENTER, ("enter: new pte value %x\n", npte)); -#if defined(M68040) || defined(M68060) - if (mmutype <= MMU_68040) { +#if defined(M68040) + if (mmutype == MMU_68040) { DCFP(pa); ICPP(pa); } @@ -1523,7 +1474,7 @@ pmap_kremove(va, len) firstpage = TRUE; needcflush = FALSE; while (sva < eva) { - nssva = m68k_trunc_seg(sva) + NBSEG; + nssva = hp300_trunc_seg(sva) + HP_SEG_SIZE; if (nssva == 0 || nssva > eva) nssva = eva; @@ -1597,7 +1548,7 @@ pmap_kremove(va, len) firstpage = FALSE; } pte++; - sva += PAGE_SIZE; + sva += NBPG; } } @@ -1692,15 +1643,15 @@ pmap_extract(pmap, va, pap) { boolean_t rv = FALSE; paddr_t pa; - pt_entry_t *pte; + u_int pte; PMAP_DPRINTF(PDB_FOLLOW, ("pmap_extract(%p, %lx) -> ", pmap, va)); if (pmap_ste_v(pmap, va)) { - pte = pmap_pte(pmap, va); - if (pmap_pte_v(pte)) { - pa = pmap_pte_pa(pte) | (va & ~PG_FRAME); + pte = *(u_int *)pmap_pte(pmap, va); + if (pte) { + pa = (pte & PG_FRAME) | (va & ~PG_FRAME); if (pap != NULL) *pap = pa; rv = TRUE; @@ -1810,7 +1761,7 @@ pmap_collect1(pmap, startpa, endpa) int opmapdebug = 0 /* XXX initialize to quiet gcc -Wall */; #endif - for (pa = startpa; pa < endpa; pa += PAGE_SIZE) { + for (pa = startpa; pa < endpa; pa += NBPG) { struct kpt_page *kpt, **pkpt; /* @@ -1828,7 +1779,7 @@ pmap_collect1(pmap, startpa, endpa) continue; #ifdef DEBUG if (pv->pv_va < (vaddr_t)Sysmap || - pv->pv_va >= (vaddr_t)Sysmap + MACHINE_MAX_PTSIZE) + pv->pv_va >= (vaddr_t)Sysmap + HP_MAX_PTSIZE) printf("collect: kernel PT VA out of range\n"); else goto ok; @@ -1836,7 +1787,7 @@ pmap_collect1(pmap, startpa, endpa) continue; ok: #endif - pte = (pt_entry_t *)(pv->pv_va + PAGE_SIZE); + pte = (pt_entry_t *)(pv->pv_va + NBPG); while (--pte >= (pt_entry_t *)pv->pv_va && *pte == PG_NV) ; if (pte >= (pt_entry_t *)pv->pv_va) @@ -1884,11 +1835,11 @@ ok: if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) pmapdebug = opmapdebug; - if (!(*ste & SG_V)) + if (*ste != SG_NV) printf("collect: kernel STE at %p still valid (%x)\n", ste, *ste); ste = &Sysptmap[ste - pmap_ste(pmap_kernel(), 0)]; - if (!(*ste & SG_V)) + if (*ste != SG_NV) printf("collect: kernel PTmap at %p still valid (%x)\n", ste, *ste); #endif @@ -1924,7 +1875,7 @@ pmap_zero_page(phys) #endif #if defined(M68040) || defined(M68060) - if (mmutype <= MMU_68040) { + if (mmutype == MMU_68040) { /* * Set copyback caching on the page; this is required * for cache consistency (since regular mappings are @@ -1976,7 +1927,7 @@ pmap_copy_page(src, dst) #endif #if defined(M68040) || defined(M68060) - if (mmutype <= MMU_68040) { + if (mmutype == MMU_68040) { /* * Set copyback caching on the pages; this is required * for cache consistency (since regular mappings are @@ -2155,7 +2106,7 @@ pmap_mapmulti(pmap, va) #endif bste = pmap_ste(pmap, HPMMBASEADDR(va)); ste = pmap_ste(pmap, va); - if (!(*ste & SG_V) && (*bste & SG_V)) { + if (*ste == SG_NV && (*bste & SG_V)) { *ste = *bste; TBIAU(); return (0); @@ -2381,8 +2332,8 @@ pmap_remove_mapping(pmap, va, pte, flags) PMAP_DPRINTF(PDB_REMOVE|PDB_PTPAGE, ("remove: ste was %x@%p pte was %x@%p\n", *ste, ste, opte, pmap_pte(pmap, va))); -#if defined(M68040) || defined(M68060) - if (mmutype <= MMU_68040) { +#if defined(M68040) + if (mmutype == MMU_68040) { st_entry_t *este = &ste[NPTEPG/SG4_LEV3SIZE]; while (ste < este) @@ -2415,17 +2366,16 @@ pmap_remove_mapping(pmap, va, pte, flags) ptpmap->pm_stab)); pmap_remove(pmap_kernel(), (vaddr_t)ptpmap->pm_stab, - (vaddr_t)ptpmap->pm_stab + MACHINE_STSIZE); - pmap_update(pmap_kernel()); + (vaddr_t)ptpmap->pm_stab + HP_STSIZE); uvm_pagefree(PHYS_TO_VM_PAGE((paddr_t) ptpmap->pm_stpa)); uvm_km_free_wakeup(st_map, (vaddr_t)ptpmap->pm_stab, - MACHINE_STSIZE); + HP_STSIZE); ptpmap->pm_stab = Segtabzero; ptpmap->pm_stpa = Segtabzeropa; -#if defined(M68040) || defined(M68060) - if (mmutype <= MMU_68040) +#if defined(M68040) + if (mmutype == MMU_68040) ptpmap->pm_stfree = protostfree; #endif @@ -2532,7 +2482,7 @@ pmap_changebit(pa, set, mask) pt_entry_t *pte, npte; vaddr_t va; int s; -#if defined(M68K_MMU_HP) || defined(M68040) || defined(M68060) +#if defined(M68K_MMU_HP) || defined(M68040) boolean_t firstpage = TRUE; #endif @@ -2575,7 +2525,7 @@ pmap_changebit(pa, set, mask) #endif npte = (*pte | set) & mask; if (*pte != npte) { -#if defined(M68040) || defined(M68060) +#if defined(M68040) /* * If we are changing caching status or * protection make sure the caches are @@ -2615,9 +2565,6 @@ pmap_enter_ptpage(pmap, va) struct pv_entry *pv; st_entry_t *ste; int s; -#if defined(M68040) || defined(M68060) - paddr_t stpa; -#endif PMAP_DPRINTF(PDB_FOLLOW|PDB_ENTER|PDB_PTPAGE, ("pmap_enter_ptpage: pmap %p, va %lx\n", pmap, va)); @@ -2631,29 +2578,15 @@ pmap_enter_ptpage(pmap, va) */ if (pmap->pm_stab == Segtabzero) { pmap->pm_stab = (st_entry_t *) - uvm_km_zalloc(st_map, MACHINE_STSIZE); + uvm_km_zalloc(st_map, HP_STSIZE); pmap_extract(pmap_kernel(), (vaddr_t)pmap->pm_stab, (paddr_t *)&pmap->pm_stpa); -#if defined(M68040) || defined(M68060) - if (mmutype <= MMU_68040) { -#ifdef DEBUG - if (dowriteback && dokwriteback) { -#endif - stpa = (paddr_t)pmap->pm_stpa; -#if defined(M68060) - if (mmutype == MMU_68060) { - while (stpa < (paddr_t)pmap->pm_stpa + - MACHINE_STSIZE) { - pmap_changebit(stpa, PG_CI, ~PG_CCB); - stpa += PAGE_SIZE; - } - DCIS(); /* XXX */ - } else -#endif - pmap_changebit(stpa, 0, ~PG_CCB); +#if defined(M68040) + if (mmutype == MMU_68040) { #ifdef DEBUG - } + if (dowriteback && dokwriteback) #endif + pmap_changebit((paddr_t)pmap->pm_stpa, 0, ~PG_CCB); pmap->pm_stfree = protostfree; } #endif @@ -2670,11 +2603,11 @@ pmap_enter_ptpage(pmap, va) } ste = pmap_ste(pmap, va); -#if defined(M68040) || defined(M68060) +#if defined(M68040) /* * Allocate level 2 descriptor block if necessary */ - if (mmutype <= MMU_68040) { + if (mmutype == MMU_68040) { if (*ste == SG_NV) { int ix; caddr_t addr; @@ -2695,12 +2628,12 @@ pmap_enter_ptpage(pmap, va) /* * Since a level 2 descriptor maps a block of SG4_LEV3SIZE * level 3 descriptors, we need a chunk of NPTEPG/SG4_LEV3SIZE - * (16) such descriptors (PAGE_SIZE/SG4_LEV3SIZE bytes) to map a + * (16) such descriptors (NBPG/SG4_LEV3SIZE bytes) to map a * PT page--the unit of allocation. We set `ste' to point * to the first entry of that chunk which is validated in its * entirety below. */ - ste = (st_entry_t *)((int)ste & ~(PAGE_SIZE/SG4_LEV3SIZE-1)); + ste = (st_entry_t *)((int)ste & ~(NBPG/SG4_LEV3SIZE-1)); PMAP_DPRINTF(PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB, ("enter: ste2 %p (%p)\n", pmap_ste2(pmap, va), ste)); @@ -2725,20 +2658,16 @@ pmap_enter_ptpage(pmap, va) PMAP_DPRINTF(PDB_COLLECT, ("enter: no KPT pages, collecting...\n")); pmap_collect(pmap_kernel()); - if ((kpt = kpt_free_list) == NULL) + if ((kpt = kpt_free_list) == (struct kpt_page *)0) panic("pmap_enter_ptpage: can't get KPT page"); } kpt_free_list = kpt->kpt_next; kpt->kpt_next = kpt_used_list; kpt_used_list = kpt; ptpa = kpt->kpt_pa; - bzero((caddr_t)kpt->kpt_va, PAGE_SIZE); + bzero((caddr_t)kpt->kpt_va, NBPG); pmap_enter(pmap, va, ptpa, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED); -#if defined(M68060) - if (mmutype == MMU_68060) - pmap_changebit(ptpa, PG_CI, ~PG_CCB); -#endif pmap_update(pmap); #ifdef DEBUG if (pmapdebug & (PDB_ENTER|PDB_PTPAGE)) { @@ -2775,9 +2704,9 @@ pmap_enter_ptpage(pmap, va) pmap_enter(pmap_kernel(), va, ptpa, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED); - pmap_update(pmap_kernel()); + pmap_update(pmap); } -#if defined(M68040) || defined(M68060) +#if defined(M68040) /* * Turn off copyback caching of page table pages, * could get ugly otherwise. @@ -2785,7 +2714,7 @@ pmap_enter_ptpage(pmap, va) #ifdef DEBUG if (dowriteback && dokwriteback) #endif - if (mmutype <= MMU_68040) { + if (mmutype == MMU_68040) { #ifdef DEBUG pt_entry_t *pte = pmap_pte(pmap_kernel(), va); if ((pmapdebug & PDB_PARANOIA) && (*pte & PG_CCB) == 0) @@ -2793,13 +2722,7 @@ pmap_enter_ptpage(pmap, va) pmap == pmap_kernel() ? "Kernel" : "User", va, ptpa, pte, *pte); #endif -#ifdef M68060 - if (mmutype == MMU_68060) { - pmap_changebit(ptpa, PG_CI, ~PG_CCB); - DCIS(); - } else -#endif - pmap_changebit(ptpa, 0, ~PG_CCB); + pmap_changebit(ptpa, 0, ~PG_CCB); } #endif /* @@ -2834,8 +2757,8 @@ pmap_enter_ptpage(pmap, va) * it would be difficult to identify ST pages in pmap_pageable to * release them. We also avoid the overhead of vm_map_pageable. */ -#if defined(M68040) || defined(M68060) - if (mmutype <= MMU_68040) { +#if defined(M68040) + if (mmutype == MMU_68040) { st_entry_t *este; for (este = &ste[NPTEPG/SG4_LEV3SIZE]; ste < este; ste++) { @@ -2850,17 +2773,14 @@ pmap_enter_ptpage(pmap, va) ("enter: stab %p refcnt %d\n", pmap->pm_stab, pmap->pm_sref)); } - -#if defined(M68060) - if (mmutype == MMU_68060) { - /* - * Flush stale TLB info. - */ - if (pmap == pmap_kernel()) - TBIAS(); - else - TBIAU(); - } +#if 0 + /* + * Flush stale TLB info. + */ + if (pmap == pmap_kernel()) + TBIAS(); + else + TBIAU(); #endif pmap->pm_ptpages++; splx(s); @@ -2957,8 +2877,7 @@ pmap_check_wiring(str, va) } count = 0; - for (pte = (pt_entry_t *)va; pte < (pt_entry_t *)(va + PAGE_SIZE); - pte++) + for (pte = (pt_entry_t *)va; pte < (pt_entry_t *)(va + NBPG); pte++) if (*pte) count++; if ((pg->wire_count - 1) != count) @@ -2966,21 +2885,3 @@ pmap_check_wiring(str, va) str, va, (pg->wire_count - 1), count); } #endif /* DEBUG */ - -/* XXX this should go out soon */ -#ifdef mac68k -void -mac68k_set_pte(va, pge) - vaddr_t va; - paddr_t pge; -{ -extern vaddr_t tmp_vpages[]; - register pt_entry_t *pte; - - if (va != tmp_vpages[0]) - return; - - pte = pmap_pte(pmap_kernel(), va); - *pte = (pt_entry_t) pge; -} -#endif diff --git a/sys/arch/hp300/hp300/pmap_bootstrap.c b/sys/arch/hp300/hp300/pmap_bootstrap.c index 9108859dcc3..b8418539f87 100644 --- a/sys/arch/hp300/hp300/pmap_bootstrap.c +++ b/sys/arch/hp300/hp300/pmap_bootstrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pmap_bootstrap.c,v 1.13 2001/12/14 21:44:04 miod Exp $ */ +/* $OpenBSD: pmap_bootstrap.c,v 1.14 2001/12/20 19:02:27 miod Exp $ */ /* $NetBSD: pmap_bootstrap.c,v 1.13 1997/06/10 18:56:50 veego Exp $ */ /* @@ -68,6 +68,7 @@ extern int maxmem, physmem; extern paddr_t avail_start, avail_end; extern vaddr_t virtual_avail, virtual_end; extern vsize_t mem_size; +extern int protection_codes[]; #ifdef M68K_MMU_HP extern int pmap_aliasmask; #endif @@ -447,6 +448,25 @@ pmap_bootstrap(nextpa, firstpa) #endif /* + * Initialize protection array. + * XXX don't use a switch statement, it might produce an + * absolute "jmp" table. + */ + { + int *kp; + + kp = &RELOC(protection_codes, int); + kp[VM_PROT_NONE|VM_PROT_NONE|VM_PROT_NONE] = 0; + kp[VM_PROT_READ|VM_PROT_NONE|VM_PROT_NONE] = PG_RO; + kp[VM_PROT_READ|VM_PROT_NONE|VM_PROT_EXECUTE] = PG_RO; + kp[VM_PROT_NONE|VM_PROT_NONE|VM_PROT_EXECUTE] = PG_RO; + kp[VM_PROT_NONE|VM_PROT_WRITE|VM_PROT_NONE] = PG_RW; + kp[VM_PROT_NONE|VM_PROT_WRITE|VM_PROT_EXECUTE] = PG_RW; + kp[VM_PROT_READ|VM_PROT_WRITE|VM_PROT_NONE] = PG_RW; + kp[VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE] = PG_RW; + } + + /* * Kernel page/segment table allocated in locore, * just initialize pointers. */ @@ -500,22 +520,3 @@ pmap_bootstrap(nextpa, firstpa) RELOC(virtual_avail, vaddr_t) = va; } } - -void -pmap_init_md() -{ - vaddr_t addr; - - /* - * mark as unavailable the regions which we have mapped in - * pmap_bootstrap(). - */ - addr = (vaddr_t) intiobase; - if (uvm_map(kernel_map, &addr, - m68k_ptob(IIOMAPSIZE+EIOMAPSIZE), - NULL, UVM_UNKNOWN_OFFSET, 0, - UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, - UVM_INH_NONE, UVM_ADV_RANDOM, - UVM_FLAG_FIXED))) - panic("pmap_init: bogons in the VM system!\n"); -} diff --git a/sys/arch/hp300/include/cpu.h b/sys/arch/hp300/include/cpu.h index 06f7ecb1e0f..80ea3091c74 100644 --- a/sys/arch/hp300/include/cpu.h +++ b/sys/arch/hp300/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.16 2001/11/30 20:58:18 miod Exp $ */ +/* $OpenBSD: cpu.h,v 1.17 2001/12/20 19:02:27 miod Exp $ */ /* $NetBSD: cpu.h,v 1.28 1998/02/13 07:41:51 scottr Exp $ */ /* @@ -184,6 +184,9 @@ int badaddr __P((caddr_t)); int badbaddr __P((caddr_t)); void dumpconf __P((void)); +/* pmap.c functions */ +vaddr_t pmap_map __P((vaddr_t, paddr_t, paddr_t, int)); + /* sys_machdep.c functions */ int cachectl __P((int, vaddr_t, int)); diff --git a/sys/arch/hp300/include/param.h b/sys/arch/hp300/include/param.h index 85b39cad6b0..3f1974599c0 100644 --- a/sys/arch/hp300/include/param.h +++ b/sys/arch/hp300/include/param.h @@ -1,4 +1,4 @@ -/* $OpenBSD: param.h,v 1.18 2001/12/05 01:57:14 provos Exp $ */ +/* $OpenBSD: param.h,v 1.19 2001/12/20 19:02:27 miod Exp $ */ /* $NetBSD: param.h,v 1.35 1997/07/10 08:22:38 veego Exp $ */ /* @@ -65,6 +65,12 @@ #define KERNBASE 0x00000000 /* start of kernel virtual */ +#define SEGSHIFT 22 /* LOG2(NBSEG) */ +#define NBSEG (1 << SEGSHIFT) /* bytes/segment */ +#define SEGOFSET (NBSEG-1) /* byte offset into segment */ + +#define UPAGES 2 /* pages of u-area */ + #include <m68k/param.h> #define NPTEPG (NBPG/(sizeof (pt_entry_t))) @@ -85,4 +91,18 @@ void _delay __P((u_int)); #endif /* _KERNEL && !_LOCORE */ +#ifdef COMPAT_HPUX +/* + * Constants/macros for HPUX multiple mapping of user address space. + * Pages in the first 256Mb are mapped in at every 256Mb segment. + */ +#define HPMMMASK 0xF0000000 +#define ISHPMMADDR(v) \ + ((curproc->p_md.md_flags & MDP_HPUXMMAP) && \ + ((unsigned)(v) & HPMMMASK) && \ + ((unsigned)(v) & HPMMMASK) != HPMMMASK) +#define HPMMBASEADDR(v) \ + ((unsigned)(v) & ~HPMMMASK) +#endif + #endif /* !_MACHINE_PARAM_H_ */ diff --git a/sys/arch/hp300/include/pmap.h b/sys/arch/hp300/include/pmap.h index 9df02e00f25..8cdb0e6286f 100644 --- a/sys/arch/hp300/include/pmap.h +++ b/sys/arch/hp300/include/pmap.h @@ -1,13 +1,162 @@ -/* $OpenBSD: pmap.h,v 1.11 2001/11/30 20:58:18 miod Exp $ */ +/* $OpenBSD: pmap.h,v 1.12 2001/12/20 19:02:27 miod Exp $ */ +/* $NetBSD: pmap.h,v 1.13 1997/06/10 18:58:19 veego Exp $ */ -#ifndef _MACHINE_PMAP_H_ -#define _MACHINE_PMAP_H_ +/* + * Copyright (c) 1987 Carnegie-Mellon University + * Copyright (c) 1991, 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. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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.h 8.1 (Berkeley) 6/10/93 + */ -#include <m68k/pmap_motorola.h> +#ifndef _HP300_PMAP_H_ +#define _HP300_PMAP_H_ -#ifdef _KERNEL -void pmap_init_md __P((void)); -#define PMAP_INIT_MD() pmap_init_md() +#include <machine/cpu.h> +#include <machine/pte.h> + +#if defined(M68040) +#define HP_SEG_SIZE (mmutype == MMU_68040 ? 0x40000 : NBSEG) +#else +#define HP_SEG_SIZE NBSEG +#endif + +#define hp300_trunc_seg(x) (((unsigned)(x)) & ~(HP_SEG_SIZE-1)) +#define hp300_round_seg(x) hp300_trunc_seg((unsigned)(x) + HP_SEG_SIZE-1) + +/* + * Pmap stuff + */ +struct pmap { + pt_entry_t *pm_ptab; /* KVA of page table */ + st_entry_t *pm_stab; /* KVA of segment table */ + int pm_stchanged; /* ST changed */ + int pm_stfree; /* 040: free lev2 blocks */ + st_entry_t *pm_stpa; /* 040: ST phys addr */ + short pm_sref; /* segment table ref count */ + short pm_count; /* pmap reference count */ + struct simplelock pm_lock; /* lock on pmap */ + struct pmap_statistics pm_stats; /* pmap statistics */ + long pm_ptpages; /* more stats: PT pages */ +}; + +typedef struct pmap *pmap_t; + +/* + * On the 040 we keep track of which level 2 blocks are already in use + * with the pm_stfree mask. Bits are arranged from LSB (block 0) to MSB + * (block 31). For convenience, the level 1 table is considered to be + * block 0. + * + * MAX[KU]L2SIZE control how many pages of level 2 descriptors are allowed. + * for the kernel and users. 8 implies only the initial "segment table" + * page is used. WARNING: don't change MAXUL2SIZE unless you can allocate + * physically contiguous pages for the ST in pmap.c! + */ +#define MAXKL2SIZE 32 +#define MAXUL2SIZE 8 +#define l2tobm(n) (1 << (n)) +#define bmtol2(n) (ffs(n) - 1) + +/* + * Macros for speed + */ +#define PMAP_ACTIVATE(pmap, loadhw) \ +{ \ + if ((loadhw)) \ + loadustp(m68k_btop((paddr_t)(pmap)->pm_stpa)); \ +} +#define PMAP_DEACTIVATE(pmapp, pcbp) + +/* + * For each vm_page_t, there is a list of all currently valid virtual + * mappings of that page. An entry is a pv_entry, the list is pv_table. + */ +struct pv_entry { + struct pv_entry *pv_next; /* next pv_entry */ + struct pmap *pv_pmap; /* pmap where mapping lies */ + vaddr_t pv_va; /* virtual address for mapping */ + st_entry_t *pv_ptste; /* non-zero if VA maps a PT page */ + struct pmap *pv_ptpmap; /* if pv_ptste, pmap for PT page */ + int pv_flags; /* flags */ +}; + +#define PV_CI 0x01 /* header: all entries are cache inhibited */ +#define PV_PTPAGE 0x02 /* header: entry maps a page table page */ + +struct pv_page; + +struct pv_page_info { + TAILQ_ENTRY(pv_page) pgi_list; + struct pv_entry *pgi_freelist; + int pgi_nfree; +}; + +/* + * This is basically: + * ((NBPG - sizeof(struct pv_page_info)) / sizeof(struct pv_entry)) + */ +#define NPVPPG 170 + +struct pv_page { + struct pv_page_info pvp_pgi; + struct pv_entry pvp_pv[NPVPPG]; +}; + +extern struct pmap kernel_pmap_store; + +#define pmap_kernel() (&kernel_pmap_store) +#define active_pmap(pm) \ + ((pm) == pmap_kernel() || (pm) == curproc->p_vmspace->vm_map.pmap) +#define active_user_pmap(pm) \ + (curproc && \ + (pm) != pmap_kernel() && (pm) == curproc->p_vmspace->vm_map.pmap) + +extern struct pv_entry *pv_table; /* array of entries, one per page */ + +#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count) +#define pmap_wired_count(pmap) ((pmap)->pm_stats.wired_count) + +#define pmap_update(pmap) /* empty */ + +extern pt_entry_t *Sysmap; +extern char *vmmap; /* map for mem, dumps, etc. */ + +#ifdef M68K_MMU_HP +void pmap_prefer __P((vaddr_t, vaddr_t *)); +#define PMAP_PREFER(foff, vap) pmap_prefer((foff), (vap)) #endif -#endif /* _MACHINE_PMAP_H_ */ +#endif /* !_HP300_PMAP_H_ */ diff --git a/sys/arch/hp300/include/pte.h b/sys/arch/hp300/include/pte.h index e359464ad33..e524b59b016 100644 --- a/sys/arch/hp300/include/pte.h +++ b/sys/arch/hp300/include/pte.h @@ -1,14 +1,153 @@ -/* $OpenBSD: pte.h,v 1.3 2001/11/30 20:58:18 miod Exp $ */ +/* $OpenBSD: pte.h,v 1.4 2001/12/20 19:02:27 miod Exp $ */ +/* $NetBSD: pte.h,v 1.4 1994/10/26 07:26:40 cgd Exp $ */ -#ifndef _MACHINE_PTE_H_ -#define _MACHINE_PTE_H_ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1982, 1986, 1990, 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. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + * + * from: Utah $Hdr: pte.h 1.13 92/01/20$ + * + * @(#)pte.h 8.1 (Berkeley) 6/10/93 + */ -#include <m68k/pte_motorola.h> +#ifndef _HP300_PTE_H_ +#define _HP300_PTE_H_ -#define MACHINE_STSIZE M68K_STSIZE -#define MACHINE_MAX_PTSIZE M68K_MAX_PTSIZE -#define MACHINE_MAX_KPTSIZE M68K_MAX_KPTSIZE -#define MACHINE_PTBASE M68K_PTBASE -#define MACHINE_PTMAXSIZE M68K_PTMAXSIZE +/* + * HP300 hardware segment/page table entries + */ -#endif /* _MACHINE_PTE_H_ */ +#if 0 +struct ste { + unsigned int sg_pfnum:20; /* page table frame number */ + unsigned int :8; /* reserved at 0 */ + unsigned int :1; /* reserved at 1 */ + unsigned int sg_prot:1; /* write protect bit */ + unsigned int sg_v:2; /* valid bits */ +}; + +struct ste40 { + unsigned int sg_ptaddr:24; /* page table page addr */ + unsigned int :4; /* reserved at 0 */ + unsigned int sg_u; /* hardware modified (dirty) bit */ + unsigned int sg_prot:1; /* write protect bit */ + unsigned int sg_v:2; /* valid bits */ +}; + +struct pte { + unsigned int pg_pfnum:20; /* page frame number or 0 */ + unsigned int :3; + unsigned int pg_w:1; /* is wired */ + unsigned int :1; /* reserved at zero */ + unsigned int pg_ci:1; /* cache inhibit bit */ + unsigned int :1; /* reserved at zero */ + unsigned int pg_m:1; /* hardware modified (dirty) bit */ + unsigned int pg_u:1; /* hardware used (reference) bit */ + unsigned int pg_prot:1; /* write protect bit */ + unsigned int pg_v:2; /* valid bit */ +}; +#endif + +typedef int st_entry_t; /* segment table entry */ +typedef int pt_entry_t; /* Mach page table entry */ + +#define PT_ENTRY_NULL ((pt_entry_t *) 0) +#define ST_ENTRY_NULL ((st_entry_t *) 0) + +#define SG_V 0x00000002 /* segment is valid */ +#define SG_NV 0x00000000 +#define SG_PROT 0x00000004 /* access protection mask */ +#define SG_RO 0x00000004 +#define SG_RW 0x00000000 +#define SG_U 0x00000008 /* modified bit (68040) */ +#define SG_FRAME 0xfffff000 +#define SG_IMASK 0xffc00000 +#define SG_ISHIFT 22 +#define SG_PMASK 0x003ff000 +#define SG_PSHIFT 12 + +/* 68040 additions */ +#define SG4_MASK1 0xfe000000 +#define SG4_SHIFT1 25 +#define SG4_MASK2 0x01fc0000 +#define SG4_SHIFT2 18 +#define SG4_MASK3 0x0003f000 +#define SG4_SHIFT3 12 +#define SG4_ADDR1 0xfffffe00 +#define SG4_ADDR2 0xffffff00 +#define SG4_LEV1SIZE 128 +#define SG4_LEV2SIZE 128 +#define SG4_LEV3SIZE 64 + +#define PG_V 0x00000001 +#define PG_NV 0x00000000 +#define PG_PROT 0x00000004 +#define PG_U 0x00000008 +#define PG_M 0x00000010 +#define PG_W 0x00000100 +#define PG_RO 0x00000004 +#define PG_RW 0x00000000 +#define PG_FRAME 0xfffff000 +#define PG_CI 0x00000040 +#define PG_SHIFT 12 +#define PG_PFNUM(x) (((x) & PG_FRAME) >> PG_SHIFT) + +/* 68040 additions */ +#define PG_CMASK 0x00000060 /* cache mode mask */ +#define PG_CWT 0x00000000 /* writethrough caching */ +#define PG_CCB 0x00000020 /* copyback caching */ +#define PG_CIS 0x00000040 /* cache inhibited serialized */ +#define PG_CIN 0x00000060 /* cache inhibited nonserialized */ +#define PG_SO 0x00000080 /* supervisor only */ + +#define HP_STSIZE (MAXUL2SIZE*SG4_LEV2SIZE*sizeof(st_entry_t)) + /* user process segment table size */ +#define HP_MAX_PTSIZE 0x400000 /* max size of UPT */ +#define HP_MAX_KPTSIZE 0x100000 /* max memory to allocate to KPT */ +#define HP_PTBASE 0x10000000 /* UPT map base address */ +#define HP_PTMAXSIZE 0x70000000 /* UPT map maximum size */ + +/* + * Kernel virtual address to page table entry and to physical address. + */ +#define kvtopte(va) \ + (&Sysmap[((unsigned)(va) - VM_MIN_KERNEL_ADDRESS) >> PGSHIFT]) +#define ptetokv(pt) \ + ((((pt_entry_t *)(pt) - Sysmap) << PGSHIFT) + VM_MIN_KERNEL_ADDRESS) +#define kvtophys(va) \ + ((kvtopte(va)->pg_pfnum << PGSHIFT) | ((int)(va) & PGOFSET)) + +#endif /* !_HP300_PTE_H_ */ diff --git a/sys/arch/m68k/include/param.h b/sys/arch/m68k/include/param.h index f948a1bcebe..7578b263e02 100644 --- a/sys/arch/m68k/include/param.h +++ b/sys/arch/m68k/include/param.h @@ -1,4 +1,4 @@ -/* $OpenBSD: param.h,v 1.5 2001/11/30 20:57:52 miod Exp $ */ +/* $OpenBSD: param.h,v 1.6 2001/12/20 19:02:28 miod Exp $ */ /* $NetBSD: param.h,v 1.2 1997/06/10 18:21:23 veego Exp $ */ /* @@ -81,16 +81,6 @@ #define SSIZE 1 /* initial stack size/NBPG */ #define SINCR 1 /* increment of stack/NBPG */ -#ifndef SEGSHIFT -#if defined(M68040) || defined(M68060) -#define SEGSHIFT ((mmutype <= MMU_68040) ? 18 : (34 - PGSHIFT)) -#else -#define SEGSHIFT (34 - PGSHIFT) -#endif -#define NBSEG (1 << SEGSHIFT) -#define SEGOFSET (NBSEG - 1) -#endif - /* mac68k use 3 pages of u-area */ #ifndef UPAGES #define UPAGES 2 /* pages of u-area */ @@ -150,18 +140,4 @@ #define m68k_btop(x) ((unsigned)(x) >> PGSHIFT) #define m68k_ptob(x) ((unsigned)(x) << PGSHIFT) -#ifdef COMPAT_HPUX -/* - * Constants/macros for HPUX multiple mapping of user address space. - * Pages in the first 256Mb are mapped in at every 256Mb segment. - */ -#define HPMMMASK 0xF0000000 -#define ISHPMMADDR(v) \ - ((curproc->p_md.md_flags & MDP_HPUXMMAP) && \ - ((unsigned)(v) & HPMMMASK) && \ - ((unsigned)(v) & HPMMMASK) != HPMMMASK) -#define HPMMBASEADDR(v) \ - ((unsigned)(v) & ~HPMMMASK) -#endif /* COMPAT_HPUX */ - #endif /* !_M68K_PARAM_H_ */ diff --git a/sys/arch/m68k/include/pmap_motorola.h b/sys/arch/m68k/include/pmap_motorola.h deleted file mode 100644 index 028c4f61faa..00000000000 --- a/sys/arch/m68k/include/pmap_motorola.h +++ /dev/null @@ -1,160 +0,0 @@ -/* $OpenBSD: pmap_motorola.h,v 1.2 2001/12/05 00:11:51 millert Exp $ */ - -/* - * Copyright (c) 1987 Carnegie-Mellon University - * Copyright (c) 1991, 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. - * - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. 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.h 8.1 (Berkeley) 6/10/93 - */ - -#ifndef _PMAP_MOTOROLA_H_ -#define _PMAP_MOTOROLA_H_ - -#include <machine/cpu.h> -#include <machine/pte.h> - -/* - * Pmap stuff - */ -struct pmap { - pt_entry_t *pm_ptab; /* KVA of page table */ - st_entry_t *pm_stab; /* KVA of segment table */ - int pm_stfree; /* 040: free lev2 blocks */ - st_entry_t *pm_stpa; /* 040: ST phys addr */ - short pm_sref; /* segment table ref count */ - short pm_count; /* pmap reference count */ - struct simplelock pm_lock; /* lock on pmap */ - struct pmap_statistics pm_stats; /* pmap statistics */ - long pm_ptpages; /* more stats: PT pages */ -}; - -typedef struct pmap *pmap_t; - -/* - * On the 040 we keep track of which level 2 blocks are already in use - * with the pm_stfree mask. Bits are arranged from LSB (block 0) to MSB - * (block 31). For convenience, the level 1 table is considered to be - * block 0. - * - * MAX[KU]L2SIZE control how many pages of level 2 descriptors are allowed. - * for the kernel and users. 8 implies only the initial "segment table" - * page is used. WARNING: don't change MAXUL2SIZE unless you can allocate - * physically contiguous pages for the ST in pmap.c! - */ -#define MAXKL2SIZE 32 -#define MAXUL2SIZE 8 -#define l2tobm(n) (1 << (n)) -#define bmtol2(n) (ffs(n) - 1) - -/* - * Macros for speed - */ -#define PMAP_ACTIVATE(pmap, loadhw) \ -{ \ - if ((loadhw)) \ - loadustp(m68k_btop((paddr_t)(pmap)->pm_stpa)); \ -} - -/* - * For each vm_page_t, there is a list of all currently valid virtual - * mappings of that page. An entry is a pv_entry, the list is pv_table. - */ -struct pv_entry { - struct pv_entry *pv_next; /* next pv_entry */ - struct pmap *pv_pmap; /* pmap where mapping lies */ - vaddr_t pv_va; /* virtual address for mapping */ - st_entry_t *pv_ptste; /* non-zero if VA maps a PT page */ - struct pmap *pv_ptpmap; /* if pv_ptste, pmap for PT page */ - int pv_flags; /* flags */ -}; - -#define PV_CI 0x01 /* header: all entries are cache inhibited */ -#define PV_PTPAGE 0x02 /* header: entry maps a page table page */ - -struct pv_page; - -struct pv_page_info { - TAILQ_ENTRY(pv_page) pgi_list; - struct pv_entry *pgi_freelist; - int pgi_nfree; -}; - -/* - * This is basically: - * ((PAGE_SIZE - sizeof(struct pv_page_info)) / sizeof(struct pv_entry)) - */ -#if PAGE_SHIFT == 13 -#define NPVPPG 340 -#elif PAGE_SHIFT == 12 -#define NPVPPG 170 -#endif - -struct pv_page { - struct pv_page_info pvp_pgi; - struct pv_entry pvp_pv[NPVPPG]; -}; - -#ifdef _KERNEL - -extern struct pmap kernel_pmap_store; - -#define pmap_kernel() (&kernel_pmap_store) -#define active_pmap(pm) \ - ((pm) == pmap_kernel() || (pm) == curproc->p_vmspace->vm_map.pmap) -#define active_user_pmap(pm) \ - (curproc && \ - (pm) != pmap_kernel() && (pm) == curproc->p_vmspace->vm_map.pmap) - -extern struct pv_entry *pv_table; /* array of entries, one per page */ - -#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count) -#define pmap_wired_count(pmap) ((pmap)->pm_stats.wired_count) - -#define pmap_update(pmap) /* nothing (yet) */ - -extern pt_entry_t *Sysmap; -extern char *vmmap; /* map for mem, dumps, etc. */ - -#ifdef M68K_MMU_HP -void pmap_prefer __P((vaddr_t, vaddr_t *)); -#define PMAP_PREFER(foff, vap) pmap_prefer((foff), (vap)) -#endif - -vaddr_t pmap_map __P((vaddr_t, paddr_t, paddr_t, int)); - -#endif /* _KERNEL */ - -#endif /* !_PMAP_MOTOROLA_H_ */ diff --git a/sys/arch/m68k/include/pte_motorola.h b/sys/arch/m68k/include/pte_motorola.h deleted file mode 100644 index a250eaa82e1..00000000000 --- a/sys/arch/m68k/include/pte_motorola.h +++ /dev/null @@ -1,152 +0,0 @@ -/* $OpenBSD: pte_motorola.h,v 1.1 2001/11/30 20:54:50 miod Exp $ */ - -/* - * Copyright (c) 1988 University of Utah. - * Copyright (c) 1982, 1986, 1990, 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. - * - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. 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. - * - * from: Utah $Hdr: pte.h 1.13 92/01/20$ - * - * @(#)pte.h 8.1 (Berkeley) 6/10/93 - */ - -#ifndef _PTE_MOTOROLA_H_ -#define _PTE_MOTOROLA_H_ - -/* - * m68k hardware with motorola MMU segment/page table entries - */ - -#if 0 -struct ste { - unsigned int sg_pfnum:20; /* page table frame number */ - unsigned int :8; /* reserved at 0 */ - unsigned int :1; /* reserved at 1 */ - unsigned int sg_prot:1; /* write protect bit */ - unsigned int sg_v:2; /* valid bits */ -}; - -struct ste40 { - unsigned int sg_ptaddr:24; /* page table page addr */ - unsigned int :4; /* reserved at 0 */ - unsigned int sg_u; /* hardware modified (dirty) bit */ - unsigned int sg_prot:1; /* write protect bit */ - unsigned int sg_v:2; /* valid bits */ -}; - -struct pte { - unsigned int pg_pfnum:20; /* page frame number or 0 */ - unsigned int :3; - unsigned int pg_w:1; /* is wired */ - unsigned int :1; /* reserved at zero */ - unsigned int pg_ci:1; /* cache inhibit bit */ - unsigned int :1; /* reserved at zero */ - unsigned int pg_m:1; /* hardware modified (dirty) bit */ - unsigned int pg_u:1; /* hardware used (reference) bit */ - unsigned int pg_prot:1; /* write protect bit */ - unsigned int pg_v:2; /* valid bit */ -}; -#endif - -typedef int st_entry_t; /* segment table entry */ -typedef int pt_entry_t; /* Mach page table entry */ - -#define PT_ENTRY_NULL ((pt_entry_t *) 0) -#define ST_ENTRY_NULL ((st_entry_t *) 0) - -#define SG_V 0x00000002 /* segment is valid */ -#define SG_NV 0x00000000 -#define SG_PROT 0x00000004 /* access protection mask */ -#define SG_RO 0x00000004 -#define SG_RW 0x00000000 -#define SG_U 0x00000008 /* modified bit (68040) */ -#define SG_FRAME 0xfffff000 -#define SG_IMASK 0xffc00000 -#define SG_ISHIFT 22 -#define SG_PMASK 0x003ff000 -#define SG_PSHIFT 12 - -/* 68040 additions */ -#define SG4_MASK1 0xfe000000 -#define SG4_SHIFT1 25 -#define SG4_MASK2 0x01fc0000 -#define SG4_SHIFT2 18 -#define SG4_MASK3 0x0003f000 -#define SG4_SHIFT3 12 -#define SG4_ADDR1 0xfffffe00 -#define SG4_ADDR2 0xffffff00 -#define SG4_LEV1SIZE 128 -#define SG4_LEV2SIZE 128 -#define SG4_LEV3SIZE 64 - -#define PG_V 0x00000001 -#define PG_NV 0x00000000 -#define PG_PROT 0x00000004 -#define PG_U 0x00000008 -#define PG_M 0x00000010 -#define PG_W 0x00000100 -#define PG_RO 0x00000004 -#define PG_RW 0x00000000 -#define PG_FRAME 0xfffff000 -#define PG_CI 0x00000040 -#define PG_SHIFT 12 -#define PG_PFNUM(x) (((x) & PG_FRAME) >> PG_SHIFT) - -/* 68040 additions */ -#define PG_CMASK 0x00000060 /* cache mode mask */ -#define PG_CWT 0x00000000 /* writethrough caching */ -#define PG_CCB 0x00000020 /* copyback caching */ -#define PG_CIS 0x00000040 /* cache inhibited serialized */ -#define PG_CIN 0x00000060 /* cache inhibited nonserialized */ -#define PG_SO 0x00000080 /* supervisor only */ - -#define M68K_STSIZE (MAXUL2SIZE*SG4_LEV2SIZE*sizeof(st_entry_t)) - /* user process segment table size */ -#define M68K_MAX_PTSIZE 0x400000 /* max size of UPT */ -#define M68K_MAX_KPTSIZE 0x100000 /* max memory to allocate to KPT */ -#define M68K_PTBASE 0x10000000 /* UPT map base address */ -#define M68K_PTMAXSIZE 0x70000000 /* UPT map maximum size */ - -/* - * Kernel virtual address to page table entry and to physical address. - */ -#define kvtopte(va) \ - (&Sysmap[((unsigned)(va) - VM_MIN_KERNEL_ADDRESS) >> PGSHIFT]) -#define ptetokv(pt) \ - ((((pt_entry_t *)(pt) - Sysmap) << PGSHIFT) + VM_MIN_KERNEL_ADDRESS) -#define kvtophys(va) \ - ((kvtopte(va)->pg_pfnum << PGSHIFT) | ((int)(va) & PGOFSET)) - -#endif /* !_PTE_MOTOROLA_H_ */ diff --git a/sys/arch/mac68k/conf/files.mac68k b/sys/arch/mac68k/conf/files.mac68k index 07b6f6dfa94..18baa464216 100644 --- a/sys/arch/mac68k/conf/files.mac68k +++ b/sys/arch/mac68k/conf/files.mac68k @@ -1,4 +1,4 @@ -# $OpenBSD: files.mac68k,v 1.25 2001/11/30 20:58:18 miod Exp $ +# $OpenBSD: files.mac68k,v 1.26 2001/12/20 19:02:28 miod Exp $ # $NetBSD: files.mac68k,v 1.61 1997/03/01 20:22:16 scottr Exp $ # mac68k-specific configuration info @@ -114,7 +114,7 @@ file arch/mac68k/mac68k/macrom.c file arch/mac68k/mac68k/macromasm.s file arch/mac68k/mac68k/mainbus.c file arch/mac68k/mac68k/mem.c -file arch/m68k/m68k/pmap_motorola.c +file arch/mac68k/mac68k/pmap.c file arch/mac68k/mac68k/pmap_bootstrap.c file arch/mac68k/mac68k/pram.c file arch/mac68k/mac68k/pramasm.s diff --git a/sys/arch/mac68k/include/param.h b/sys/arch/mac68k/include/param.h index 50f6fcfcd50..c53102b7acd 100644 --- a/sys/arch/mac68k/include/param.h +++ b/sys/arch/mac68k/include/param.h @@ -1,4 +1,4 @@ -/* $OpenBSD: param.h,v 1.15 2001/12/05 01:57:15 provos Exp $ */ +/* $OpenBSD: param.h,v 1.16 2001/12/20 19:02:28 miod Exp $ */ /* $NetBSD: param.h,v 1.28 1997/03/01 06:57:45 scottr Exp $ */ /* @@ -98,6 +98,10 @@ #define KERNBASE 0x00000000 /* start of kernel virtual */ +#define SEGSHIFT 22 /* LOG2(NBSEG) */ +#define NBSEG (1 << SEGSHIFT) /* bytes/segment */ +#define SEGOFSET (NBSEG-1) /* byte offset into segment */ + #define UPAGES 3 /* pages of u-area */ #include <m68k/param.h> diff --git a/sys/arch/mac68k/include/pmap.h b/sys/arch/mac68k/include/pmap.h index a0ae0f2011d..c190143ed8e 100644 --- a/sys/arch/mac68k/include/pmap.h +++ b/sys/arch/mac68k/include/pmap.h @@ -1,16 +1,194 @@ -/* $OpenBSD: pmap.h,v 1.14 2001/12/02 02:01:52 millert Exp $ */ +/* $OpenBSD: pmap.h,v 1.15 2001/12/20 19:02:28 miod Exp $ */ +/* $NetBSD: pmap.h,v 1.26 1999/07/21 03:18:21 briggs Exp $ */ +/* + * Copyright (c) 1987 Carnegie-Mellon University + * Copyright (c) 1991 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. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + */ +/*- + * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, + * Michael L. Finch, Bradley A. Grantham, and + * Lawrence A. Kesteloot + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Alice Group. + * 4. The names of the Alice Group or any of its members may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``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 ALICE GROUP 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.h 7.6 (Berkeley) 5/10/91 + */ #ifndef _MAC68K_PMAP_H_ #define _MAC68K_PMAP_H_ -#include <m68k/pmap_motorola.h> +#include <machine/cpu.h> +#include <machine/pte.h> + +#if defined(M68040) +#define MAC_SEG_SIZE (mmutype == MMU_68040 ? 0x40000 : NBSEG) +#else +#define MAC_SEG_SIZE NBSEG +#endif + +#define mac68k_trunc_seg(x) (((unsigned)(x)) & ~(MAC_SEG_SIZE-1)) +#define mac68k_round_seg(x) mac68k_trunc_seg((unsigned)(x)+MAC_SEG_SIZE-1) + +/* + * Pmap stuff + */ +struct pmap { + pt_entry_t *pm_ptab; /* KVA of page table */ + st_entry_t *pm_stab; /* KVA of segment table */ + int pm_stfree; /* 040: free lev2 blocks */ + st_entry_t *pm_stpa; /* 040: ST phys addr */ + short pm_sref; /* segment table ref count */ + short pm_count; /* pmap reference count */ + struct simplelock pm_lock; /* lock on pmap */ + struct pmap_statistics pm_stats; /* pmap statistics */ + long pm_ptpages; /* more stats: PT pages */ +}; + +typedef struct pmap *pmap_t; + +/* + * On the 040, we keep track of which level 2 blocks are already in use + * with the pm_stfree mask. Bits are arranged from LSB (block 0) to MSB + * (block 31). For convenience, the level 1 table is considered to be + * block 0. + * + * MAX[KU]L2SIZE control how many pages of level 2 descriptors are allowed + * for the kernel and users. 8 implies only the initial "segment table" + * page is used. WARNING: don't change MAXUL2SIZE unless you can allocate + * physically contiguous pages for the ST in pmap.c! + */ +#define MAXKL2SIZE 32 +#define MAXUL2SIZE 8 +#define l2tobm(n) (1 << (n)) +#define bmtol2(n) (ffs(n) - 1) + +/* + * Macros for speed + */ +#define PMAP_ACTIVATE(pmap, loadhw) \ +{ \ + if ((loadhw)) \ + loadustp(m68k_btop((paddr_t)(pmap)->pm_stpa)); \ +} + +/* + * For each vm_page_t, there is a list of all currently valid virtual + * mappings of that page. An entry is a pv_entry_t, the list is pv_table. + */ +typedef struct pv_entry { + struct pv_entry *pv_next; /* next pv_entry */ + struct pmap *pv_pmap; /* pmap where mapping lies */ + vaddr_t pv_va; /* virtual address for mapping */ + st_entry_t *pv_ptste; /* non-zero if VA maps a PT page */ + struct pmap *pv_ptpmap; /* if pv_ptste, pmap for PT page */ + int pv_flags; /* flags */ +} *pv_entry_t; + +#define PV_CI 0x01 /* all entries must be cache inhibited */ +#define PV_PTPAGE 0x02 /* entry maps a page table page */ + +struct pv_page; + +struct pv_page_info { + TAILQ_ENTRY(pv_page) pgi_list; + struct pv_entry *pgi_freelist; + int pgi_nfree; +}; + +/* + * This is basically: + * ((NBPG - sizeof(struct pv_page_info)) / sizeof(struct pv_entry)) + */ +#define NPVPPG 170 + +struct pv_page { + struct pv_page_info pvp_pgi; + struct pv_entry pvp_pv[NPVPPG]; +}; #ifdef _KERNEL +extern struct pmap kernel_pmap_store; + +#define pmap_kernel() (&kernel_pmap_store) +#define active_pmap(pm) \ + ((pm) == pmap_kernel() || (pm) == curproc->p_vmspace->vm_map.pmap) +#define active_user_pmap(pm) \ + (curproc && \ + (pm) != pmap_kernel() && (pm) == curproc->p_vmspace->vm_map.pmap) + +extern struct pv_entry *pv_table; /* array of entries, one per page */ + +#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count) +#define pmap_wired_count(pmap) ((pmap)->pm_stats.wired_count) +#define pmap_update(pmap) /* nothing */ -void mac68k_set_pte __P((vaddr_t va, paddr_t pge)); +extern pt_entry_t *Sysmap; +extern char *vmmap; /* map for mem, dumps, etc. */ -void pmap_init_md __P((void)); -#define PMAP_INIT_MD() pmap_init_md() +/* pmap.c */ +vm_offset_t pmap_map __P((vaddr_t, paddr_t, paddr_t, int)); +void mac68k_set_pte __P((vm_offset_t va, vm_offset_t pge)); #endif /* _KERNEL */ diff --git a/sys/arch/mac68k/include/pte.h b/sys/arch/mac68k/include/pte.h index bf2f20714e4..e15eaaf41d6 100644 --- a/sys/arch/mac68k/include/pte.h +++ b/sys/arch/mac68k/include/pte.h @@ -1,14 +1,156 @@ -/* $OpenBSD: pte.h,v 1.5 2001/11/30 20:58:18 miod Exp $ */ +/* $OpenBSD: pte.h,v 1.6 2001/12/20 19:02:28 miod Exp $ */ +/* $NetBSD: pte.h,v 1.9 1996/05/05 06:17:58 briggs Exp $ */ -#ifndef _MACHINE_PTE_H_ -#define _MACHINE_PTE_H_ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1982, 1990 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. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + */ +/*- + * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, + * Michael L. Finch, Bradley A. Grantham, and + * Lawrence A. Kesteloot + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Alice Group. + * 4. The names of the Alice Group or any of its members may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``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 ALICE GROUP 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. + * + */ +/* + * from: Utah $Hdr: pte.h 1.11 89/09/03$ + * + * @(#)pte.h 7.3 (Berkeley) 5/8/91 + */ -#include <m68k/pte_motorola.h> +#ifndef _MAC68K_PTE_H_ +#define _MAC68K_PTE_H_ -#define MACHINE_STSIZE M68K_STSIZE -#define MACHINE_MAX_PTSIZE M68K_MAX_PTSIZE -#define MACHINE_MAX_KPTSIZE M68K_MAX_KPTSIZE -#define MACHINE_PTBASE M68K_PTBASE -#define MACHINE_PTMAXSIZE M68K_PTMAXSIZE +/* + * Mac hardware segment/page table entries + */ -#endif /* _MACHINE_PTE_H_ */ +typedef int st_entry_t; /* segment table entry */ +typedef int pt_entry_t; /* Mach page table entry */ + +#define PT_ENTRY_NULL ((pt_entry_t *) 0) +#define ST_ENTRY_NULL ((st_entry_t *) 0) + +#define SG_V 0x00000002 /* segment is valid */ +#define SG_NV 0x00000000 +#define SG_PROT 0x00000004 /* access protection mask */ +#define SG_RO 0x00000004 +#define SG_RW 0x00000000 +#define SG_U 0x00000008 /* modified bit (68040) */ +#define SG_FRAME 0xfffff000 +#define SG_IMASK 0xffc00000 +#define SG_ISHIFT 22 +#define SG_PMASK 0x003ff000 +#define SG_PSHIFT 12 + +/* 68040 additions */ +#define SG4_MASK1 0xfe000000 +#define SG4_SHIFT1 25 +#define SG4_MASK2 0x01fc0000 +#define SG4_SHIFT2 18 +#define SG4_MASK3 0x0003f000 +#define SG4_SHIFT3 12 +#define SG4_ADDR1 0xfffffe00 +#define SG4_ADDR2 0xffffff00 +#define SG4_LEV1SIZE 128 +#define SG4_LEV2SIZE 128 +#define SG4_LEV3SIZE 64 + +#define PG_V 0x00000001 +#define PG_NV 0x00000000 +#define PG_PROT 0x00000004 +#define PG_U 0x00000008 +#define PG_M 0x00000010 +#define PG_W 0x00000100 +#define PG_RO 0x00000004 +#define PG_RW 0x00000000 +#define PG_FRAME 0xfffff000 +#define PG_CI 0x00000040 +#define PG_SHIFT 12 +#define PG_PFNUM(x) (((x) & PG_FRAME) >> PG_SHIFT) + +/* 68040 additions */ +#define PG_CMASK 0x00000060 /* cache mode mask */ +#define PG_CWT 0x00000000 /* writethrough caching */ +#define PG_CCB 0x00000020 /* copyback caching */ +#define PG_CIS 0x00000040 /* cache inhibited serialized */ +#define PG_CIN 0x00000060 /* cache inhibited nonserialized */ +#define PG_SO 0x00000080 /* supervisor only */ + +#define MAC_STSIZE (MAXUL2SIZE*SG4_LEV2SIZE*sizeof(st_entry_t)) + /* user process segment table size */ +#define MAC_MAX_PTSIZE 0x400000 /* max size of UPT */ +#define MAC_MAX_KPTSIZE 0x100000 /* max memory to allocate to KPT */ +#define MAC_PTBASE 0x10000000 /* UPT map base address */ +#define MAC_PTMAXSIZE 0x70000000 /* UPT map maximum size */ + +/* + * Kernel virtual address to page table entry and to physical address. + */ +#define kvtopte(va) \ + (&Sysmap[((unsigned)(va) - VM_MIN_KERNEL_ADDRESS) >> PGSHIFT]) +#define ptetokv(pt) \ + ((((pt_entry_t *)(pt) - Sysmap) << PGSHIFT) + VM_MIN_KERNEL_ADDRESS) +#define kvtophys(va) \ + ((kvtopte(va)->pg_pfnum << PGSHIFT) | ((int)(va) & PGOFSET)) + +#endif /* _MAC68K_PTE_H_ */ diff --git a/sys/arch/mac68k/mac68k/pmap.c b/sys/arch/mac68k/mac68k/pmap.c new file mode 100644 index 00000000000..6ff46799375 --- /dev/null +++ b/sys/arch/mac68k/mac68k/pmap.c @@ -0,0 +1,2351 @@ +/* $OpenBSD: pmap.c,v 1.37 2001/12/20 19:02:28 miod Exp $ */ +/* $NetBSD: pmap.c,v 1.55 1999/04/22 04:24:53 chs Exp $ */ + +/* + * Copyright (c) 1991, 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. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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.6 (Berkeley) 5/27/94 + */ + +/* + * Derived from HP9000/300 series physical map management code. + * + * Supports: + * 68020 with 68851 MMU Mac II + * 68030 with on-chip MMU IIcx, etc. + * 68040 with on-chip MMU Quadras, etc. + * + * Notes: + * Don't even pay lip service to multiprocessor support. + * + * We assume TLB entries don't have process tags (except for the + * supervisor/user distinction) so we only invalidate TLB entries + * when changing mappings for the current (or kernel) pmap. This is + * technically not true for the 68551 but we flush the TLB on every + * context switch, so it effectively winds up that way. + * + * Bitwise and/or operations are significantly faster than bitfield + * references so we use them when accessing STE/PTEs in the pmap_pte_* + * macros. Note also that the two are not always equivalent; e.g.: + * (*pte & PG_PROT)[4] != pte->pg_prot[1] + * and a couple of routines that deal with protection and wiring take + * some shortcuts that assume the and/or definitions. + * + * This implementation will only work for PAGE_SIZE == NBPG + * (i.e. 4096 bytes). + */ + +/* + * 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/user.h> +#include <sys/pool.h> + +#include <machine/pte.h> + +#include <uvm/uvm.h> + +#include <machine/cpu.h> + +#ifdef DEBUG +#define PDB_FOLLOW 0x0001 +#define PDB_INIT 0x0002 +#define PDB_ENTER 0x0004 +#define PDB_REMOVE 0x0008 +#define PDB_CREATE 0x0010 +#define PDB_PTPAGE 0x0020 +#define PDB_CACHE 0x0040 +#define PDB_BITS 0x0080 +#define PDB_COLLECT 0x0100 +#define PDB_PROTECT 0x0200 +#define PDB_SEGTAB 0x0400 +#define PDB_MULTIMAP 0x0800 +#define PDB_PARANOIA 0x2000 +#define PDB_WIRING 0x4000 +#define PDB_PVDUMP 0x8000 + +int debugmap = 0; +int pmapdebug = PDB_PARANOIA; + +#define PMAP_DPRINTF(l, x) if (pmapdebug & (l)) printf x + +#if defined(M68040) +int dowriteback = 1; /* 68040: enable writeback caching */ +int dokwriteback = 1; /* 68040: enable writeback caching of kernel AS */ +#endif +#else /* ! DEBUG */ +#define PMAP_DPRINTF(l, x) /* nothing */ +#endif /* DEBUG */ + +/* + * Get STEs and PTEs for user/kernel address space + */ +#if defined(M68040) +#define pmap_ste1(m, v) \ + (&((m)->pm_stab[(vaddr_t)(v) >> SG4_SHIFT1])) +/* XXX assumes physically contiguous ST pages (if more than one) */ +#define pmap_ste2(m, v) \ + (&((m)->pm_stab[(st_entry_t *)(*(u_int *)pmap_ste1(m, v) & SG4_ADDR1) \ + - (m)->pm_stpa + (((v) & SG4_MASK2) >> SG4_SHIFT2)])) +#define pmap_ste(m, v) \ + (&((m)->pm_stab[(vaddr_t)(v) \ + >> (mmutype == MMU_68040 ? SG4_SHIFT1 : SG_ISHIFT)])) +#define pmap_ste_v(m, v) \ + (mmutype == MMU_68040 \ + ? ((*pmap_ste1(m, v) & SG_V) && \ + (*pmap_ste2(m, v) & SG_V)) \ + : (*pmap_ste(m, v) & SG_V)) +#else +#define pmap_ste(m, v) (&((m)->pm_stab[(vaddr_t)(v) >> SG_ISHIFT])) +#define pmap_ste_v(m, v) (*pmap_ste(m, v) & SG_V) +#endif + +#define pmap_pte(m, v) (&((m)->pm_ptab[(vaddr_t)(v) >> PG_SHIFT])) +#define pmap_pte_pa(pte) (*(pte) & PG_FRAME) +#define pmap_pte_w(pte) (*(pte) & PG_W) +#define pmap_pte_ci(pte) (*(pte) & PG_CI) +#define pmap_pte_m(pte) (*(pte) & PG_M) +#define pmap_pte_u(pte) (*(pte) & PG_U) +#define pmap_pte_prot(pte) (*(pte) & PG_PROT) +#define pmap_pte_v(pte) (*(pte) & PG_V) + +#define pmap_pte_set_w(pte, v) \ + if (v) *(pte) |= PG_W; else *(pte) &= ~PG_W +#define pmap_pte_set_prot(pte, v) \ + if (v) *(pte) |= PG_PROT; else *(pte) &= ~PG_PROT +#define pmap_pte_w_chg(pte, nw) ((nw) ^ pmap_pte_w(pte)) +#define pmap_pte_prot_chg(pte, np) ((np) ^ pmap_pte_prot(pte)) + +/* + * Given a map and a machine independent protection code, + * convert to a m68k protection code. + */ +#define pte_prot(m, p) (protection_codes[p]) +int protection_codes[8]; + +/* + * Kernel page table page management. + */ +struct kpt_page { + struct kpt_page *kpt_next; /* link on either used or free list */ + vaddr_t kpt_va; /* always valid kernel VA */ + paddr_t kpt_pa; /* PA of this page (for speed) */ +}; +struct kpt_page *kpt_free_list, *kpt_used_list; +struct kpt_page *kpt_pages; + +/* + * Kernel segment/page table and page table map. + * The page table map gives us a level of indirection we need to dynamically + * expand the page table. It is essentially a copy of the segment table + * with PTEs instead of STEs. All are initialized in locore at boot time. + * Sysmap will initially contain VM_KERNEL_PT_PAGES pages of PTEs. + * Segtabzero is an empty segment table which all processes share til they + * reference something. + */ +st_entry_t *Sysseg; +pt_entry_t *Sysmap, *Sysptmap; +st_entry_t *Segtabzero, *Segtabzeropa; +vsize_t Sysptsize = VM_KERNEL_PT_PAGES; + +struct pmap kernel_pmap_store; +struct vm_map *st_map, *pt_map; +struct vm_map st_map_store, pt_map_store; + +paddr_t avail_start; /* PA of first available physical page */ +paddr_t avail_end; /* PA of last available physical page */ +vsize_t mem_size; /* memory size in bytes */ +vaddr_t virtual_avail; /* VA of first avail page (after kernel bss)*/ +vaddr_t virtual_end; /* VA of last avail page (end of kernel AS) */ +int page_cnt; /* number of pages managed by VM system */ + +boolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */ +struct pv_entry *pv_table; +char *pmap_attributes; /* reference and modify bits */ +TAILQ_HEAD(pv_page_list, pv_page) pv_page_freelist; +int pv_nfree; + +/* The following four variables are defined in pmap_bootstrap.c */ +extern int vidlen; +#define VIDMAPSIZE btoc(vidlen) + +#if defined(M68040) +int protostfree; /* prototype (default) free ST map */ +#endif + +extern caddr_t CADDR1, CADDR2; + +pt_entry_t *caddr1_pte; /* PTE for CADDR1 */ +pt_entry_t *caddr2_pte; /* PTE for CADDR2 */ + +struct pool pmap_pmap_pool; /* memory pool for pmap structures */ + +struct pv_entry *pmap_alloc_pv __P((void)); +void pmap_free_pv __P((struct pv_entry *)); +void pmap_collect_pv __P((void)); + +#define PAGE_IS_MANAGED(pa) (pmap_initialized && \ + vm_physseg_find(atop((pa)), NULL) != -1) + +#define pa_to_pvh(pa) \ +({ \ + int bank_, pg_; \ + \ + bank_ = vm_physseg_find(atop((pa)), &pg_); \ + &vm_physmem[bank_].pmseg.pvent[pg_]; \ +}) + +#define pa_to_attribute(pa) \ +({ \ + int bank_, pg_; \ + \ + bank_ = vm_physseg_find(atop((pa)), &pg_); \ + &vm_physmem[bank_].pmseg.attrs[pg_]; \ +}) + +/* + * Internal routines + */ +void pmap_remove_mapping __P((pmap_t, vaddr_t, pt_entry_t *, int)); +boolean_t pmap_testbit __P((paddr_t, int)); +void pmap_changebit __P((paddr_t, int, int)); +void pmap_enter_ptpage __P((pmap_t, vaddr_t)); +void pmap_collect1 __P((pmap_t, paddr_t, vaddr_t)); +void pmap_pinit __P((pmap_t)); +void pmap_release __P((pmap_t)); + +#ifdef DEBUG +void pmap_pvdump __P((paddr_t)); +void pmap_check_wiring __P((char *, vaddr_t)); +#endif + +/* pmap_remove_mapping flags */ +#define PRM_TFLUSH 1 +#define PRM_CFLUSH 2 + +/* + * pmap_virtual_space: [ INTERFACE ] + * + * Report the range of available kernel virtual address + * space to the VM system during bootstrap. + * + * This is only an interface function if we do not use + * pmap_steal_memory()! + * + * Note: no locking is necessary in this function. + */ +void +pmap_virtual_space(vstartp, vendp) + vaddr_t *vstartp, *vendp; +{ + + *vstartp = virtual_avail; + *vendp = virtual_end; +} + +/* + * pmap_init: [ INTERFACE ] + * + * Initialize the pmap module. Called by vm_init(), to initialize any + * structures that the pmap system needs to map virtual memory. + * + * Note: no locking is necessary in this function. + */ +void +pmap_init() +{ + vaddr_t addr, addr2; + vsize_t s; + struct pv_entry *pv; + char *attr; + int rv; + int npages; + int bank; + + PMAP_DPRINTF(PDB_FOLLOW, ("pmap_init()\n")); + + /* + * Before we do anything else, initialize the PTE pointers + * used by pmap_zero_page() and pmap_copy_page(). + */ + caddr1_pte = pmap_pte(pmap_kernel(), CADDR1); + caddr2_pte = pmap_pte(pmap_kernel(), CADDR2); + + /* + * Now that kernel map has been allocated, we can mark as + * unavailable regions which we have mapped in pmap_bootstrap(). + */ + addr = (vaddr_t)IOBase; + if (uvm_map(kernel_map, &addr, + m68k_ptob(IIOMAPSIZE + ROMMAPSIZE + VIDMAPSIZE), + NULL, UVM_UNKNOWN_OFFSET, 0, + UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, + UVM_INH_NONE, UVM_ADV_RANDOM, + UVM_FLAG_FIXED))) + goto bogons; + addr = (vaddr_t)Sysmap; + if (uvm_map(kernel_map, &addr, MAC_MAX_PTSIZE, + NULL, UVM_UNKNOWN_OFFSET, 0, + UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, + UVM_INH_NONE, UVM_ADV_RANDOM, + UVM_FLAG_FIXED))) { + /* + * If this fails, it is probably because the static + * portion of the kernel page table isn't big enough + * and we overran the page table map. + */ + bogons: + panic("pmap_init: bogons in the VM system!\n"); + } + + PMAP_DPRINTF(PDB_INIT, + ("pmap_init: Sysseg %p, Sysmap %p, Sysptmap %p\n", + Sysseg, Sysmap, Sysptmap)); + PMAP_DPRINTF(PDB_INIT, + (" pstart %lx, pend %lx, vstart %lx, vend %lx\n", + avail_start, avail_end, virtual_avail, virtual_end)); + + /* + * Allocate memory for random pmap data structures. Includes the + * initial segment table, pv_head_table and pmap_attributes. + */ + for (page_cnt = 0, bank = 0; bank < vm_nphysseg; bank++) + page_cnt += vm_physmem[bank].end - vm_physmem[bank].start; + s = MAC_STSIZE; /* Segtabzero */ + s += page_cnt * sizeof(struct pv_entry); /* pv table */ + s += page_cnt * sizeof(char); /* attribute table */ + s = round_page(s); + addr = uvm_km_zalloc(kernel_map, s); + if (addr == 0) + panic("pmap_init: can't allocate data structures"); + + Segtabzero = (st_entry_t *)addr; + pmap_extract(pmap_kernel(), addr, (paddr_t *)&Segtabzeropa); + addr += MAC_STSIZE; + + pv_table = (struct pv_entry *)addr; + addr += page_cnt * sizeof(struct pv_entry); + + pmap_attributes = (char *)addr; + + PMAP_DPRINTF(PDB_INIT, ("pmap_init: %lx bytes: page_cnt %x s0 %p(%p) " + "tbl %p atr %p\n", + s, page_cnt, Segtabzero, Segtabzeropa, + pv_table, pmap_attributes)); + + /* + * Now that the pv and attribute tables have been allocated, + * assign them to the memory segments. + */ + pv = pv_table; + attr = pmap_attributes; + for (bank = 0; bank < vm_nphysseg; bank++) { + npages = vm_physmem[bank].end - vm_physmem[bank].start; + vm_physmem[bank].pmseg.pvent = pv; + vm_physmem[bank].pmseg.attrs = attr; + pv += npages; + attr += npages; + } + + /* + * Allocate physical memory for kernel PT pages and their management. + * We need 1 PT page per possible task plus some slop. + */ + npages = min(atop(MAC_MAX_KPTSIZE), maxproc+16); + s = ptoa(npages) + round_page(npages * sizeof(struct kpt_page)); + + /* + * Verify that space will be allocated in region for which + * we already have kernel PT pages. + */ + addr = 0; + rv = uvm_map(kernel_map, &addr, s, NULL, UVM_UNKNOWN_OFFSET, 0, + UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, + UVM_ADV_RANDOM, UVM_FLAG_NOMERGE)); + if (rv || (addr + s) >= (vaddr_t)Sysmap) + panic("pmap_init: kernel PT too small"); + uvm_unmap(kernel_map, addr, addr + s); + + /* + * Now allocate the space and link the pages together to + * form the KPT free list. + */ + addr = uvm_km_zalloc(kernel_map, s); + if (addr == 0) + panic("pmap_init: cannot allocate KPT free list"); + s = ptoa(npages); + addr2 = addr + s; + kpt_pages = &((struct kpt_page *)addr2)[npages]; + kpt_free_list = (struct kpt_page *)0; + do { + addr2 -= NBPG; + (--kpt_pages)->kpt_next = kpt_free_list; + kpt_free_list = kpt_pages; + kpt_pages->kpt_va = addr2; + pmap_extract(pmap_kernel(), addr2, &kpt_pages->kpt_pa); + } while (addr != addr2); + + PMAP_DPRINTF(PDB_INIT, ("pmap_init: KPT: %ld pages from %lx to %lx\n", + atop(s), addr, addr + s)); + + /* + * Allocate the segment table map and the page table map. + */ + s = maxproc * MAC_STSIZE; + st_map = uvm_km_suballoc(kernel_map, &addr, &addr2, s, TRUE, + FALSE, &st_map_store); + + addr = MAC_PTBASE; + if ((MAC_PTMAXSIZE / MAC_MAX_PTSIZE) < maxproc) { + s = MAC_PTMAXSIZE; + /* + * XXX We don't want to hang when we run out of + * page tables, so we lower maxproc so that fork() + * will fail instead. Note that root could still raise + * this value via sysctl(2). + */ + maxproc = (MAC_PTMAXSIZE / MAC_MAX_PTSIZE); + } else + s = (maxproc * MAC_MAX_PTSIZE); + pt_map = uvm_km_suballoc(kernel_map, &addr, &addr2, s, TRUE, + TRUE, &pt_map_store); + +#if defined(M68040) + if (mmutype == MMU_68040) { + protostfree = ~l2tobm(0); + for (rv = MAXUL2SIZE; rv < sizeof(protostfree)*NBBY; rv++) + protostfree &= ~l2tobm(rv); + } +#endif + + /* + * Initialize the pmap pools. + */ + pool_init(&pmap_pmap_pool, sizeof(struct pmap), 0, 0, 0, "pmappl", + 0, pool_page_alloc_nointr, pool_page_free_nointr, M_VMPMAP); + + /* + * Now it is safe to enable pv_table recording. + */ + pmap_initialized = TRUE; +} + +/* + * pmap_alloc_pv: + * + * Allocate a pv_entry. + */ +struct pv_entry * +pmap_alloc_pv() +{ + struct pv_page *pvp; + struct pv_entry *pv; + int i; + + if (pv_nfree == 0) { + pvp = (struct pv_page *)uvm_km_zalloc(kernel_map, NBPG); + if (pvp == 0) + panic("pmap_alloc_pv: uvm_km_zalloc() failed"); + pvp->pvp_pgi.pgi_freelist = pv = &pvp->pvp_pv[1]; + for (i = NPVPPG - 2; i; i--, pv++) + pv->pv_next = pv + 1; + pv->pv_next = 0; + pv_nfree += pvp->pvp_pgi.pgi_nfree = NPVPPG - 1; + TAILQ_INSERT_HEAD(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + pv = &pvp->pvp_pv[0]; + } else { + --pv_nfree; + pvp = pv_page_freelist.tqh_first; + if (--pvp->pvp_pgi.pgi_nfree == 0) { + TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + } + pv = pvp->pvp_pgi.pgi_freelist; +#ifdef DIAGNOSTIC + if (pv == 0) + panic("pmap_alloc_pv: pgi_nfree inconsistent"); +#endif + pvp->pvp_pgi.pgi_freelist = pv->pv_next; + } + return pv; +} + +/* + * pmap_free_pv: + * + * Free a pv_entry. + */ +void +pmap_free_pv(pv) + struct pv_entry *pv; +{ + struct pv_page *pvp; + + pvp = (struct pv_page *) trunc_page((vaddr_t)pv); + switch (++pvp->pvp_pgi.pgi_nfree) { + case 1: + TAILQ_INSERT_TAIL(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + default: + pv->pv_next = pvp->pvp_pgi.pgi_freelist; + pvp->pvp_pgi.pgi_freelist = pv; + ++pv_nfree; + break; + case NPVPPG: + pv_nfree -= NPVPPG - 1; + TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + uvm_km_free(kernel_map, (vaddr_t)pvp, NBPG); + break; + } +} + +/* + * pmap_collect_pv: + * + * Perform compaction on the PV list, called via pmap_collect(). + */ +void +pmap_collect_pv() +{ + struct pv_page_list pv_page_collectlist; + struct pv_page *pvp, *npvp; + struct pv_entry *ph, *ppv, *pv, *npv; + int s; + + TAILQ_INIT(&pv_page_collectlist); + + for (pvp = pv_page_freelist.tqh_first; pvp; pvp = npvp) { + if (pv_nfree < NPVPPG) + break; + npvp = pvp->pvp_pgi.pgi_list.tqe_next; + if (pvp->pvp_pgi.pgi_nfree > NPVPPG / 3) { + TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + TAILQ_INSERT_TAIL(&pv_page_collectlist, pvp, + pvp_pgi.pgi_list); + pv_nfree -= NPVPPG; + pvp->pvp_pgi.pgi_nfree = -1; + } + } + + if (pv_page_collectlist.tqh_first == 0) + return; + + for (ph = &pv_table[page_cnt - 1]; ph >= &pv_table[0]; ph--) { + if (ph->pv_pmap == 0) + continue; + s = splimp(); + for (ppv = ph; (pv = ppv->pv_next) != 0; ) { + pvp = (struct pv_page *) trunc_page((vaddr_t)pv); + if (pvp->pvp_pgi.pgi_nfree == -1) { + pvp = pv_page_freelist.tqh_first; + if (--pvp->pvp_pgi.pgi_nfree == 0) { + TAILQ_REMOVE(&pv_page_freelist, pvp, + pvp_pgi.pgi_list); + } + npv = pvp->pvp_pgi.pgi_freelist; +#ifdef DIAGNOSTIC + if (npv == 0) + panic("pmap_collect_pv: pgi_nfree inconsistent"); +#endif + pvp->pvp_pgi.pgi_freelist = npv->pv_next; + *npv = *pv; + ppv->pv_next = npv; + ppv = npv; + } else + ppv = pv; + } + splx(s); + } + + for (pvp = pv_page_collectlist.tqh_first; pvp; pvp = npvp) { + npvp = pvp->pvp_pgi.pgi_list.tqe_next; + uvm_km_free(kernel_map, (vaddr_t)pvp, NBPG); + } +} + +/* + * pmap_map: + * + * Used to map a range of physical addresses into kernel + * virtual address space. + * + * For now, VM is already on, we only need to map the + * specified memory. + * + * Note: THIS FUNCTION IS DEPRECATED, AND SHOULD BE REMOVED! + */ +vaddr_t +pmap_map(va, spa, epa, prot) + vaddr_t va; + paddr_t spa, epa; + int prot; +{ + + PMAP_DPRINTF(PDB_FOLLOW, + ("pmap_map(%lx, %lx, %lx, %x)\n", va, spa, epa, prot)); + + while (spa < epa) { + pmap_enter(pmap_kernel(), va, spa, prot, 0); + va += NBPG; + spa += NBPG; + } + return (va); +} + +/* + * pmap_create: [ INTERFACE ] + * + * Create and return a physical map. + * + * Note: no locking is necessary in this function. + */ +struct pmap * +pmap_create(void) +{ + struct pmap *pmap; + + PMAP_DPRINTF(PDB_FOLLOW|PDB_CREATE, + ("pmap_create(%lx)\n", size)); + + pmap = pool_get(&pmap_pmap_pool, PR_WAITOK); + + bzero(pmap, sizeof(*pmap)); + pmap_pinit(pmap); + return (pmap); +} + +/* + * pmap_pinit: + * + * Initialize a preallocated and zeroed pmap structure. + * + * Note: THIS FUNCTION SHOULD BE MOVED INTO pmap_create()! + */ +void +pmap_pinit(pmap) + struct pmap *pmap; +{ + + PMAP_DPRINTF(PDB_FOLLOW|PDB_CREATE, + ("pmap_pinit(%p)\n", pmap)); + + /* + * No need to allocate page table space yet but we do need a + * valid segment table. Initially, we point everyone at the + * "null" segment table. On the first pmap_enter, a real + * segment table will be allocated. + */ + pmap->pm_stab = Segtabzero; + pmap->pm_stpa = Segtabzeropa; +#if defined(M68040) + if (mmutype == MMU_68040) + pmap->pm_stfree = protostfree; +#endif + pmap->pm_count = 1; + simple_lock_init(&pmap->pm_lock); +} + +/* + * pmap_destroy: [ INTERFACE ] + * + * Drop the reference count on the specified pmap, releasing + * all resources if the reference count drops to zero. + */ +void +pmap_destroy(pmap) + pmap_t pmap; +{ + int count; + + if (pmap == NULL) + return; + + PMAP_DPRINTF(PDB_FOLLOW, ("pmap_destroy(%p)\n", pmap)); + + simple_lock(&pmap->pm_lock); + count = --pmap->pm_count; + simple_unlock(&pmap->pm_lock); + if (count == 0) { + pmap_release(pmap); + pool_put(&pmap_pmap_pool, pmap); + } +} + +/* + * pmap_release: + * + * Relese the resources held by a pmap. + * + * Note: THIS FUNCTION SHOULD BE MOVED INTO pmap_destroy(). + */ +void +pmap_release(pmap) + struct pmap *pmap; +{ + + PMAP_DPRINTF(PDB_FOLLOW, ("pmap_release(%p)\n", pmap)); + +#ifdef notdef /* DIAGNOSTIC */ + /* count would be 0 from pmap_destroy... */ + simple_lock(&pmap->pm_lock); + if (pmap->pm_count != 1) + panic("pmap_release count"); +#endif + + if (pmap->pm_ptab) + uvm_km_free_wakeup(pt_map, (vaddr_t)pmap->pm_ptab, + MAC_MAX_PTSIZE); + if (pmap->pm_stab != Segtabzero) + uvm_km_free_wakeup(st_map, (vaddr_t)pmap->pm_stab, + MAC_STSIZE); +} + +/* + * pmap_reference: [ INTERFACE ] + * + * Add a reference to the specified pmap. + */ +void +pmap_reference(pmap) + pmap_t pmap; +{ + + if (pmap == NULL) + return; + + PMAP_DPRINTF(PDB_FOLLOW, ("pmap_reference(%p)\n", pmap)); + + simple_lock(&pmap->pm_lock); + pmap->pm_count++; + simple_unlock(&pmap->pm_lock); +} + + /* + * pmap_activate: [ INTERFACE ] + * + * Activate the pmap used by the specified process. This includes + * reloading the MMU context if the current process, and marking + * the pmap in use by the processor. + * + * Note: we may only use spin locks here, since we are called + * by a critical section in cpu_switch()! + */ +void +pmap_activate(p) + struct proc *p; +{ + pmap_t pmap = p->p_vmspace->vm_map.pmap; + + PMAP_DPRINTF(PDB_FOLLOW|PDB_SEGTAB, + ("pmap_activate(%p)\n", p)); + + PMAP_ACTIVATE(pmap, p == curproc); +} + +/* + * pmap_deactivate: [ INTERFACE ] + * + * Mark that the pmap used by the specified process is no longer + * in use by the processor. + * + * The comment above pmap_activate() wrt. locking applies here, + * as well. + */ +void +pmap_deactivate(p) + struct proc *p; +{ + + /* No action necessary in this pmap implementation. */ +} + +/* + * pmap_remove: [ INTERFACE ] + * + * Remove 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_remove(pmap, sva, eva) + pmap_t pmap; + vaddr_t sva, eva; +{ + vaddr_t nssva; + pt_entry_t *pte; + boolean_t firstpage, needcflush; + int flags; + + PMAP_DPRINTF(PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT, + ("pmap_remove(%p, %lx, %lx)\n", pmap, sva, eva)); + + if (pmap == NULL) + return; + + firstpage = TRUE; + needcflush = FALSE; + flags = active_pmap(pmap) ? PRM_TFLUSH : 0; + while (sva < eva) { + nssva = mac68k_trunc_seg(sva) + MAC_SEG_SIZE; + if (nssva == 0 || nssva > eva) + nssva = eva; + /* + * If VA belongs to an unallocated segment, + * skip to the next segment boundary. + */ + if (!pmap_ste_v(pmap, sva)) { + sva = nssva; + continue; + } + /* + * Invalidate every valid mapping within this segment. + */ + pte = pmap_pte(pmap, sva); + while (sva < nssva) { + if (pmap_pte_v(pte)) { + pmap_remove_mapping(pmap, sva, pte, flags); + firstpage = FALSE; + } + pte++; + sva += NBPG; + } + } + /* + * Didn't do anything, no need for cache flushes + */ + if (firstpage) + return; +} + +/* + * pmap_page_protect: [ INTERFACE ] + * + * Lower the permission for all mappings to a given page to + * the permissions specified. + */ +void +pmap_page_protect(struct vm_page *pg, vm_prot_t prot) +{ + paddr_t pa; + struct pv_entry *pv; + int s; + + pa = VM_PAGE_TO_PHYS(pg); + +#ifdef DEBUG + if ((pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) || + (prot == VM_PROT_NONE && (pmapdebug & PDB_REMOVE))) + printf("pmap_page_protect(%lx, %x)\n", pa, prot); +#endif + if (PAGE_IS_MANAGED(pa) == 0) + return; + + switch (prot) { + case VM_PROT_READ|VM_PROT_WRITE: + case VM_PROT_ALL: + return; + /* copy_on_write */ + case VM_PROT_READ: + case VM_PROT_READ|VM_PROT_EXECUTE: + pmap_changebit(pa, PG_RO, ~0); + return; + /* remove_all */ + default: + break; + } + pv = pa_to_pvh(pa); + s = splimp(); + while (pv->pv_pmap != NULL) { + pt_entry_t *pte; + + pte = pmap_pte(pv->pv_pmap, pv->pv_va); +#ifdef DEBUG + if (!pmap_ste_v(pv->pv_pmap, pv->pv_va) || + pmap_pte_pa(pte) != pa) + panic("pmap_page_protect: bad mapping"); +#endif + if (!pmap_pte_w(pte)) + pmap_remove_mapping(pv->pv_pmap, pv->pv_va, + pte, PRM_TFLUSH|PRM_CFLUSH); + else { + pv = pv->pv_next; +#ifdef DEBUG + if (pmapdebug & PDB_PARANOIA) + printf("%s wired mapping for %lx not removed\n", + "pmap_page_protect:", pa); +#endif + if (pv == NULL) + break; + } + } + splx(s); +} + +/* + * pmap_protect: [ INTERFACE ] + * + * Set the physical protectoin on the specified range of this map + * as requested. + */ +void +pmap_protect(pmap, sva, eva, prot) + pmap_t pmap; + vaddr_t sva, eva; + vm_prot_t prot; +{ + vaddr_t nssva; + pt_entry_t *pte; + boolean_t firstpage, needtflush; + int isro; + + PMAP_DPRINTF(PDB_FOLLOW|PDB_PROTECT, + ("pmap_protect(%p, %lx, %lx, %x)\n", + pmap, sva, eva, prot)); + + if (pmap == NULL) + return; + + if ((prot & VM_PROT_READ) == VM_PROT_NONE) { + pmap_remove(pmap, sva, eva); + return; + } + if (prot & VM_PROT_WRITE) + return; + + isro = pte_prot(pmap, prot); + needtflush = active_pmap(pmap); + firstpage = TRUE; + while (sva < eva) { + nssva = mac68k_trunc_seg(sva) + MAC_SEG_SIZE; + if (nssva == 0 || nssva > eva) + nssva = eva; + /* + * If VA belongs to an unallocated segment, + * skip to the next segment boundary. + */ + if (!pmap_ste_v(pmap, sva)) { + sva = nssva; + continue; + } + /* + * Change protection on mapping if it is valid and doesn't + * already have the correct protection. + */ + pte = pmap_pte(pmap, sva); + while (sva < nssva) { + if (pmap_pte_v(pte) && pmap_pte_prot_chg(pte, isro)) { +#if defined(M68040) + /* + * Clear caches if making RO (see section + * "7.3 Cache Coherency" in the manual). + */ + if (isro && mmutype == MMU_68040) { + paddr_t pa = pmap_pte_pa(pte); + + DCFP(pa); + ICPP(pa); + } +#endif + pmap_pte_set_prot(pte, isro); + if (needtflush) + TBIS(sva); + firstpage = FALSE; + } + pte++; + sva += NBPG; + } + } +} + +void +mac68k_set_pte(va, pge) + vm_offset_t va; + vm_offset_t pge; +{ +extern vm_offset_t tmp_vpages[]; + register pt_entry_t *pte; + + if (va != tmp_vpages[0]) + return; + + pte = pmap_pte(pmap_kernel(), va); + *pte = (pt_entry_t) pge; +} + +/* + * pmap_enter: [ INTERFACE ] + * + * Insert the given physical page (pa) at + * the specified virtual address (va) in the + * target physical map with the protection requested. + * + * If specified, the page will be wired down, meaning + * that the related pte cannot be reclaimed. + * + * Note: This is the only routine which MAY NOT lazy-evaluate + * or lose information. Thatis, this routine must actually + * insert this page into the given map NOW. + */ +int +pmap_enter(pmap, va, pa, prot, flags) + pmap_t pmap; + vaddr_t va; + paddr_t pa; + vm_prot_t prot; + int flags; +{ + pt_entry_t *pte; + int npte; + paddr_t opa; + boolean_t cacheable = TRUE; + boolean_t checkpv = TRUE; + boolean_t wired = (flags & PMAP_WIRED) != 0; + + PMAP_DPRINTF(PDB_FOLLOW|PDB_ENTER, + ("pmap_enter(%p, %lx, %lx, %x, %x)\n", + pmap, va, pa, prot, wired)); + +#ifdef DIAGNOSTIC + /* + * pmap_enter() should never be used for CADDR1 and CADDR2. + */ + if (pmap == pmap_kernel() && + (va == (vaddr_t)CADDR1 || va == (vaddr_t)CADDR2)) + panic("pmap_enter: used for CADDR1 or CADDR2"); +#endif + + /* + * For user mapping, allocate kernel VM resources if necessary. + */ + if (pmap->pm_ptab == NULL) + pmap->pm_ptab = (pt_entry_t *) + uvm_km_valloc_wait(pt_map, MAC_MAX_PTSIZE); + + /* + * Segment table entry not valid, we need a new PT page + */ + if (!pmap_ste_v(pmap, va)) + pmap_enter_ptpage(pmap, va); + + pa = m68k_trunc_page(pa); + pte = pmap_pte(pmap, va); + opa = pmap_pte_pa(pte); + + PMAP_DPRINTF(PDB_ENTER, ("enter: pte %p, *pte %x\n", pte, *pte)); + + /* + * Mapping has not changed, must be protection or wiring change. + */ + if (opa == pa) { + /* + * Wiring change, just update stats. + * We don't worry about wiring PT pages as they remain + * resident as long as there are valid mappings in them. + * Hence, if a user page is wired, the PT page will be also. + */ + if (pmap_pte_w_chg(pte, wired ? PG_W : 0)) { + PMAP_DPRINTF(PDB_ENTER, + ("enter: wiring change -> %x\n", wired)); + if (wired) + pmap->pm_stats.wired_count++; + else + pmap->pm_stats.wired_count--; + } + /* + * Retain cache inhibition status + */ + checkpv = FALSE; + if (pmap_pte_ci(pte)) + cacheable = FALSE; + goto validate; + } + + /* + * Mapping has changed, invalidate old range and fall through to + * handle validating new mapping. + */ + if (opa) { + PMAP_DPRINTF(PDB_ENTER, + ("enter: removing old mapping %lx\n", va)); + pmap_remove_mapping(pmap, va, pte, PRM_TFLUSH|PRM_CFLUSH); + } + + /* + * If this is a new user mapping, increment the wiring count + * on this PT page. PT pages are wired down as long as there + * is a valid mapping in the page. + */ + if (pmap != pmap_kernel()) + (void)uvm_map_pageable(pt_map, trunc_page((vaddr_t)pte), + round_page((vaddr_t)(pte+1)), FALSE, FALSE); + + /* + * Enter on the PV list if part of our managed memory + * Note that we raise IPL while manipulating pv_table + * since pmap_enter can be called at interrupt time. + */ + if (PAGE_IS_MANAGED(pa)) { + struct pv_entry *pv, *npv; + int s; + + pv = pa_to_pvh(pa); + s = splimp(); + PMAP_DPRINTF(PDB_ENTER, + ("enter: pv at %p: %lx/%p/%p\n", + pv, pv->pv_va, pv->pv_pmap, pv->pv_next)); + /* + * No entries yet, use header as the first entry + */ + if (pv->pv_pmap == NULL) { + pv->pv_va = va; + pv->pv_pmap = pmap; + pv->pv_next = NULL; + pv->pv_ptste = NULL; + pv->pv_ptpmap = NULL; + pv->pv_flags = 0; + } + /* + * There is at least one other VA mapping this page. + * Place this entry after the header. + */ + else { +#ifdef DEBUG + for (npv = pv; npv; npv = npv->pv_next) + if (pmap == npv->pv_pmap && va == npv->pv_va) + panic("pmap_enter: already in pv_tab"); +#endif + npv = pmap_alloc_pv(); + npv->pv_va = va; + npv->pv_pmap = pmap; + npv->pv_next = pv->pv_next; + npv->pv_ptste = NULL; + npv->pv_ptpmap = NULL; + npv->pv_flags = 0; + pv->pv_next = npv; + } + + /* + * Speed pmap_is_referenced() or pmap_is_modified() based + * on the hint provided in access_type. + */ +#ifdef DIAGNOSTIC + if ((flags & VM_PROT_ALL) & ~prot) + panic("pmap_enter: access_type exceeds prot"); +#endif + if (flags & VM_PROT_WRITE) + *pa_to_attribute(pa) |= (PG_U|PG_M); + else if (flags & VM_PROT_ALL) + *pa_to_attribute(pa) |= PG_U; + splx(s); + } + /* + * Assumption: if it is not part of our managed memory + * then it must be device memory which may be volitile. + */ + else if (pmap_initialized) { + checkpv = cacheable = FALSE; + } + + /* + * Increment counters + */ + pmap->pm_stats.resident_count++; + if (wired) + pmap->pm_stats.wired_count++; + +validate: + /* + * Build the new PTE. + */ + npte = pa | pte_prot(pmap, prot) | (*pte & (PG_M|PG_U)) | PG_V; + if (wired) + npte |= PG_W; + + /* Don't cache if process can't take it, like SunOS ones. */ + if (mmutype == MMU_68040 && pmap != pmap_kernel() && + (curproc->p_md.md_flags & MDP_UNCACHE_WX) && + (prot & VM_PROT_EXECUTE) && (prot & VM_PROT_WRITE)) + checkpv = cacheable = FALSE; + + if (!checkpv && !cacheable) + npte |= PG_CI; +#if defined(M68040) + if (mmutype == MMU_68040 && (npte & (PG_PROT|PG_CI)) == PG_RW) +#ifdef DEBUG + if (dowriteback && (dokwriteback || pmap != pmap_kernel())) +#endif + npte |= PG_CCB; +#endif + + PMAP_DPRINTF(PDB_ENTER, ("enter: new pte value %x\n", npte)); + + /* + * Remember if this was a wiring-only change. + * If so, we need not flush the TLB and caches. + */ + wired = ((*pte ^ npte) == PG_W); +#if defined(M68040) + if (mmutype == MMU_68040 && !wired) { + DCFP(pa); + ICPP(pa); + } +#endif + *pte = npte; + if (!wired && active_pmap(pmap)) + TBIS(va); +#ifdef DEBUG + if ((pmapdebug & PDB_WIRING) && pmap != pmap_kernel()) + pmap_check_wiring("enter", trunc_page((vaddr_t)pmap_pte(pmap, va))); +#endif + + return (0); +} + +/* + * pmap_unwire: [ INTERFACE ] + * + * Change the wiring attribute for a map/virtual-address pair. + * + * The mapping must already exist in the pmap. + */ +void +pmap_unwire(pmap, va) + pmap_t pmap; + vaddr_t va; +{ + pt_entry_t *pte; + + PMAP_DPRINTF(PDB_FOLLOW, ("pmap_unwire(%p, %lx)\n", pmap, va)); + + if (pmap == NULL) + return; + + pte = pmap_pte(pmap, va); +#ifdef DEBUG + /* + * Page table page is not allocated. + * Should this ever happen? Ignore it for now, + * we don't want to force allocation of unnecessary PTE pages. + */ + if (!pmap_ste_v(pmap, va)) { + if (pmapdebug & PDB_PARANOIA) + printf("pmap_unwire: invalid STE for %lx\n", va); + return; + } + /* + * Page not valid. Should this ever happen? + * Just continue and change wiring anyway. + */ + if (!pmap_pte_v(pte)) { + if (pmapdebug & PDB_PARANOIA) + printf("pmap_unwire: invalid PTE for %lx\n", va); + } +#endif + /* + * If wiring actually changed (always?) set the wire bit and + * update the wire count. Note that wiring is not a hardware + * characteristic so there is no need to invalidate the TLB. + */ + if (pmap_pte_w_chg(pte, 0)) { + pmap_pte_set_w(pte, 0); + pmap->pm_stats.wired_count--; + } +} + +/* + * pmap_extract: [ INTERFACE ] + * + * Extract the physical address associated with the given + * pmap/virtual address pair. + */ +boolean_t +pmap_extract(pmap, va, pap) + pmap_t pmap; + vaddr_t va; + paddr_t *pap; +{ + paddr_t pa; + + PMAP_DPRINTF(PDB_FOLLOW, + ("pmap_extract(%p, %lx) -> ", pmap, va)); + + if (pmap && pmap_ste_v(pmap, va)) + pa = *pmap_pte(pmap, va); + else + return (FALSE); + + pa = (pa & PG_FRAME) | (va & ~PG_FRAME); + + PMAP_DPRINTF(PDB_FOLLOW, ("%lx\n", pa)); + + *pap = pa; + return (TRUE); +} + +/* + * pmap_copy: [ INTERFACE ] + * + * Copy the mapping range specified by src_addr/len + * from the source map to the range dst_addr/len + * in the destination map. + * + * This routine is only advisory and need not do anything. + */ +void +pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr) + pmap_t dst_pmap; + pmap_t src_pmap; + vaddr_t dst_addr; + vsize_t len; + vaddr_t src_addr; +{ + + PMAP_DPRINTF(PDB_FOLLOW, + ("pmap_copy(%p, %p, %lx, %lx, %lx)\n", + dst_pmap, src_pmap, dst_addr, len, src_addr)); +} + +/* + * pmap_collect: [ INTERFACE ] + * + * Garbage collects the physical map system for pages which are no + * longer used. Success need not be guaranteed -- that is, there + * may well be pages which are not referenced, but others may be + * collected. + * + * Called by the pageout daemon when pages are scarce. + */ +void +pmap_collect(pmap) + pmap_t pmap; +{ + + PMAP_DPRINTF(PDB_FOLLOW, ("pmap_collect(%p)\n", pmap)); + + if (pmap == pmap_kernel()) { + int bank, s; + + /* + * XXX This is very bogus. We should handle kernel PT + * XXX pages much differently. + */ + + s = splimp(); + for (bank = 0; bank < vm_nphysseg; bank++) + pmap_collect1(pmap, ptoa(vm_physmem[bank].start), + ptoa(vm_physmem[bank].end)); + splx(s); + } else { + /* + * This process is about to be swapped out; free all of + * the PT pages by removing the physical mappings for its + * entire address space. Note: pmap_remove() performs + * all necessary locking. + */ + pmap_remove(pmap, VM_MIN_ADDRESS, VM_MAX_ADDRESS); + } + +#ifdef notyet + /* Go compact and garbage-collect the pv_table. */ + pmap_collect_pv(); +#endif +} + +/* + * pmap_collect1: + * + * Garbage-collect KPT pages. Helper for the above (bogus) + * pmap_collect(). + * + * Note: THIS SHOULD GO AWAY, AND BE REPLACED WITH A BETTER + * WAY OF HANDLING PT PAGES! + */ +void +pmap_collect1(pmap, startpa, endpa) + pmap_t pmap; + paddr_t startpa, endpa; +{ + paddr_t pa; + struct pv_entry *pv; + pt_entry_t *pte; + paddr_t kpa; +#ifdef DEBUG + st_entry_t *ste; + int opmapdebug = 0 /* XXX initialize to quiet gcc -Wall */; +#endif + + for (pa = startpa; pa < endpa; pa += NBPG) { + struct kpt_page *kpt, **pkpt; + + /* + * Locate physical pages which are being used as kernel + * page table pages. + */ + pv = pa_to_pvh(pa); + if (pv->pv_pmap != pmap_kernel() || !(pv->pv_flags & PV_PTPAGE)) + continue; + do { + if (pv->pv_ptste && pv->pv_ptpmap == pmap_kernel()) + break; + } while ((pv = pv->pv_next)); + if (pv == NULL) + continue; +#ifdef DEBUG + if (pv->pv_va < (vaddr_t)Sysmap || + pv->pv_va >= (vaddr_t)Sysmap + MAC_MAX_PTSIZE) + printf("collect: kernel PT VA out of range\n"); + else + goto ok; + pmap_pvdump(pa); + continue; +ok: +#endif + pte = (pt_entry_t *)(pv->pv_va + NBPG); + while (--pte >= (pt_entry_t *)pv->pv_va && *pte == PG_NV) + ; + if (pte >= (pt_entry_t *)pv->pv_va) + continue; + +#ifdef DEBUG + if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) { + printf("collect: freeing KPT page at %lx (ste %x@%p)\n", + pv->pv_va, *pv->pv_ptste, pv->pv_ptste); + opmapdebug = pmapdebug; + pmapdebug |= PDB_PTPAGE; + } + + ste = pv->pv_ptste; +#endif + /* + * If all entries were invalid we can remove the page. + * We call pmap_remove_entry to take care of invalidating + * ST and Sysptmap entries. + */ + pmap_extract(pmap, pv->pv_va, &kpa); + pmap_remove_mapping(pmap, pv->pv_va, PT_ENTRY_NULL, + PRM_TFLUSH|PRM_CFLUSH); + /* + * Use the physical address to locate the original + * (kmem_alloc assigned) address for the page and put + * that page back on the free list. + */ + for (pkpt = &kpt_used_list, kpt = *pkpt; + kpt != (struct kpt_page *)0; + pkpt = &kpt->kpt_next, kpt = *pkpt) + if (kpt->kpt_pa == kpa) + break; +#ifdef DEBUG + if (kpt == (struct kpt_page *)0) + panic("pmap_collect: lost a KPT page"); + if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) + printf("collect: %lx (%lx) to free list\n", + kpt->kpt_va, kpa); +#endif + *pkpt = kpt->kpt_next; + kpt->kpt_next = kpt_free_list; + kpt_free_list = kpt; +#ifdef DEBUG + if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) + pmapdebug = opmapdebug; + + if (*ste != SG_NV) + printf("collect: kernel STE at %p still valid (%x)\n", + ste, *ste); + ste = &Sysptmap[ste - pmap_ste(pmap_kernel(), 0)]; + if (*ste != SG_NV) + printf("collect: kernel PTmap at %p still valid (%x)\n", + ste, *ste); +#endif + } +} + +/* + * pmap_zero_page: [ INTERFACE ] + * + * Zero the specified (machine independent) page by mapping the page + * into virtual memory and using bzero to clear its contents, one + * machine dependent page at a time. + * + * Note: WE DO NOT CURRENTLY LOCK THE TEMPORARY ADDRESSES! + * (Actually, we go to splimp(), and since we don't + * support multiple processors, this is sufficient.) + */ +void +pmap_zero_page(phys) + paddr_t phys; +{ + int s, npte; + + PMAP_DPRINTF(PDB_FOLLOW, ("pmap_zero_page(%lx)\n", phys)); + + npte = phys | PG_V; + +#if defined(M68040) || defined(M68060) + if (mmutype == MMU_68040) { + /* + * Set copyback caching on the page; this is required + * for cache consistency (since regular mappings are + * copyback as well). + */ + npte |= PG_CCB; + } +#endif + + s = splimp(); + + *caddr1_pte = npte; + TBIS((vaddr_t)CADDR1); + + zeropage(CADDR1); + +#ifdef DEBUG + *caddr1_pte = PG_NV; + TBIS((vaddr_t)CADDR1); +#endif + + splx(s); +} + +/* + * pmap_copy_page: [ INTERFACE ] + * + * Copy the specified (machine independent) page by mapping the page + * into virtual memory and using bcopy to copy the page, one machine + * dependent page at a time. + * + * Note: WE DO NOT CURRENTLY LOCK THE TEMPORARY ADDRESSES! + * (Actually, we go to splimp(), and since we don't + * support multiple processors, this is sufficient.) + */ +void +pmap_copy_page(src, dst) + paddr_t src, dst; +{ + int s, npte1, npte2; + + PMAP_DPRINTF(PDB_FOLLOW, ("pmap_copy_page(%lx, %lx)\n", src, dst)); + + npte1 = src | PG_RO | PG_V; + npte2 = dst | PG_V; + +#if defined(M68040) || defined(M68060) + if (mmutype == MMU_68040) { + /* + * Set copyback caching on the pages; this is required + * for cache consistency (since regular mappings are + * copyback as well). + */ + npte1 |= PG_CCB; + npte2 |= PG_CCB; + } +#endif + + s = splimp(); + + *caddr1_pte = npte1; + TBIS((vaddr_t)CADDR1); + + *caddr2_pte = npte2; + TBIS((vaddr_t)CADDR2); + + copypage(CADDR1, CADDR2); + +#ifdef DEBUG + *caddr1_pte = PG_NV; + TBIS((vaddr_t)CADDR1); + + *caddr2_pte = PG_NV; + TBIS((vaddr_t)CADDR2); +#endif + + splx(s); +} + +/* + * pmap_clear_modify: [ INTERFACE ] + * + * Clear the modify bits on the specified physical page. + */ +boolean_t +pmap_clear_modify(struct vm_page *pg) +{ + paddr_t pa = VM_PAGE_TO_PHYS(pg); + boolean_t ret; + + ret = pmap_is_modified(pg); + + PMAP_DPRINTF(PDB_FOLLOW, ("pmap_clear_modify(%lx)\n", pa)); + + pmap_changebit(pa, 0, ~PG_M); + + return (ret); +} + +/* + * pmap_clear_reference: [ INTERFACE ] + * + * Clear the reference bit on the specified physical page. + */ +boolean_t +pmap_clear_reference(struct vm_page *pg) +{ + paddr_t pa = VM_PAGE_TO_PHYS(pg); + boolean_t ret; + + ret = pmap_is_referenced(pg); + + PMAP_DPRINTF(PDB_FOLLOW, ("pmap_clear_reference(%lx)\n", pa)); + + pmap_changebit(pa, 0, ~PG_U); + + return (ret); +} + +/* + * pmap_is_referenced: [ INTERFACE ] + * + * Return whether or not the specified physical page is referenced + * by any physical maps. + */ +boolean_t +pmap_is_referenced(struct vm_page *pg) +{ + paddr_t pa = VM_PAGE_TO_PHYS(pg); + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) { + boolean_t rv = pmap_testbit(pa, PG_U); + printf("pmap_is_referenced(%lx) -> %c\n", pa, "FT"[rv]); + return(rv); + } +#endif + return(pmap_testbit(pa, PG_U)); +} + +/* + * pmap_is_modified: [ INTERFACE ] + * + * Return whether or not the specified physical page is modified + * by any physical maps. + */ +boolean_t +pmap_is_modified(struct vm_page *pg) +{ + paddr_t pa = VM_PAGE_TO_PHYS(pg); + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) { + boolean_t rv = pmap_testbit(pa, PG_M); + printf("pmap_is_modified(%lx) -> %c\n", pa, "FT"[rv]); + return(rv); + } +#endif + return(pmap_testbit(pa, PG_M)); +} + +/* + * pmap_phys_address: [ INTERFACE ] + * + * Return the physical address corresponding to the specified + * cookie. Used by the device pager to decode a device driver's + * mmap entry point return value. + * + * Note: no locking is necessary in this function. + */ +paddr_t +pmap_phys_address(ppn) + int ppn; +{ + return(m68k_ptob(ppn)); +} + +/* + * Miscellaneous support routines follow + */ + +/* + * pmap_remove_mapping: + * + * Invalidate a single page denoted by pmap/va. + * + * If (pte != NULL), it is the already computed PTE for the page. + * + * If (flags & PRM_TFLUSH), we must invalidate any TLB information. + * + * If (flags & PRM_CFLUSH), we must flush/invalidate any cache + * information. + */ +/* static */ +void +pmap_remove_mapping(pmap, va, pte, flags) + pmap_t pmap; + vaddr_t va; + pt_entry_t *pte; + int flags; +{ + paddr_t pa; + struct pv_entry *pv, *npv; + pmap_t ptpmap; + st_entry_t *ste; + int s, bits; +#ifdef DEBUG + pt_entry_t opte; +#endif + + PMAP_DPRINTF(PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT, + ("pmap_remove_mapping(%p, %lx, %p, %x)\n", + pmap, va, pte, flags)); + + /* + * PTE not provided, compute it from pmap and va. + */ + if (pte == PT_ENTRY_NULL) { + pte = pmap_pte(pmap, va); + if (*pte == PG_NV) + return; + } + + pa = pmap_pte_pa(pte); +#ifdef DEBUG + opte = *pte; +#endif + /* + * Update statistics + */ + if (pmap_pte_w(pte)) + pmap->pm_stats.wired_count--; + pmap->pm_stats.resident_count--; + + /* + * Invalidate the PTE after saving the reference modify info. + */ + PMAP_DPRINTF(PDB_REMOVE, ("remove: invalidating pte at %p\n", pte)); + bits = *pte & (PG_U|PG_M); + *pte = PG_NV; + if ((flags & PRM_TFLUSH) && active_pmap(pmap)) + TBIS(va); + /* + * For user mappings decrement the wiring count on + * the PT page. We do this after the PTE has been + * invalidated because vm_map_pageable winds up in + * pmap_pageable which clears the modify bit for the + * PT page. + */ + if (pmap != pmap_kernel()) { + (void)uvm_map_pageable(pt_map, trunc_page((vaddr_t)pte), + round_page((vaddr_t)(pte+1)), TRUE, FALSE); +#ifdef DEBUG + if (pmapdebug & PDB_WIRING) + pmap_check_wiring("remove", (vaddr_t)trunc_page(pte)); +#endif + } + /* + * If this isn't a managed page, we are all done. + */ + if (PAGE_IS_MANAGED(pa) == 0) + return; + /* + * Otherwise remove it from the PV table + * (raise IPL since we may be called at interrupt time). + */ + pv = pa_to_pvh(pa); + ste = ST_ENTRY_NULL; + s = splimp(); + /* + * If it is the first entry on the list, it is actually + * in the header and we must copy the following entry up + * to the header. Otherwise we must search the list for + * the entry. In either case we free the now unused entry. + */ + if (pmap == pv->pv_pmap && va == pv->pv_va) { + ste = pv->pv_ptste; + ptpmap = pv->pv_ptpmap; + npv = pv->pv_next; + if (npv) { + npv->pv_flags = pv->pv_flags; + *pv = *npv; + pmap_free_pv(npv); + } else + pv->pv_pmap = NULL; + } else { + for (npv = pv->pv_next; npv; npv = npv->pv_next) { + if (pmap == npv->pv_pmap && va == npv->pv_va) + break; + pv = npv; + } +#ifdef DEBUG + if (npv == NULL) + panic("pmap_remove: PA not in pv_tab"); +#endif + ste = npv->pv_ptste; + ptpmap = npv->pv_ptpmap; + pv->pv_next = npv->pv_next; + pmap_free_pv(npv); + pv = pa_to_pvh(pa); + } + + /* + * If this was a PT page we must also remove the + * mapping from the associated segment table. + */ + if (ste) { + PMAP_DPRINTF(PDB_REMOVE|PDB_PTPAGE, + ("remove: ste was %x@%p pte was %x@%p\n", + *ste, ste, opte, pmap_pte(pmap, va))); +#if defined(M68040) + if (mmutype == MMU_68040) { + st_entry_t *este = &ste[NPTEPG/SG4_LEV3SIZE]; + + while (ste < este) + *ste++ = SG_NV; +#ifdef DEBUG + ste -= NPTEPG/SG4_LEV3SIZE; +#endif + } else +#endif + *ste = SG_NV; + /* + * If it was a user PT page, we decrement the + * reference count on the segment table as well, + * freeing it if it is now empty. + */ + if (ptpmap != pmap_kernel()) { + PMAP_DPRINTF(PDB_REMOVE|PDB_SEGTAB, + ("remove: stab %p, refcnt %d\n", + ptpmap->pm_stab, ptpmap->pm_sref - 1)); +#ifdef DEBUG + if ((pmapdebug & PDB_PARANOIA) && + ptpmap->pm_stab != (st_entry_t *)trunc_page((vaddr_t)ste)) + panic("remove: bogus ste"); +#endif + if (--(ptpmap->pm_sref) == 0) { + PMAP_DPRINTF(PDB_REMOVE|PDB_SEGTAB, + ("remove: free stab %p\n", + ptpmap->pm_stab)); + uvm_km_free_wakeup(st_map, + (vaddr_t)ptpmap->pm_stab, MAC_STSIZE); + ptpmap->pm_stab = Segtabzero; + ptpmap->pm_stpa = Segtabzeropa; +#if defined(M68040) + if (mmutype == MMU_68040) + ptpmap->pm_stfree = protostfree; +#endif + /* + * XXX may have changed segment table + * pointer for current process so + * update now to reload hardware. + */ + if (active_user_pmap(ptpmap)) + PMAP_ACTIVATE(ptpmap, 1); + } +#ifdef DEBUG + else if (ptpmap->pm_sref < 0) + panic("remove: sref < 0"); +#endif + } +#if 0 + /* + * XXX this should be unnecessary as we have been + * flushing individual mappings as we go. + */ + if (ptpmap == pmap_kernel()) + TBIAS(); + else + TBIAU(); +#endif + pv->pv_flags &= ~PV_PTPAGE; + ptpmap->pm_ptpages--; + } + /* + * Update saved attributes for managed page + */ + *pa_to_attribute(pa) |= bits; + splx(s); +} + +/* + * pmap_testbit: + * + * Test the modified/referenced bits of a physical page. + */ +/* static */ +boolean_t +pmap_testbit(pa, bit) + paddr_t pa; + int bit; +{ + struct pv_entry *pv; + pt_entry_t *pte; + int s; + + if (PAGE_IS_MANAGED(pa) == 0) + return (FALSE); + + pv = pa_to_pvh(pa); + s = splimp(); + /* + * Check saved info first + */ + if (*pa_to_attribute(pa) & bit) { + splx(s); + return(TRUE); + } + + /* + * Not found. Check current mappings, returning immediately if + * found. Cache a hit to speed future lookups. + */ + if (pv->pv_pmap != NULL) { + for (; pv; pv = pv->pv_next) { + pte = pmap_pte(pv->pv_pmap, pv->pv_va); + if (*pte & bit) { + *pa_to_attribute(pa) |= bit; + splx(s); + return(TRUE); + } + } + } + splx(s); + return(FALSE); +} + +/* + * pmap_changebit: + * + * Change the modified/referenced bits, or other PTE bits, + * for a physical page. + */ +/* static */ +void +pmap_changebit(pa, set, mask) + paddr_t pa; + int set, mask; +{ + struct pv_entry *pv; + pt_entry_t *pte, npte; + vaddr_t va; + int s; +#if defined(M68040) + boolean_t firstpage = TRUE; +#endif + + PMAP_DPRINTF(PDB_BITS, + ("pmap_changebit(%lx, %x, %x)\n", pa, set, mask)); + + if (PAGE_IS_MANAGED(pa) == 0) + return; + + pv = pa_to_pvh(pa); + s = splimp(); + + /* + * Clear saved attributes (modify, reference) + */ + *pa_to_attribute(pa) &= mask; + + /* + * Loop over all current mappings setting/clearing as appropos + * If setting RO do we need to clear the VAC? + */ + if (pv->pv_pmap != NULL) { +#ifdef DEBUG + int toflush = 0; +#endif + for (; pv; pv = pv->pv_next) { +#ifdef DEBUG + toflush |= (pv->pv_pmap == pmap_kernel()) ? 2 : 1; +#endif + va = pv->pv_va; + + /* + * XXX don't write protect pager mappings + */ + if (set == PG_RO) { + if (va >= uvm.pager_sva && va < uvm.pager_eva) + continue; + } + + pte = pmap_pte(pv->pv_pmap, va); + npte = (*pte | set) & mask; + if (*pte != npte) { +#if defined(M68040) + /* + * If we are changing caching status or + * protection make sure the caches are + * flushed (but only once). + */ + if (firstpage && (mmutype == MMU_68040) && + ((set == PG_RO) || + (set & PG_CMASK) || + (mask & PG_CMASK) == 0)) { + firstpage = FALSE; + DCFP(pa); + ICPP(pa); + } +#endif + *pte = npte; + if (active_pmap(pv->pv_pmap)) + TBIS(va); + } + } + } + splx(s); +} + +/* + * pmap_enter_ptpage: + * + * Allocate and map a PT page for the specified pmap/va pair. + */ +/* static */ +void +pmap_enter_ptpage(pmap, va) + pmap_t pmap; + vaddr_t va; +{ + paddr_t ptpa; + struct pv_entry *pv; + st_entry_t *ste; + int s; + + PMAP_DPRINTF(PDB_FOLLOW|PDB_ENTER|PDB_PTPAGE, + ("pmap_enter_ptpage: pmap %p, va %lx\n", pmap, va)); + + /* + * Allocate a segment table if necessary. Note that it is allocated + * from a private map and not pt_map. This keeps user page tables + * aligned on segment boundaries in the kernel address space. + * The segment table is wired down. It will be freed whenever the + * reference count drops to zero. + */ + if (pmap->pm_stab == Segtabzero) { + pmap->pm_stab = (st_entry_t *) + uvm_km_zalloc(st_map, MAC_STSIZE); + pmap_extract(pmap_kernel(), (vaddr_t)pmap->pm_stab, + (paddr_t *)&pmap->pm_stpa); +#if defined(M68040) + if (mmutype == MMU_68040) { +#ifdef DEBUG + if (dowriteback && dokwriteback) +#endif + pmap_changebit((paddr_t)pmap->pm_stpa, 0, ~PG_CCB); + pmap->pm_stfree = protostfree; + } +#endif + /* + * XXX may have changed segment table pointer for current + * process so update now to reload hardware. + */ + if (active_user_pmap(pmap)) + PMAP_ACTIVATE(pmap, 1); + + PMAP_DPRINTF(PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB, + ("enter: pmap %p stab %p(%p)\n", + pmap, pmap->pm_stab, pmap->pm_stpa)); + } + + ste = pmap_ste(pmap, va); +#if defined(M68040) + /* + * Allocate level 2 descriptor block if necessary + */ + if (mmutype == MMU_68040) { + if (*ste == SG_NV) { + int ix; + caddr_t addr; + + ix = bmtol2(pmap->pm_stfree); + if (ix == -1) + panic("enter: out of address space"); /* XXX */ + pmap->pm_stfree &= ~l2tobm(ix); + addr = (caddr_t)&pmap->pm_stab[ix*SG4_LEV2SIZE]; + bzero(addr, SG4_LEV2SIZE*sizeof(st_entry_t)); + addr = (caddr_t)&pmap->pm_stpa[ix*SG4_LEV2SIZE]; + *ste = (u_int)addr | SG_RW | SG_U | SG_V; + + PMAP_DPRINTF(PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB, + ("enter: alloc ste2 %d(%p)\n", ix, addr)); + } + ste = pmap_ste2(pmap, va); + /* + * Since a level 2 descriptor maps a block of SG4_LEV3SIZE + * level 3 descriptors, we need a chunk of NPTEPG/SG4_LEV3SIZE + * (16) such descriptors (NBPG/SG4_LEV3SIZE bytes) to map a + * PT page--the unit of allocation. We set `ste' to point + * to the first entry of that chunk which is validated in its + * entirety below. + */ + ste = (st_entry_t *)((int)ste & ~(NBPG/SG4_LEV3SIZE-1)); + + PMAP_DPRINTF(PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB, + ("enter: ste2 %p (%p)\n", pmap_ste2(pmap, va), ste)); + } +#endif + va = trunc_page((vaddr_t)pmap_pte(pmap, va)); + + /* + * In the kernel we allocate a page from the kernel PT page + * free list and map it into the kernel page table map (via + * pmap_enter). + */ + if (pmap == pmap_kernel()) { + struct kpt_page *kpt; + + s = splimp(); + if ((kpt = kpt_free_list) == (struct kpt_page *)0) { + /* + * No PT pages available. + * Try once to free up unused ones. + */ + PMAP_DPRINTF(PDB_COLLECT, + ("enter: no KPT pages, collecting...\n")); + pmap_collect(pmap_kernel()); + if ((kpt = kpt_free_list) == (struct kpt_page *)0) + panic("pmap_enter_ptpage: can't get KPT page"); + } + kpt_free_list = kpt->kpt_next; + kpt->kpt_next = kpt_used_list; + kpt_used_list = kpt; + ptpa = kpt->kpt_pa; + bzero((caddr_t)kpt->kpt_va, NBPG); + pmap_enter(pmap, va, ptpa, VM_PROT_DEFAULT, + VM_PROT_DEFAULT|PMAP_WIRED); +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE)) { + int ix = pmap_ste(pmap, va) - pmap_ste(pmap, 0); + + printf("enter: add &Sysptmap[%d]: %x (KPT page %lx)\n", + ix, Sysptmap[ix], kpt->kpt_va); + } +#endif + splx(s); + } + /* + * For user processes we just simulate a fault on that location + * letting the VM system allocate a zero-filled page. + */ + else { + /* + * Count the segment table reference now so that we won't + * lose the segment table when low on memory. + */ + pmap->pm_sref++; + PMAP_DPRINTF(PDB_ENTER|PDB_PTPAGE, + ("enter: about to fault UPT pg at %lx\n", va)); + s = uvm_fault(pt_map, va, 0, VM_PROT_READ|VM_PROT_WRITE); + if (s) { + printf("uvm_fault(pt_map, 0x%lx, 0, RW) -> %d\n", + va, s); + panic("pmap_enter: uvm_fault failed"); + } + pmap_extract(pmap_kernel(), va, &ptpa); + } +#if defined(M68040) + /* + * Turn off copyback caching of page table pages, + * could get ugly otherwise. + */ +#ifdef DEBUG + if (dowriteback && dokwriteback) +#endif + if (mmutype == MMU_68040) { +#ifdef DEBUG + pt_entry_t *pte = pmap_pte(pmap_kernel(), va); + if ((pmapdebug & PDB_PARANOIA) && (*pte & PG_CCB) == 0) + printf("%s PT no CCB: kva=%lx ptpa=%lx pte@%p=%x\n", + pmap == pmap_kernel() ? "Kernel" : "User", + va, ptpa, pte, *pte); +#endif + pmap_changebit(ptpa, 0, ~PG_CCB); + } +#endif + /* + * Locate the PV entry in the kernel for this PT page and + * record the STE address. This is so that we can invalidate + * the STE when we remove the mapping for the page. + */ + pv = pa_to_pvh(ptpa); + s = splimp(); + if (pv) { + pv->pv_flags |= PV_PTPAGE; + do { + if (pv->pv_pmap == pmap_kernel() && pv->pv_va == va) + break; + } while ((pv = pv->pv_next)); + } +#ifdef DEBUG + if (pv == NULL) + panic("pmap_enter_ptpage: PT page not entered"); +#endif + pv->pv_ptste = ste; + pv->pv_ptpmap = pmap; + + PMAP_DPRINTF(PDB_ENTER|PDB_PTPAGE, + ("enter: new PT page at PA %lx, ste at %p\n", ptpa, ste)); + + /* + * Map the new PT page into the segment table. + * Also increment the reference count on the segment table if this + * was a user page table page. Note that we don't use vm_map_pageable + * to keep the count like we do for PT pages, this is mostly because + * it would be difficult to identify ST pages in pmap_pageable to + * release them. We also avoid the overhead of vm_map_pageable. + */ +#if defined(M68040) + if (mmutype == MMU_68040) { + st_entry_t *este; + + for (este = &ste[NPTEPG/SG4_LEV3SIZE]; ste < este; ste++) { + *ste = ptpa | SG_U | SG_RW | SG_V; + ptpa += SG4_LEV3SIZE * sizeof(st_entry_t); + } + } else +#endif + *ste = (ptpa & SG_FRAME) | SG_RW | SG_V; + if (pmap != pmap_kernel()) { + PMAP_DPRINTF(PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB, + ("enter: stab %p refcnt %d\n", + pmap->pm_stab, pmap->pm_sref)); + } +#if 0 + /* + * Flush stale TLB info. + */ + if (pmap == pmap_kernel()) + TBIAS(); + else + TBIAU(); +#endif + pmap->pm_ptpages++; + splx(s); +} + +#ifdef DEBUG +/* + * pmap_pvdump: + * + * Dump the contents of the PV list for the specified physical page. + */ +/* static */ +void +pmap_pvdump(pa) + paddr_t pa; +{ + struct pv_entry *pv; + + printf("pa %lx", pa); + for (pv = pa_to_pvh(pa); pv; pv = pv->pv_next) + printf(" -> pmap %p, va %lx, ptste %p, ptpmap %p, flags %x", + pv->pv_pmap, pv->pv_va, pv->pv_ptste, pv->pv_ptpmap, + pv->pv_flags); + printf("\n"); +} + +/* + * pmap_check_wiring: + * + * Count the number of valid mappings in the specified PT page, + * and ensure that it is consistent with the number of wirings + * to that page that the VM system has. + */ +/* static */ +void +pmap_check_wiring(str, va) + char *str; + vaddr_t va; +{ + struct vm_map_entry *entry; + int count; + pt_entry_t *pte; + + va = trunc_page(va); + if (!pmap_ste_v(pmap_kernel(), va) || + !pmap_pte_v(pmap_pte(pmap_kernel(), va))) + return; + + if (!uvm_map_lookup_entry(pt_map, va, &entry)) { + printf("wired_check: entry for %lx not found\n", va); + return; + } + count = 0; + for (pte = (pt_entry_t *)va; pte < (pt_entry_t *)(va + NBPG); pte++) + if (*pte) + count++; + if (entry->wired_count != count) + printf("*%s*: %lx: w%d/a%d\n", + str, va, entry->wired_count, count); +} +#endif /* DEBUG */ + +void +pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot) +{ + pmap_enter(pmap_kernel(), va, pa, prot, VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED); +} + +void +pmap_kremove(vaddr_t va, vsize_t len) +{ + for (len >>= PAGE_SHIFT; len > 0; len--, va += PAGE_SIZE) { + pmap_remove(pmap_kernel(), va, va + PAGE_SIZE); + } +} diff --git a/sys/arch/mac68k/mac68k/pmap_bootstrap.c b/sys/arch/mac68k/mac68k/pmap_bootstrap.c index f3a45f84fca..54781633ec6 100644 --- a/sys/arch/mac68k/mac68k/pmap_bootstrap.c +++ b/sys/arch/mac68k/mac68k/pmap_bootstrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pmap_bootstrap.c,v 1.17 2001/12/14 21:44:05 miod Exp $ */ +/* $OpenBSD: pmap_bootstrap.c,v 1.18 2001/12/20 19:02:28 miod Exp $ */ /* $NetBSD: pmap_bootstrap.c,v 1.50 1999/04/07 06:14:33 scottr Exp $ */ /* @@ -71,6 +71,7 @@ extern paddr_t avail_start; extern paddr_t avail_end; extern vaddr_t virtual_avail, virtual_end; extern vsize_t mem_size; +extern int protection_codes[]; /* * These are used to map the RAM: @@ -484,6 +485,25 @@ pmap_bootstrap(nextpa, firstpa) virtual_end = VM_MAX_KERNEL_ADDRESS; /* + * Initialize protection array. + * XXX don't use a switch statement, it might produce an + * absolute "jmp" table. + */ + { + int *kp; + + kp = (int *) &protection_codes; + kp[VM_PROT_NONE|VM_PROT_NONE|VM_PROT_NONE] = 0; + kp[VM_PROT_READ|VM_PROT_NONE|VM_PROT_NONE] = PG_RO; + kp[VM_PROT_READ|VM_PROT_NONE|VM_PROT_EXECUTE] = PG_RO; + kp[VM_PROT_NONE|VM_PROT_NONE|VM_PROT_EXECUTE] = PG_RO; + kp[VM_PROT_NONE|VM_PROT_WRITE|VM_PROT_NONE] = PG_RW; + kp[VM_PROT_NONE|VM_PROT_WRITE|VM_PROT_EXECUTE] = PG_RW; + kp[VM_PROT_READ|VM_PROT_WRITE|VM_PROT_NONE] = PG_RW; + kp[VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE] = PG_RW; + } + + /* * Kernel page/segment table allocated in locore, * just initialize pointers. */ @@ -622,22 +642,3 @@ bootstrap_mac68k(tc) videoaddr = newvideoaddr; } - -void -pmap_init_md() -{ - vaddr_t addr; - - /* - * Mark as unavailable the regions which we have mapped in - * pmap_bootstrap(). - */ - addr = (vaddr_t)IOBase; - if (uvm_map(kernel_map, &addr, - m68k_ptob(IIOMAPSIZE + ROMMAPSIZE + VIDMAPSIZE), - NULL, UVM_UNKNOWN_OFFSET, 0, - UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, - UVM_INH_NONE, UVM_ADV_RANDOM, - UVM_FLAG_FIXED))) - panic("pmap_init: bogons in the VM system!\n"); -} diff --git a/sys/arch/mvme68k/conf/files.mvme68k b/sys/arch/mvme68k/conf/files.mvme68k index b6b9c9f89ed..e8801595ab7 100644 --- a/sys/arch/mvme68k/conf/files.mvme68k +++ b/sys/arch/mvme68k/conf/files.mvme68k @@ -1,4 +1,4 @@ -# $OpenBSD: files.mvme68k,v 1.20 2001/11/30 20:58:18 miod Exp $ +# $OpenBSD: files.mvme68k,v 1.21 2001/12/20 19:02:29 miod Exp $ # config file for mvme68k @@ -115,7 +115,7 @@ file arch/mvme68k/mvme68k/disksubr.c file arch/mvme68k/mvme68k/dkbad.c file arch/mvme68k/mvme68k/machdep.c file arch/mvme68k/mvme68k/mem.c -file arch/m68k/m68k/pmap_motorola.c +file arch/mvme68k/mvme68k/pmap.c file arch/mvme68k/mvme68k/pmap_bootstrap.c file arch/mvme68k/mvme68k/sys_machdep.c file arch/mvme68k/mvme68k/trap.c diff --git a/sys/arch/mvme68k/include/param.h b/sys/arch/mvme68k/include/param.h index 55c75df112e..b3b64736ec6 100644 --- a/sys/arch/mvme68k/include/param.h +++ b/sys/arch/mvme68k/include/param.h @@ -1,4 +1,4 @@ -/* $OpenBSD: param.h,v 1.15 2001/12/07 21:49:15 art Exp $ */ +/* $OpenBSD: param.h,v 1.16 2001/12/20 19:02:29 miod Exp $ */ /* * Copyright (c) 1988 University of Utah. @@ -57,6 +57,12 @@ #define PAGE_SIZE (1 << PAGE_SHIFT) #define PAGE_MASK (PAGE_SIZE - 1) +#define NPTEPG (NBPG/(sizeof (pt_entry_t))) + +#define SEGSHIFT 22 /* LOG2(NBSEG) */ +#define NBSEG (1 << SEGSHIFT) /* bytes/segment */ +#define SEGOFSET (NBSEG-1) /* byte offset into segment */ + #define KERNBASE 0x00000000 /* start of kernel virtual */ #define KERNTEXTOFF 0x00010000 /* start of kernel text */ @@ -86,4 +92,17 @@ #define DELAY(n) delay(n) #endif +#ifdef COMPAT_HPUX +/* + * Constants/macros for HPUX multiple mapping of user address space. + * Pages in the first 256Mb are mapped in at every 256Mb segment. + */ +#define HPMMMASK 0xF0000000 +#define ISHPMMADDR(v) \ + ((curproc->p_md.md_flags & MDP_HPUXMMAP) && \ + ((unsigned)(v) & HPMMMASK) && \ + ((unsigned)(v) & HPMMMASK) != HPMMMASK) +#define HPMMBASEADDR(v) \ + ((unsigned)(v) & ~HPMMMASK) +#endif #endif /* _MACHINE_PARAM_H_ */ diff --git a/sys/arch/mvme68k/include/pmap.h b/sys/arch/mvme68k/include/pmap.h index 309e6bdd51c..2e873a725f9 100644 --- a/sys/arch/mvme68k/include/pmap.h +++ b/sys/arch/mvme68k/include/pmap.h @@ -1,13 +1,155 @@ -/* $OpenBSD: pmap.h,v 1.9 2001/11/30 20:58:18 miod Exp $ */ +/* $OpenBSD: pmap.h,v 1.10 2001/12/20 19:02:29 miod Exp $ */ -#ifndef _MACHINE_PMAP_H_ -#define _MACHINE_PMAP_H_ +/* + * Copyright (c) 1987 Carnegie-Mellon University + * Copyright (c) 1991, 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. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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.h 8.1 (Berkeley) 6/10/93 + */ -#include <m68k/pmap_motorola.h> +#ifndef _MVME68K_PMAP_H_ +#define _MVME68K_PMAP_H_ -#ifdef _KERNEL -void pmap_init_md __P((void)); -#define PMAP_INIT_MD() pmap_init_md() +#include <machine/pte.h> + +#if defined(M68040) +#define M68K_SEG_SIZE (mmutype == MMU_68040 ? 0x40000 : NBSEG) +#else +#define M68K_SEG_SIZE NBSEG #endif -#endif /* _MACHINE_PMAP_H_ */ +/* + * Pmap stuff + */ +struct pmap { + pt_entry_t *pm_ptab; /* KVA of page table */ + st_entry_t *pm_stab; /* KVA of segment table */ + int pm_stfree; /* 040: free lev2 blocks */ + st_entry_t *pm_stpa; /* 040: ST phys addr */ + short pm_sref; /* segment table ref count */ + short pm_count; /* pmap reference count */ + struct simplelock pm_lock; /* lock on pmap */ + struct pmap_statistics pm_stats; /* pmap statistics */ + long pm_ptpages; /* more stats: PT pages */ +}; + +typedef struct pmap *pmap_t; + +/* + * On the 040 we keep track of which level 2 blocks are already in use + * with the pm_stfree mask. Bits are arranged from LSB (block 0) to MSB + * (block 31). For convenience, the level 1 table is considered to be + * block 0. + * + * MAX[KU]L2SIZE control how many pages of level 2 descriptors are allowed. + * for the kernel and users. 8 implies only the initial "segment table" + * page is used. WARNING: don't change MAXUL2SIZE unless you can allocate + * physically contiguous pages for the ST in pmap.c! + */ +#define MAXKL2SIZE 32 +#define MAXUL2SIZE 8 +#define l2tobm(n) (1 << (n)) +#define bmtol2(n) (ffs(n) - 1) + +/* + * Macros for speed + */ +#define PMAP_ACTIVATE(pmap, loadhw) \ +{ \ + if ((loadhw)) \ + loadustp(m68k_btop((vm_offset_t)(pmap)->pm_stpa)); \ +} + +/* + * For each vm_page_t, there is a list of all currently valid virtual + * mappings of that page. An entry is a pv_entry, the list is pv_table. + */ +struct pv_entry { + struct pv_entry *pv_next; /* next pv_entry */ + struct pmap *pv_pmap; /* pmap where mapping lies */ + vm_offset_t pv_va; /* virtual address for mapping */ + st_entry_t *pv_ptste; /* non-zero if VA maps a PT page */ + struct pmap *pv_ptpmap; /* if pv_ptste, pmap for PT page */ + int pv_flags; /* flags */ +}; + +#define PV_CI 0x01 /* header: all entries are cache inhibited */ +#define PV_PTPAGE 0x02 /* header: entry maps a page table page */ + +struct pv_page; + +struct pv_page_info { + TAILQ_ENTRY(pv_page) pgi_list; + struct pv_entry *pgi_freelist; + int pgi_nfree; +}; + +/* + * This is basically: + * ((NBPG - sizeof(struct pv_page_info)) / sizeof(struct pv_entry)) + */ +#define NPVPPG 170 + +struct pv_page { + struct pv_page_info pvp_pgi; + struct pv_entry pvp_pv[NPVPPG]; +}; + +#ifdef _KERNEL + +extern struct pmap kernel_pmap_store; + +#define pmap_kernel() (&kernel_pmap_store) +#define active_pmap(pm) \ + ((pm) == pmap_kernel() || (pm) == curproc->p_vmspace->vm_map.pmap) +#define active_user_pmap(pm) \ + (curproc && \ + (pm) != pmap_kernel() && (pm) == curproc->p_vmspace->vm_map.pmap) + + +extern struct pv_entry *pv_table; /* array of entries, one per page */ + +#define pmap_page_index(pa) atop(pa - vm_first_phys) + +#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count) +#define pmap_wired_count(pmap) ((pmap)->pm_stats.wired_count) +#define pmap_update(pmap) /* nothing */ + +extern pt_entry_t *Sysmap; +extern char *vmmap; /* map for mem, dumps, etc. */ +#endif /* _KERNEL */ + +#endif /* !_MVME68K_PMAP_H_ */ diff --git a/sys/arch/mvme68k/include/pte.h b/sys/arch/mvme68k/include/pte.h index bf2f20714e4..78e9deb44c8 100644 --- a/sys/arch/mvme68k/include/pte.h +++ b/sys/arch/mvme68k/include/pte.h @@ -1,14 +1,152 @@ -/* $OpenBSD: pte.h,v 1.5 2001/11/30 20:58:18 miod Exp $ */ +/* $OpenBSD: pte.h,v 1.6 2001/12/20 19:02:29 miod Exp $ */ -#ifndef _MACHINE_PTE_H_ -#define _MACHINE_PTE_H_ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1982, 1986, 1990, 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. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + * + * from: Utah $Hdr: pte.h 1.13 92/01/20$ + * + * @(#)pte.h 8.1 (Berkeley) 6/10/93 + */ -#include <m68k/pte_motorola.h> +#ifndef _MVME68K_PTE_H_ +#define _MVME68K_PTE_H_ -#define MACHINE_STSIZE M68K_STSIZE -#define MACHINE_MAX_PTSIZE M68K_MAX_PTSIZE -#define MACHINE_MAX_KPTSIZE M68K_MAX_KPTSIZE -#define MACHINE_PTBASE M68K_PTBASE -#define MACHINE_PTMAXSIZE M68K_PTMAXSIZE +/* + * m68k hardware segment/page table entries + */ -#endif /* _MACHINE_PTE_H_ */ +#if 0 +struct ste { + unsigned int sg_pfnum:20; /* page table frame number */ + unsigned int :8; /* reserved at 0 */ + unsigned int :1; /* reserved at 1 */ + unsigned int sg_prot:1; /* write protect bit */ + unsigned int sg_v:2; /* valid bits */ +}; + +struct ste40 { + unsigned int sg_ptaddr:24; /* page table page addr */ + unsigned int :4; /* reserved at 0 */ + unsigned int sg_u; /* hardware modified (dirty) bit */ + unsigned int sg_prot:1; /* write protect bit */ + unsigned int sg_v:2; /* valid bits */ +}; + +struct pte { + unsigned int pg_pfnum:20; /* page frame number or 0 */ + unsigned int :3; + unsigned int pg_w:1; /* is wired */ + unsigned int :1; /* reserved at zero */ + unsigned int pg_ci:1; /* cache inhibit bit */ + unsigned int :1; /* reserved at zero */ + unsigned int pg_m:1; /* hardware modified (dirty) bit */ + unsigned int pg_u:1; /* hardware used (reference) bit */ + unsigned int pg_prot:1; /* write protect bit */ + unsigned int pg_v:2; /* valid bit */ +}; +#endif + +typedef int st_entry_t; /* segment table entry */ +typedef int pt_entry_t; /* Mach page table entry */ + +#define PT_ENTRY_NULL ((pt_entry_t *) 0) +#define ST_ENTRY_NULL ((st_entry_t *) 0) + +#define SG_V 0x00000002 /* segment is valid */ +#define SG_NV 0x00000000 +#define SG_PROT 0x00000004 /* access protection mask */ +#define SG_RO 0x00000004 +#define SG_RW 0x00000000 +#define SG_U 0x00000008 /* modified bit (68040) */ +#define SG_FRAME 0xfffff000 +#define SG_IMASK 0xffc00000 +#define SG_ISHIFT 22 +#define SG_PMASK 0x003ff000 +#define SG_PSHIFT 12 + +/* 68040 additions */ +#define SG4_MASK1 0xfe000000 +#define SG4_SHIFT1 25 +#define SG4_MASK2 0x01fc0000 +#define SG4_SHIFT2 18 +#define SG4_MASK3 0x0003f000 +#define SG4_SHIFT3 12 +#define SG4_ADDR1 0xfffffe00 +#define SG4_ADDR2 0xffffff00 +#define SG4_LEV1SIZE 128 +#define SG4_LEV2SIZE 128 +#define SG4_LEV3SIZE 64 + +#define PG_V 0x00000001 +#define PG_NV 0x00000000 +#define PG_PROT 0x00000004 +#define PG_U 0x00000008 +#define PG_M 0x00000010 +#define PG_W 0x00000100 +#define PG_RO 0x00000004 +#define PG_RW 0x00000000 +#define PG_FRAME 0xfffff000 +#define PG_CI 0x00000040 +#define PG_SHIFT 12 +#define PG_PFNUM(x) (((x) & PG_FRAME) >> PG_SHIFT) + +/* 68040 additions */ +#define PG_CMASK 0x00000060 /* cache mode mask */ +#define PG_CWT 0x00000000 /* writethrough caching */ +#define PG_CCB 0x00000020 /* copyback caching */ +#define PG_CIS 0x00000040 /* cache inhibited serialized */ +#define PG_CIN 0x00000060 /* cache inhibited nonserialized */ +#define PG_SO 0x00000080 /* supervisor only */ + +#define M68K_STSIZE (MAXUL2SIZE*SG4_LEV2SIZE*sizeof(st_entry_t)) + /* user process segment table size */ +#define M68K_MAX_PTSIZE 0x400000 /* max size of UPT */ +#define M68K_MAX_KPTSIZE 0x100000 /* max memory to allocate to KPT */ +#define M68K_PTBASE 0x10000000 /* UPT map base address */ +#define M68K_PTMAXSIZE 0x70000000 /* UPT map maximum size */ + +/* + * Kernel virtual address to page table entry and to physical address. + */ +#define kvtopte(va) \ + (&Sysmap[((unsigned)(va) - VM_MIN_KERNEL_ADDRESS) >> PGSHIFT]) +#define ptetokv(pt) \ + ((((pt_entry_t *)(pt) - Sysmap) << PGSHIFT) + VM_MIN_KERNEL_ADDRESS) +#define kvtophys(va) \ + ((kvtopte(va)->pg_pfnum << PGSHIFT) | ((int)(va) & PGOFSET)) + +#endif /* !_MVME68K_PTE_H_ */ diff --git a/sys/arch/mvme68k/mvme68k/pmap.c b/sys/arch/mvme68k/mvme68k/pmap.c new file mode 100644 index 00000000000..7ef277f8f3e --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/pmap.c @@ -0,0 +1,2403 @@ +/* $OpenBSD: pmap.c,v 1.37 2001/12/20 19:02:29 miod Exp $ */ + +/* + * Copyright (c) 1995 Theo de Raadt + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed under OpenBSD by + * Theo de Raadt for Willowglen Singapore. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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) 1991, 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. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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.6 (Berkeley) 5/27/94 + */ + +/* + * m68k series physical map management code. + * + * Supports: + * XXX 68020 with 68551 MMU + * 68030 with on-chip MMU + * 68040 with on-chip MMU + * 68060 with on-chip MMU + * + * Notes: + * Don't even pay lip service to multiprocessor support. + * + * We assume TLB entries don't have process tags (except for the + * supervisor/user distinction) so we only invalidate TLB entries + * when changing mappings for the current (or kernel) pmap. This is + * technically not true for the 68551 but we flush the TLB on every + * context switch, so it effectively winds up that way. + * + * Bitwise and/or operations are significantly faster than bitfield + * references so we use them when accessing STE/PTEs in the pmap_pte_* + * macros. Note also that the two are not always equivalent; e.g.: + * (*pte & PG_PROT) [4] != pte->pg_prot [1] + * and a couple of routines that deal with protection and wiring take + * some shortcuts that assume the and/or definitions. + * + * This implementation will only work for PAGE_SIZE == NBPG + * (i.e. 4096 bytes). + */ + +/* + * 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/user.h> + +#include <machine/pte.h> + +#include <uvm/uvm_extern.h> +#include <uvm/uvm.h> + +#include <machine/cpu.h> + +#ifdef DEBUG +#define PDB_FOLLOW 0x0001 +#define PDB_INIT 0x0002 +#define PDB_ENTER 0x0004 +#define PDB_REMOVE 0x0008 +#define PDB_CREATE 0x0010 +#define PDB_PTPAGE 0x0020 +#define PDB_CACHE 0x0040 +#define PDB_BITS 0x0080 +#define PDB_COLLECT 0x0100 +#define PDB_PROTECT 0x0200 +#define PDB_SEGTAB 0x0400 +#define PDB_MULTIMAP 0x0800 +#define PDB_PARANOIA 0x2000 +#define PDB_WIRING 0x4000 +#define PDB_PVDUMP 0x8000 +#define PDB_ALL 0xFFFF + +int debugmap = 0; +int pmapdebug = PDB_PARANOIA; + +#if defined(M68040) || defined(M68060) +int dowriteback = 1; /* 68040: enable writeback caching */ +int dokwriteback = 1; /* 68040: enable writeback caching of kernel AS */ +#endif +#endif + +/* + * Get STEs and PTEs for user/kernel address space + */ +#if defined(M68040) || defined(M68060) +#define pmap_ste1(m, v) \ + (&((m)->pm_stab[(vm_offset_t)(v) >> SG4_SHIFT1])) +/* XXX assumes physically contiguous ST pages (if more than one) */ +#define pmap_ste2(m, v) \ + (&((m)->pm_stab[(st_entry_t *)(*(u_int *)pmap_ste1(m, v) & SG4_ADDR1) \ + - (m)->pm_stpa + (((v) & SG4_MASK2) >> SG4_SHIFT2)])) +#define pmap_ste(m, v) \ + (&((m)->pm_stab[(vm_offset_t)(v) \ + >> (mmutype <= MMU_68040 ? SG4_SHIFT1 : SG_ISHIFT)])) +#define pmap_ste_v(m, v) \ + (mmutype <= MMU_68040 \ + ? ((*pmap_ste1(m, v) & SG_V) && \ + (*pmap_ste2(m, v) & SG_V)) \ + : (*pmap_ste(m, v) & SG_V)) +#else +#define pmap_ste(m, v) (&((m)->pm_stab[(vm_offset_t)(v) >> SG_ISHIFT])) +#define pmap_ste_v(m, v) (*pmap_ste(m, v) & SG_V) +#endif + +#define pmap_pte(m, v) (&((m)->pm_ptab[(vm_offset_t)(v) >> PG_SHIFT])) +#define pmap_pte_pa(pte) (*(pte) & PG_FRAME) +#define pmap_pte_w(pte) (*(pte) & PG_W) +#define pmap_pte_ci(pte) (*(pte) & PG_CI) +#define pmap_pte_m(pte) (*(pte) & PG_M) +#define pmap_pte_u(pte) (*(pte) & PG_U) +#define pmap_pte_prot(pte) (*(pte) & PG_PROT) +#define pmap_pte_v(pte) (*(pte) & PG_V) + +#define pmap_pte_set_w(pte, v) \ + if (v) *(pte) |= PG_W; else *(pte) &= ~PG_W +#define pmap_pte_set_prot(pte, v) \ + if (v) *(pte) |= PG_PROT; else *(pte) &= ~PG_PROT +#define pmap_pte_w_chg(pte, nw) ((nw) ^ pmap_pte_w(pte)) +#define pmap_pte_prot_chg(pte, np) ((np) ^ pmap_pte_prot(pte)) + +/* + * Given a map and a machine independent protection code, + * convert to an m68k protection code. + */ +#define pte_prot(m, p) (protection_codes[p]) +int protection_codes[8]; + +/* + * Kernel page table page management. + */ +struct kpt_page { + struct kpt_page *kpt_next; /* link on either used or free list */ + vm_offset_t kpt_va; /* always valid kernel VA */ + vm_offset_t kpt_pa; /* PA of this page (for speed) */ +}; +struct kpt_page *kpt_free_list, *kpt_used_list; +struct kpt_page *kpt_pages; + +/* + * Kernel segment/page table and page table map. + * The page table map gives us a level of indirection we need to dynamically + * expand the page table. It is essentially a copy of the segment table + * with PTEs instead of STEs. All are initialized in locore at boot time. + * Sysmap will initially contain VM_KERNEL_PT_PAGES pages of PTEs. + * Segtabzero is an empty segment table which all processes share til they + * reference something. + */ +st_entry_t *Sysseg; +pt_entry_t *Sysmap, *Sysptmap; +st_entry_t *Segtabzero, *Segtabzeropa; +vm_size_t Sysptsize = VM_KERNEL_PT_PAGES; + +struct pmap kernel_pmap_store; +struct vm_map *st_map, *pt_map; +struct vm_map st_map_store, pt_map_store; + +vm_offset_t avail_start; /* PA of first available physical page */ +vm_offset_t avail_end; /* PA of last available physical page */ +vm_size_t mem_size; /* memory size in bytes */ +vm_offset_t virtual_avail; /* VA of first avail page (after kernel bss)*/ +vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */ +int page_cnt; /* number of pages managed by VM system */ + +boolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */ +struct pv_entry *pv_table; +char *pmap_attributes; /* reference and modify bits */ +TAILQ_HEAD(pv_page_list, pv_page) pv_page_freelist; +int pv_nfree; + +#if defined(M68040) || defined(M68060) +int protostfree; /* prototype (default) free ST map */ +#endif + +/* + * Internal routines + */ +void pmap_remove_mapping __P((pmap_t, vm_offset_t, pt_entry_t *, int)); +boolean_t pmap_testbit __P((vm_offset_t, int)); +void pmap_changebit __P((vm_offset_t, int, boolean_t)); +void pmap_enter_ptpage __P((pmap_t, vm_offset_t)); +void pmap_ptpage_addref __P((vaddr_t)); +int pmap_ptpage_delref __P((vaddr_t)); +void pmap_collect1 __P((pmap_t, vm_offset_t, vm_offset_t)); +void pmap_pinit __P((struct pmap *)); +void pmap_release __P((struct pmap *)); + + +#ifdef DEBUG +void pmap_pvdump __P((vm_offset_t)); +void pmap_check_wiring __P((char *, vm_offset_t)); +#endif + +/* pmap_remove_mapping flags */ +#define PRM_TFLUSH 1 +#define PRM_CFLUSH 2 +#define PRM_KEEPPTPAGE 4 + +#define PAGE_IS_MANAGED(pa) (pmap_initialized && \ + vm_physseg_find(atop((pa)), NULL) != -1) + +#define pa_to_pvh(pa) \ +({ \ + int bank_, pg_; \ + \ + bank_ = vm_physseg_find(atop((pa)), &pg_); \ + &vm_physmem[bank_].pmseg.pvent[pg_]; \ +}) + +#define pa_to_attribute(pa) \ +({ \ + int bank_, pg_; \ + \ + bank_ = vm_physseg_find(atop((pa)), &pg_); \ + &vm_physmem[bank_].pmseg.attrs[pg_]; \ +}) + +/* + * Routine: pmap_virtual_space + * + * Function: + * Report the range of available kernel virtual address + * space to the VM system during bootstrap. Called by + * vm_bootstrap_steal_memory(). + */ +void +pmap_virtual_space(vstartp, vendp) + vm_offset_t *vstartp, *vendp; +{ + + *vstartp = virtual_avail; + *vendp = virtual_end; +} + +/* + * Routine: pmap_init + * + * Function: + * Initialize the pmap module. + * Called by vm_init, to initialize any structures that the pmap + * system needs to map virtual memory. + */ +void +pmap_init() +{ + vm_offset_t addr, addr2; + vm_size_t s; + int rv; + int npages; + struct pv_entry *pv; + char *attr; + int bank; + + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_init()\n"); +#endif + /* + * Now that kernel map has been allocated, we can mark as + * unavailable regions which we have mapped in pmap_bootstrap(). + */ + addr = (vaddr_t) intiobase; + if (uvm_map(kernel_map, &addr, + m68k_ptob(iiomapsize+EIOMAPSIZE), + NULL, UVM_UNKNOWN_OFFSET, 0, + UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, + UVM_INH_NONE, UVM_ADV_RANDOM, + UVM_FLAG_FIXED))) + goto bogons; + addr = (vaddr_t) Sysmap; + if (uvm_map(kernel_map, &addr, M68K_MAX_PTSIZE, + NULL, UVM_UNKNOWN_OFFSET, 0, + UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, + UVM_INH_NONE, UVM_ADV_RANDOM, + UVM_FLAG_FIXED))) { + /* + * If this fails, it is probably because the static + * portion of the kernel page table isn't big enough + * and we overran the page table map. + */ + bogons: + panic("pmap_init: bogons in the VM system!\n"); + } + +#ifdef DEBUG + if (pmapdebug & PDB_INIT) { + printf("pmap_init: Sysseg %x, Sysmap %x, Sysptmap %x\n", + Sysseg, Sysmap, Sysptmap); + printf(" pstart %x, pend %x, vstart %x, vend %x\n", + avail_start, avail_end, virtual_avail, virtual_end); + } +#endif + + /* + * Allocate memory for random pmap data structures. Includes the + * initial segment table, pv_head_table and pmap_attributes. + */ + for (page_cnt = 0, bank = 0; bank < vm_nphysseg; bank++) + page_cnt += vm_physmem[bank].end - vm_physmem[bank].start; + s = M68K_STSIZE; /* Segtabzero */ + s += page_cnt * sizeof(struct pv_entry); /* pv table */ + s += page_cnt * sizeof(char); /* attribute table */ + s = round_page(s); + addr = uvm_km_zalloc(kernel_map, s); + if (addr == 0) + panic("pmap_init: can't allocate data structures"); + + Segtabzero = (st_entry_t *) addr; + pmap_extract(pmap_kernel(), addr, (paddr_t *)&Segtabzeropa); +#ifdef M68060 + if (mmutype == MMU_68060) { + addr2 = addr; + while (addr2 < addr + M68K_STSIZE) { + pmap_changebit(addr2, PG_CCB, 0); + pmap_changebit(addr2, PG_CI, 1); + addr2 += NBPG; + } + DCIS(); + } +#endif + addr += M68K_STSIZE; + + pv_table = (struct pv_entry *) addr; + addr += page_cnt * sizeof(struct pv_entry); + + pmap_attributes = (char *) addr; + +#ifdef DEBUG + if (pmapdebug & PDB_INIT) + printf("pmap_init: %lx bytes: page_cnt %x s0 %p(%p) " + "tbl %p atr %p\n", + s, page_cnt, Segtabzero, Segtabzeropa, + pv_table, pmap_attributes); +#endif + + /* + * Now that the pv and attribute tables have been allocated, + * assign them to the memory segments. + */ + pv = pv_table; + attr = pmap_attributes; + for (bank = 0; bank < vm_nphysseg; bank++) { + npages = vm_physmem[bank].end - vm_physmem[bank].start; + vm_physmem[bank].pmseg.pvent = pv; + vm_physmem[bank].pmseg.attrs = attr; + pv += npages; + attr += npages; + } + + /* + * Allocate physical memory for kernel PT pages and their management. + * We need 1 PT page per possible task plus some slop. + */ + npages = min(atop(M68K_MAX_KPTSIZE), maxproc+16); + s = ptoa(npages) + round_page(npages * sizeof(struct kpt_page)); + + /* + * Verify that space will be allocated in region for which + * we already have kernel PT pages. + */ + addr = 0; + rv = uvm_map(kernel_map, &addr, s, NULL, UVM_UNKNOWN_OFFSET, 0, + UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, + UVM_ADV_RANDOM, UVM_FLAG_NOMERGE)); + if (rv || (addr + s) >= (vaddr_t)Sysmap) + panic("pmap_init: kernel PT too small"); + uvm_unmap(kernel_map, addr, addr + s); + + /* + * Now allocate the space and link the pages together to + * form the KPT free list. + */ + addr = uvm_km_zalloc(kernel_map, s); + if (addr == 0) + panic("pmap_init: cannot allocate KPT free list"); + s = ptoa(npages); + addr2 = addr + s; + kpt_pages = &((struct kpt_page *)addr2)[npages]; + kpt_free_list = (struct kpt_page *) 0; + do { + addr2 -= NBPG; + (--kpt_pages)->kpt_next = kpt_free_list; + kpt_free_list = kpt_pages; + kpt_pages->kpt_va = addr2; + pmap_extract(pmap_kernel(), addr2, &kpt_pages->kpt_pa); +#ifdef M68060 + if (mmutype == MMU_68060) { + pmap_changebit(kpt_pages->kpt_pa, PG_CCB, 0); + pmap_changebit(kpt_pages->kpt_pa, PG_CI, 1); + DCIS(); + } +#endif + } while (addr != addr2); +#ifdef DEBUG + if (pmapdebug & PDB_INIT) + printf("pmap_init: KPT: %d pages from %x to %x\n", + atop(s), addr, addr + s); +#endif + + /* + * Allocate the segment table map + */ + s = maxproc * M68K_STSIZE; + st_map = uvm_km_suballoc(kernel_map, &addr, &addr2, s, 0, FALSE, + &st_map_store); + + /* + * Slightly modified version of kmem_suballoc() to get page table + * map where we want it. + */ + addr = M68K_PTBASE; + if ((M68K_PTMAXSIZE / M68K_MAX_PTSIZE) < maxproc) { + s = M68K_PTMAXSIZE; + /* + * XXX We don't want to hang when we run out of + * page tables, so we lower maxproc so that fork() + * will fail instead. Note that root could still raise + * this value via sysctl(2). + */ + maxproc = (M68K_PTMAXSIZE / M68K_MAX_PTSIZE); + } else + s = (maxproc * M68K_MAX_PTSIZE); + pt_map = uvm_km_suballoc(kernel_map, &addr, &addr2, s, VM_MAP_PAGEABLE, + TRUE, &pt_map_store); + +#if defined(M68040) || defined(M68060) + if (mmutype <= MMU_68040) { + protostfree = ~l2tobm(0); + for (rv = MAXUL2SIZE; rv < sizeof(protostfree)*NBBY; rv++) + protostfree &= ~l2tobm(rv); + } +#endif + + /* + * Now it is safe to enable pv_table recording. + */ + pmap_initialized = TRUE; +} + +struct pv_entry * +pmap_alloc_pv() +{ + struct pv_page *pvp; + struct pv_entry *pv; + int i; + + if (pv_nfree == 0) { + pvp = (struct pv_page *)uvm_km_zalloc(kernel_map, NBPG); + if (pvp == 0) + panic("pmap_alloc_pv: uvm_km_zalloc() failed"); + pvp->pvp_pgi.pgi_freelist = pv = &pvp->pvp_pv[1]; + for (i = NPVPPG - 2; i; i--, pv++) + pv->pv_next = pv + 1; + pv->pv_next = 0; + pv_nfree += pvp->pvp_pgi.pgi_nfree = NPVPPG - 1; + TAILQ_INSERT_HEAD(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + pv = &pvp->pvp_pv[0]; + } else { + --pv_nfree; + pvp = pv_page_freelist.tqh_first; + if (--pvp->pvp_pgi.pgi_nfree == 0) { + TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + } + pv = pvp->pvp_pgi.pgi_freelist; +#ifdef DIAGNOSTIC + if (pv == 0) + panic("pmap_alloc_pv: pgi_nfree inconsistent"); +#endif + pvp->pvp_pgi.pgi_freelist = pv->pv_next; + } + return pv; +} + +void +pmap_free_pv(pv) + struct pv_entry *pv; +{ + register struct pv_page *pvp; + register int i; + + pvp = (struct pv_page *) trunc_page((vaddr_t)pv); + switch (++pvp->pvp_pgi.pgi_nfree) { + case 1: + TAILQ_INSERT_TAIL(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + default: + pv->pv_next = pvp->pvp_pgi.pgi_freelist; + pvp->pvp_pgi.pgi_freelist = pv; + ++pv_nfree; + break; + case NPVPPG: + pv_nfree -= NPVPPG - 1; + TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + uvm_km_free(kernel_map, (vm_offset_t)pvp, NBPG); + break; + } +} + +void +pmap_collect_pv() +{ + struct pv_page_list pv_page_collectlist; + struct pv_page *pvp, *npvp; + struct pv_entry *ph, *ppv, *pv, *npv; + int s; + + TAILQ_INIT(&pv_page_collectlist); + + for (pvp = pv_page_freelist.tqh_first; pvp; pvp = npvp) { + if (pv_nfree < NPVPPG) + break; + npvp = pvp->pvp_pgi.pgi_list.tqe_next; + if (pvp->pvp_pgi.pgi_nfree > NPVPPG / 3) { + TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + TAILQ_INSERT_TAIL(&pv_page_collectlist, pvp, pvp_pgi.pgi_list); + pv_nfree -= pvp->pvp_pgi.pgi_nfree; + pvp->pvp_pgi.pgi_nfree = -1; + } + } + + if (pv_page_collectlist.tqh_first == 0) + return; + + for (ph = &pv_table[page_cnt - 1]; ph >= &pv_table[0]; ph--) { + if (ph->pv_pmap == 0) + continue; + s = splimp(); + for (ppv = ph; (pv = ppv->pv_next) != 0; ) { + pvp = (struct pv_page *) trunc_page((vaddr_t)pv); + if (pvp->pvp_pgi.pgi_nfree == -1) { + pvp = pv_page_freelist.tqh_first; + if (--pvp->pvp_pgi.pgi_nfree == 0) { + TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + } + npv = pvp->pvp_pgi.pgi_freelist; +#ifdef DIAGNOSTIC + if (npv == 0) + panic("pmap_collect_pv: pgi_nfree inconsistent"); +#endif + pvp->pvp_pgi.pgi_freelist = npv->pv_next; + *npv = *pv; + ppv->pv_next = npv; + ppv = npv; + } else + ppv = pv; + } + splx(s); + } + + for (pvp = pv_page_collectlist.tqh_first; pvp; pvp = npvp) { + npvp = pvp->pvp_pgi.pgi_list.tqe_next; + uvm_km_free(kernel_map, (vm_offset_t)pvp, NBPG); + } +} + +/* + * Used to map a range of physical addresses into kernel + * virtual address space. + * + * For now, VM is already on, we only need to map the + * specified memory. + */ +vm_offset_t +pmap_map(va, spa, epa, prot) + vm_offset_t va, spa, epa; + int prot; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_map(%x, %x, %x, %x)\n", va, spa, epa, prot); +#endif + + while (spa < epa) { + pmap_enter(pmap_kernel(), va, spa, prot, prot); + va += NBPG; + spa += NBPG; + } + return (va); +} + +/* + * 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. + */ +struct pmap * +pmap_create(void) +{ + struct pmap *pmap; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) + printf("pmap_create(%x)\n", size); +#endif + + pmap = (struct pmap *) malloc(sizeof *pmap, M_VMPMAP, M_WAITOK); + bzero(pmap, sizeof(*pmap)); + pmap_pinit(pmap); + return (pmap); +} + +/* + * Initialize a preallocated and zeroed pmap structure, + * such as one in a vmspace structure. + */ +void +pmap_pinit(pmap) + register struct pmap *pmap; +{ + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) + printf("pmap_pinit(%x)\n", pmap); +#endif + + /* + * No need to allocate page table space yet but we do need a + * valid segment table. Initially, we point everyone at the + * "null" segment table. On the first pmap_enter, a real + * segment table will be allocated. + */ + pmap->pm_stab = Segtabzero; + pmap->pm_stpa = Segtabzeropa; +#if defined(M68040) || defined(M68060) + if (mmutype <= MMU_68040) + pmap->pm_stfree = protostfree; +#endif + pmap->pm_count = 1; + simple_lock_init(&pmap->pm_lock); +} + +/* + * Retire the given physical map from service. + * Should only be called if the map contains + * no valid mappings. + */ +void +pmap_destroy(pmap) + register pmap_t pmap; +{ + int count; + + if (pmap == NULL) + return; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_destroy(%x)\n", pmap); +#endif + + simple_lock(&pmap->pm_lock); + count = --pmap->pm_count; + simple_unlock(&pmap->pm_lock); + if (count == 0) { + pmap_release(pmap); + free((caddr_t)pmap, M_VMPMAP); + } +} + +/* + * Release any resources held by the given physical map. + * Called when a pmap initialized by pmap_pinit is being released. + * Should only be called if the map contains no valid mappings. + */ +void +pmap_release(pmap) + register struct pmap *pmap; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_release(%x)\n", pmap); +#endif + +#ifdef notdef /* DIAGNOSTIC */ + /* count would be 0 from pmap_destroy... */ + simple_lock(&pmap->pm_lock); + if (pmap->pm_count != 1) + panic("pmap_release count"); +#endif + + if (pmap->pm_ptab) + uvm_km_free_wakeup(pt_map, (vm_offset_t)pmap->pm_ptab, + M68K_MAX_PTSIZE); + if (pmap->pm_stab != Segtabzero) + uvm_km_free_wakeup(st_map, (vm_offset_t)pmap->pm_stab, + M68K_STSIZE); +} + +/* + * Add a reference to the specified pmap. + */ +void +pmap_reference(pmap) + pmap_t pmap; +{ + + if (pmap == NULL) + return; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_reference(%x)\n", pmap); +#endif + + simple_lock(&pmap->pm_lock); + pmap->pm_count++; + simple_unlock(&pmap->pm_lock); +} + +/* + * Mark that a processor is about to be used by a given pmap. + */ +void +pmap_activate(p) + struct proc *p; +{ + pmap_t pmap = p->p_vmspace->vm_map.pmap; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_SEGTAB)) + printf("pmap_activate(%p)\n", p); +#endif + + PMAP_ACTIVATE(pmap, p == curproc); +} + +void +pmap_deactivate(p) + struct proc *p; +{ +} + +/* + * Remove 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_remove(pmap, sva, eva) + register pmap_t pmap; + register vm_offset_t sva, eva; +{ + register vm_offset_t nssva; + register pt_entry_t *pte; + boolean_t firstpage, needcflush; + int flags; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) + printf("pmap_remove(%x, %x, %x)\n", pmap, sva, eva); +#endif + + if (pmap == NULL) + return; + + firstpage = TRUE; + needcflush = FALSE; + flags = active_pmap(pmap) ? PRM_TFLUSH : 0; + while (sva < eva) { + nssva = m68k_trunc_seg(sva) + M68K_SEG_SIZE; + if (nssva == 0 || nssva > eva) + nssva = eva; + /* + * If VA belongs to an unallocated segment, + * skip to the next segment boundary. + */ + if (!pmap_ste_v(pmap, sva)) { + sva = nssva; + continue; + } + /* + * Invalidate every valid mapping within this segment. + */ + pte = pmap_pte(pmap, sva); + while (sva < nssva) { + if (pmap_pte_v(pte)) { + pmap_remove_mapping(pmap, sva, pte, flags); + firstpage = FALSE; + } + pte++; + sva += NBPG; + } + } + /* + * Didn't do anything, no need for cache flushes + */ + if (firstpage) + return; +} + +/* + * pmap_page_protect: + * + * Lower the permission for all mappings to a given page. + */ +void +pmap_page_protect(struct vm_page *pg, vm_prot_t prot) +{ + paddr_t pa = VM_PAGE_TO_PHYS(pg); + struct pv_entry *pv; + int s; + +#ifdef DEBUG + if ((pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) || + prot == VM_PROT_NONE && (pmapdebug & PDB_REMOVE)) + printf("pmap_page_protect(%x, %x)\n", pa, prot); +#endif + if (PAGE_IS_MANAGED(pa) == 0) + return; + + switch (prot) { + case VM_PROT_READ|VM_PROT_WRITE: + case VM_PROT_ALL: + return; + /* copy_on_write */ + case VM_PROT_READ: + case VM_PROT_READ|VM_PROT_EXECUTE: + pmap_changebit(pa, PG_RO, TRUE); + return; + /* remove_all */ + default: + break; + } + pv = pa_to_pvh(pa); + s = splimp(); + while (pv->pv_pmap != NULL) { + register pt_entry_t *pte; + + pte = pmap_pte(pv->pv_pmap, pv->pv_va); +#ifdef DEBUG + if (!pmap_ste_v(pv->pv_pmap, pv->pv_va) || + pmap_pte_pa(pte) != pa) + panic("pmap_page_protect: bad mapping"); +#endif + if (!pmap_pte_w(pte)) + pmap_remove_mapping(pv->pv_pmap, pv->pv_va, + pte, PRM_TFLUSH|PRM_CFLUSH); + else { + pv = pv->pv_next; +#ifdef DEBUG + if (pmapdebug & PDB_PARANOIA) + printf("%s wired mapping for %x not removed\n", + "pmap_page_protect:", pa); +#endif + } + } + splx(s); +} + +/* + * Set the physical protection on the + * specified range of this map as requested. + */ +void +pmap_protect(pmap, sva, eva, prot) + register pmap_t pmap; + register vm_offset_t sva, eva; + vm_prot_t prot; +{ + register vm_offset_t nssva; + register pt_entry_t *pte; + boolean_t firstpage, needtflush; + int isro; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) + printf("pmap_protect(%x, %x, %x, %x)\n", pmap, sva, eva, prot); +#endif + + if (pmap == NULL) + return; + + if ((prot & VM_PROT_READ) == VM_PROT_NONE) { + pmap_remove(pmap, sva, eva); + return; + } + if (prot & VM_PROT_WRITE) + return; + + isro = pte_prot(pmap, prot); + needtflush = active_pmap(pmap); + firstpage = TRUE; + while (sva < eva) { + nssva = m68k_trunc_seg(sva) + M68K_SEG_SIZE; + if (nssva == 0 || nssva > eva) + nssva = eva; + /* + * If VA belongs to an unallocated segment, + * skip to the next segment boundary. + */ + if (!pmap_ste_v(pmap, sva)) { + sva = nssva; + continue; + } + /* + * Change protection on mapping if it is valid and doesn't + * already have the correct protection. + */ + pte = pmap_pte(pmap, sva); + while (sva < nssva) { + if (pmap_pte_v(pte) && pmap_pte_prot_chg(pte, isro)) { +#if defined(M68040) || defined(M68060) + /* + * Clear caches if making RO (see section + * "7.3 Cache Coherency" in the manual). + */ + if (isro && mmutype <= MMU_68040) { + vm_offset_t pa = pmap_pte_pa(pte); + + DCFP(pa); + ICPP(pa); + } +#endif + pmap_pte_set_prot(pte, isro); + if (needtflush) + TBIS(sva); + firstpage = FALSE; + } + pte++; + sva += NBPG; + } + } +} + +/* + * Insert the given physical page (p) at + * the specified virtual address (v) in the + * target physical map with the protection requested. + * + * If specified, the page will be wired down, meaning + * that the related pte can not be reclaimed. + * + * NB: This is the only routine which MAY NOT lazy-evaluate + * or lose information. That is, this routine must actually + * insert this page into the given map NOW. + */ + +int +pmap_enter(pmap, va, pa, prot, flags) + pmap_t pmap; + vaddr_t va; + paddr_t pa; + vm_prot_t prot; + int flags; +{ + register pt_entry_t *pte; + register int npte; + vm_offset_t opa; + boolean_t cacheable = TRUE; + boolean_t checkpv = TRUE; + boolean_t wired = (flags & PMAP_WIRED) != 0; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_ENTER)) + printf("pmap_enter(%x, %x, %x, %x, %x)\n", + pmap, va, pa, prot, flags); +#endif + + /* + * For user mapping, allocate kernel VM resources if necessary. + */ + if (pmap->pm_ptab == NULL) + pmap->pm_ptab = (pt_entry_t *) + uvm_km_valloc_wait(pt_map, M68K_MAX_PTSIZE); + + /* + * Segment table entry not valid, we need a new PT page + */ + if (!pmap_ste_v(pmap, va)) + pmap_enter_ptpage(pmap, va); + + pa = m68k_trunc_page(pa); + pte = pmap_pte(pmap, va); + opa = pmap_pte_pa(pte); +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: pte %x, *pte %x\n", pte, *pte); +#endif + + /* + * Mapping has not changed, must be protection or wiring change. + */ + if (opa == pa) { + /* + * Wiring change, just update stats. + * We don't worry about wiring PT pages as they remain + * resident as long as there are valid mappings in them. + * Hence, if a user page is wired, the PT page will be also. + */ + if (pmap_pte_w_chg(pte, wired ? PG_W : 0)) { +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: wiring change -> %x\n", wired); +#endif + if (wired) + pmap->pm_stats.wired_count++; + else + pmap->pm_stats.wired_count--; + } + /* + * Retain cache inhibition status + */ + checkpv = FALSE; + if (pmap_pte_ci(pte)) + cacheable = FALSE; + goto validate; + } + + /* + * Mapping has changed, invalidate old range and fall through to + * handle validating new mapping. + */ + if (opa) { +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: removing old mapping %x\n", va); +#endif + pmap_remove_mapping(pmap, va, pte, + PRM_TFLUSH|PRM_CFLUSH|PRM_KEEPPTPAGE); + } + + /* + * If this is a new user mapping, increment the wiring count + * on this PT page. PT pages are wired down as long as there + * is a valid mapping in the page. + */ + if (pmap != pmap_kernel()) { + pmap_ptpage_addref(trunc_page((vaddr_t)pte)); + } + + /* + * Enter on the PV list if part of our managed memory + * Note that we raise IPL while manipulating pv_table + * since pmap_enter can be called at interrupt time. + */ + if (PAGE_IS_MANAGED(pa)) { + register struct pv_entry *pv, *npv; + int s; + + pv = pa_to_pvh(pa); + s = splimp(); +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: pv at %x: %x/%x/%x\n", + pv, pv->pv_va, pv->pv_pmap, pv->pv_next); +#endif + /* + * No entries yet, use header as the first entry + */ + if (pv->pv_pmap == NULL) { + pv->pv_va = va; + pv->pv_pmap = pmap; + pv->pv_next = NULL; + pv->pv_ptste = NULL; + pv->pv_ptpmap = NULL; + pv->pv_flags = 0; + } + /* + * There is at least one other VA mapping this page. + * Place this entry after the header. + */ + else { +#ifdef DEBUG + for (npv = pv; npv; npv = npv->pv_next) + if (pmap == npv->pv_pmap && va == npv->pv_va) + panic("pmap_enter: already in pv_tab"); +#endif + npv = pmap_alloc_pv(); + npv->pv_va = va; + npv->pv_pmap = pmap; + npv->pv_next = pv->pv_next; + npv->pv_ptste = NULL; + npv->pv_ptpmap = NULL; + npv->pv_flags = 0; + pv->pv_next = npv; + } + splx(s); + } + /* + * Assumption: if it is not part of our managed memory + * then it must be device memory which may be volitile. + */ + else if (pmap_initialized) { + checkpv = cacheable = FALSE; + } + + /* + * Increment counters + */ + pmap->pm_stats.resident_count++; + if (wired) + pmap->pm_stats.wired_count++; + +validate: + /* + * Build the new PTE. + */ + npte = pa | pte_prot(pmap, prot) | (*pte & (PG_M|PG_U)) | PG_V; + if (wired) + npte |= PG_W; + + /* Don't cache if process can't take it, like SunOS ones. */ + if (mmutype <= MMU_68040 && pmap != pmap_kernel() && + (curproc->p_md.md_flags & MDP_UNCACHE_WX) && + (prot & VM_PROT_EXECUTE) && (prot & VM_PROT_WRITE)) + checkpv = cacheable = FALSE; + + if (!checkpv && !cacheable) + npte |= PG_CI; +#if defined(M68040) || defined(M68060) + if (mmutype <= MMU_68040 && (npte & (PG_PROT|PG_CI)) == PG_RW) +#ifdef DEBUG + if (dowriteback && (dokwriteback || pmap != pmap_kernel())) +#endif + npte |= PG_CCB; +#endif +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: new pte value %x\n", npte); +#endif + /* + * Remember if this was a wiring-only change. + * If so, we need not flush the TLB and caches. + */ + wired = ((*pte ^ npte) == PG_W); +#if defined(M68040) || defined(M68060) + if (mmutype <= MMU_68040 && !wired) { + DCFP(pa); + ICPP(pa); + } +#endif + *pte = npte; + if (!wired && active_pmap(pmap)) + TBIS(va); +#ifdef DEBUG + if ((pmapdebug & PDB_WIRING) && pmap != pmap_kernel()) + pmap_check_wiring("enter", trunc_page(pmap_pte(pmap, va))); +#endif + + return (0); +} + +/* + * Routine: pmap_unwire + * Function: Change the wiring attribute for a map/virtual-address + * pair. + * In/out conditions: + * The mapping must already exist in the pmap. + */ +void +pmap_unwire(pmap, va) + pmap_t pmap; + vm_offset_t va; +{ + pt_entry_t *pte; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_unwire(%x, %x)\n", pmap, va); +#endif + if (pmap == NULL) + return; + + pte = pmap_pte(pmap, va); +#ifdef DEBUG + /* + * Page table page is not allocated. + * Should this ever happen? Ignore it for now, + * we don't want to force allocation of unnecessary PTE pages. + */ + if (!pmap_ste_v(pmap, va)) { + if (pmapdebug & PDB_PARANOIA) + printf("pmap_unwire: invalid STE for %x\n", va); + return; + } + /* + * Page not valid. Should this ever happen? + * Just continue and change wiring anyway. + */ + if (!pmap_pte_v(pte)) { + if (pmapdebug & PDB_PARANOIA) + printf("pmap_unwire: invalid PTE for %x\n", va); + } +#endif + /* + * If wiring actually changed (always?) set the wire bit and + * update the wire count. Note that wiring is not a hardware + * characteristic so there is no need to invalidate the TLB. + */ + if (pmap_pte_w_chg(pte, 0)) { + pmap_pte_set_w(pte, 0); + pmap->pm_stats.wired_count--; + } +} + +/* + * Routine: pmap_extract + * Function: + * Extract the physical page address associated + * with the given map/virtual_address pair. + */ + +boolean_t +pmap_extract(pmap, va, pap) + pmap_t pmap; + vm_offset_t va; + paddr_t *pap; +{ + paddr_t pa; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_extract(%x, %x) -> ", pmap, va); +#endif + if (pmap && pmap_ste_v(pmap, va)) + pa = *pmap_pte(pmap, va); + else + return (FALSE); + *pap = (pa & PG_FRAME) | (va & ~PG_FRAME); +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("%x\n", *pap); +#endif + return (TRUE); +} + +/* + * Copy the range specified by src_addr/len + * from the source map to the range dst_addr/len + * in the destination map. + * + * This routine is only advisory and need not do anything. + */ +void pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr) + pmap_t dst_pmap; + pmap_t src_pmap; + vm_offset_t dst_addr; + vm_size_t len; + vm_offset_t src_addr; +{ +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_copy(%x, %x, %x, %x, %x)\n", + dst_pmap, src_pmap, dst_addr, len, src_addr); +#endif +} + +/* + * Routine: pmap_collect + * Function: + * Garbage collects the physical map system for + * pages which are no longer used. + * Success need not be guaranteed -- that is, there + * may well be pages which are not referenced, but + * others may be collected. + * Usage: + * Called by the pageout daemon when pages are scarce. + */ +void +pmap_collect(pmap) + pmap_t pmap; +{ + int bank, s; + + if (pmap != pmap_kernel()) + return; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_collect(%p)\n", pmap); +#endif + s = splimp(); + for (bank = 0; bank < vm_nphysseg; bank++) + pmap_collect1(pmap, ptoa(vm_physmem[bank].start), + ptoa(vm_physmem[bank].end)); + splx(s); + +#ifdef notyet + /* Go compact and garbage-collect the pv_table. */ + pmap_collect_pv(); +#endif +} + +/* + * Routine: pmap_collect1() + * + * Function: + * Helper function for pmap_collect(). Do the actual + * garbage-collection of range of physical addresses. + */ +void +pmap_collect1(pmap, startpa, endpa) + pmap_t pmap; + vm_offset_t startpa, endpa; +{ + vm_offset_t pa; + struct pv_entry *pv; + pt_entry_t *pte; + vm_offset_t kpa; +#ifdef DEBUG + st_entry_t *ste; + int opmapdebug = 0 /* XXX initialize to quiet gcc -Wall */; +#endif + + for (pa = startpa; pa < endpa; pa += NBPG) { + struct kpt_page *kpt, **pkpt; + + /* + * Locate physical pages which are being used as kernel + * page table pages. + */ + pv = pa_to_pvh(pa); + if (pv->pv_pmap != pmap_kernel() || !(pv->pv_flags & PV_PTPAGE)) + continue; + do { + if (pv->pv_ptste && pv->pv_ptpmap == pmap_kernel()) + break; + } while ((pv = pv->pv_next)); + if (pv == NULL) + continue; +#ifdef DEBUG1 + if (pv->pv_va < (vm_offset_t)Sysmap || + pv->pv_va >= (vm_offset_t)Sysmap + HP_MAX_PTSIZE) + printf("collect: kernel PT VA out of range\n"); + else + goto ok; + pmap_pvdump(pa); + continue; +ok: +#endif + pte = (pt_entry_t *)(pv->pv_va + NBPG); + while (--pte >= (pt_entry_t *)pv->pv_va && *pte == PG_NV) + ; + if (pte >= (pt_entry_t *)pv->pv_va) + continue; + +#ifdef DEBUG + if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) { + printf("collect: freeing KPT page at %lx (ste %x@%p)\n", + pv->pv_va, *pv->pv_ptste, pv->pv_ptste); + opmapdebug = pmapdebug; + pmapdebug |= PDB_PTPAGE; + } + + ste = pv->pv_ptste; +#endif + /* + * If all entries were invalid we can remove the page. + * We call pmap_remove_entry to take care of invalidating + * ST and Sysptmap entries. + */ + pmap_extract(pmap, pv->pv_va, &kpa); + pmap_remove_mapping(pmap, pv->pv_va, PT_ENTRY_NULL, + PRM_TFLUSH|PRM_CFLUSH); + /* + * Use the physical address to locate the original + * (kmem_alloc assigned) address for the page and put + * that page back on the free list. + */ + for (pkpt = &kpt_used_list, kpt = *pkpt; + kpt != (struct kpt_page *)0; + pkpt = &kpt->kpt_next, kpt = *pkpt) + if (kpt->kpt_pa == kpa) + break; +#ifdef DEBUG + if (kpt == (struct kpt_page *)0) + panic("pmap_collect: lost a KPT page"); + if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) + printf("collect: %lx (%lx) to free list\n", + kpt->kpt_va, kpa); +#endif + *pkpt = kpt->kpt_next; + kpt->kpt_next = kpt_free_list; + kpt_free_list = kpt; +#ifdef DEBUG + if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) + pmapdebug = opmapdebug; + + if (*ste != SG_NV) + printf("collect: kernel STE at %p still valid (%x)\n", + ste, *ste); + ste = &Sysptmap[ste - pmap_ste(pmap_kernel(), 0)]; + if (*ste != SG_NV) + printf("collect: kernel PTmap at %p still valid (%x)\n", + ste, *ste); +#endif + } +} + +/* + * pmap_zero_page zeros the specified (machine independent) + * page by mapping the page into virtual memory and using + * bzero to clear its contents, one machine dependent page + * at a time. + * + * XXX this is a bad implementation for virtual cache machines + * (320/350) because pmap_enter doesn't cache-inhibit the temporary + * kernel mapping and we wind up with data cached for that KVA. + * It is probably a win for physical cache machines (370/380) + * as the cache loading is not wasted. + */ +void +pmap_zero_page(phys) + vm_offset_t phys; +{ + register vm_offset_t kva; + extern caddr_t CADDR1; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_zero_page(%x)\n", phys); +#endif + kva = (vm_offset_t) CADDR1; + pmap_enter(pmap_kernel(), kva, phys, VM_PROT_READ|VM_PROT_WRITE, VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED); + zeropage((caddr_t)kva); + pmap_remove_mapping(pmap_kernel(), kva, PT_ENTRY_NULL, + PRM_TFLUSH|PRM_CFLUSH); +} + +/* + * pmap_copy_page copies the specified (machine independent) + * page by mapping the page into virtual memory and using + * bcopy to copy the page, one machine dependent page at a + * time. + * + * + * XXX this is a bad implementation for virtual cache machines + * (320/350) because pmap_enter doesn't cache-inhibit the temporary + * kernel mapping and we wind up with data cached for that KVA. + * It is probably a win for physical cache machines (370/380) + * as the cache loading is not wasted. + */ +void +pmap_copy_page(src, dst) + vm_offset_t src, dst; +{ + register vm_offset_t skva, dkva; + extern caddr_t CADDR1, CADDR2; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_copy_page(%x, %x)\n", src, dst); +#endif + skva = (vm_offset_t) CADDR1; + dkva = (vm_offset_t) CADDR2; + pmap_enter(pmap_kernel(), skva, src, VM_PROT_READ, VM_PROT_READ|PMAP_WIRED); + pmap_enter(pmap_kernel(), dkva, dst, VM_PROT_READ|VM_PROT_WRITE, VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED); + copypage((caddr_t)skva, (caddr_t)dkva); + /* CADDR1 and CADDR2 are virtually contiguous */ + pmap_remove(pmap_kernel(), skva, skva + (2 * NBPG)); +} + +/* + * Clear the modify bits on the specified physical page. + */ + +boolean_t +pmap_clear_modify(struct vm_page *pg) +{ + paddr_t pa = VM_PAGE_TO_PHYS(pg); + boolean_t ret; + + ret = pmap_is_modified(pg); + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_clear_modify(%x)\n", pa); +#endif + pmap_changebit(pa, PG_M, FALSE); + + return (ret); +} + +/* + * pmap_clear_reference: + * + * Clear the reference bit on the specified physical page. + */ + +boolean_t +pmap_clear_reference(struct vm_page *pg) +{ + paddr_t pa = VM_PAGE_TO_PHYS(pg); + boolean_t ret; + + ret = pmap_is_referenced(pg); + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_clear_reference(%x)\n", pa); +#endif + pmap_changebit(pa, PG_U, FALSE); + + return (ret); +} + +/* + * pmap_is_referenced: + * + * Return whether or not the specified physical page is referenced + * by any physical maps. + */ + +boolean_t +pmap_is_referenced(struct vm_page *pg) +{ + paddr_t pa = VM_PAGE_TO_PHYS(pg); + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) { + boolean_t rv = pmap_testbit(pa, PG_U); + printf("pmap_is_referenced(%x) -> %c\n", pa, "FT"[rv]); + return(rv); + } +#endif + return(pmap_testbit(pa, PG_U)); +} + +/* + * pmap_is_modified: + * + * Return whether or not the specified physical page is modified + * by any physical maps. + */ + +boolean_t +pmap_is_modified(struct vm_page *pg) +{ + paddr_t pa = VM_PAGE_TO_PHYS(pg); +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) { + boolean_t rv = pmap_testbit(pa, PG_M); + printf("pmap_is_modified(%x) -> %c\n", pa, "FT"[rv]); + return(rv); + } +#endif + return(pmap_testbit(pa, PG_M)); +} + +vm_offset_t +pmap_phys_address(ppn) + int ppn; +{ + return(m68k_ptob(ppn)); +} + +#ifdef COMPAT_HPUX +/* + * 'PUX hack for dealing with the so called multi-mapped address space. + * The first 256mb is mapped in at every 256mb region from 0x10000000 + * up to 0xF0000000. This allows for 15 bits of tag information. + * + * We implement this at the segment table level, the machine independent + * VM knows nothing about it. + */ +pmap_mapmulti(pmap, va) + pmap_t pmap; + vm_offset_t va; +{ + st_entry_t *ste, *bste; + +#ifdef DEBUG + if (pmapdebug & PDB_MULTIMAP) { + ste = pmap_ste(pmap, HPMMBASEADDR(va)); + printf("pmap_mapmulti(%x, %x): bste %x(%x)", + pmap, va, ste, *ste); + ste = pmap_ste(pmap, va); + printf(" ste %x(%x)\n", ste, *ste); + } +#endif + bste = pmap_ste(pmap, HPMMBASEADDR(va)); + ste = pmap_ste(pmap, va); + if (*ste == SG_NV && (*bste & SG_V)) { + *ste = *bste; + TBIAU(); + return (0); + } + return (EFAULT); +} +#endif + +/* + * Miscellaneous support routines follow + */ + +/* + * Invalidate a single page denoted by pmap/va. + * If (pte != NULL), it is the already computed PTE for the page. + * If (flags & PRM_TFLUSH), we must invalidate any TLB information. + * If (flags & PRM_CFLUSH), we must flush/invalidate any cache information. + * If (flags & PRM_KEEPPTPAGE), we don't free the page table page if the + * reference drops to zero. + */ +/* static */ +void +pmap_remove_mapping(pmap, va, pte, flags) + register pmap_t pmap; + register vm_offset_t va; + register pt_entry_t *pte; + int flags; +{ + register vm_offset_t pa; + register struct pv_entry *pv, *npv; + pmap_t ptpmap; + st_entry_t *ste; + int s, bits; +#ifdef DEBUG + pt_entry_t opte; + + if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) + printf("pmap_remove_mapping(%x, %x, %x, %x)\n", + pmap, va, pte, flags); +#endif + + /* + * PTE not provided, compute it from pmap and va. + */ + if (pte == PT_ENTRY_NULL) { + pte = pmap_pte(pmap, va); + if (*pte == PG_NV) + return; + } + pa = pmap_pte_pa(pte); +#ifdef DEBUG + opte = *pte; +#endif + /* + * Update statistics + */ + if (pmap_pte_w(pte)) + pmap->pm_stats.wired_count--; + pmap->pm_stats.resident_count--; + + /* + * Invalidate the PTE after saving the reference modify info. + */ +#ifdef DEBUG + if (pmapdebug & PDB_REMOVE) + printf("remove: invalidating pte at %x\n", pte); +#endif + bits = *pte & (PG_U|PG_M); + *pte = PG_NV; + if ((flags & PRM_TFLUSH) && active_pmap(pmap)) + TBIS(va); + /* + * For user mappings decrement the wiring count on + * the PT page. We do this after the PTE has been + * invalidated because vm_map_pageable winds up in + * pmap_pageable which clears the modify bit for the + * PT page. + */ + if (pmap != pmap_kernel()) { + vaddr_t ptpva = trunc_page((vaddr_t)pte); + int refs = pmap_ptpage_delref(ptpva); + + /* + * If reference count drops to 1, and we're not instructed + * to keep it around, free the PT page. + * + * Note: refcnt == 1 comes from the fact that we allocate + * the page with uvm_fault_wire(), which initially wires + * the page. The first reference we actually add causes + * the refcnt to be 2. + */ + if (refs == 1 && (flags & PRM_KEEPPTPAGE) == 0) { + struct pv_entry *pv; + paddr_t pa; + + pa = pmap_pte_pa(pmap_pte(pmap_kernel(), ptpva)); +#ifdef DIAGNOSTIC + if (PAGE_IS_MANAGED(pa) == 0) + panic("pmap_remove_mapping: unmanaged PT page"); +#endif + pv = pa_to_pvh(pa); +#ifdef DIAGNOSTIC + if (pv->pv_ptste == NULL) + panic("pmap_remove_mapping: ptste == NULL"); + if (pv->pv_pmap != pmap_kernel() || + pv->pv_va != ptpva || + pv->pv_next != NULL) + panic("pmap_remove_mapping: " + "bad PT page pmap %p, va 0x%lx, next %p", + pv->pv_pmap, pv->pv_va, pv->pv_next); +#endif + pmap_remove_mapping(pv->pv_pmap, pv->pv_va, + NULL, PRM_TFLUSH|PRM_CFLUSH); + uvm_pagefree(PHYS_TO_VM_PAGE(pa)); +#ifdef DEBUG + if (pmapdebug & (PDB_REMOVE|PDB_PTPAGE)) + printf("remove: PT page 0x%lx (0x%lx) freed\n", + ptpva, pa)); +#endif + } +#ifdef DEBUG + if (pmapdebug & PDB_WIRING) + pmap_check_wiring("remove", trunc_page(pte)); +#endif + } + /* + * If this isn't a managed page, we are all done. + */ + if (PAGE_IS_MANAGED(pa) == 0) + return; + /* + * Otherwise remove it from the PV table + * (raise IPL since we may be called at interrupt time). + */ + pv = pa_to_pvh(pa); + ste = ST_ENTRY_NULL; + s = splimp(); + /* + * If it is the first entry on the list, it is actually + * in the header and we must copy the following entry up + * to the header. Otherwise we must search the list for + * the entry. In either case we free the now unused entry. + */ + if (pmap == pv->pv_pmap && va == pv->pv_va) { + ste = pv->pv_ptste; + ptpmap = pv->pv_ptpmap; + npv = pv->pv_next; + if (npv) { + npv->pv_flags = pv->pv_flags; + *pv = *npv; + pmap_free_pv(npv); + } else + pv->pv_pmap = NULL; + } else { + for (npv = pv->pv_next; npv; npv = npv->pv_next) { + if (pmap == npv->pv_pmap && va == npv->pv_va) + break; + pv = npv; + } +#ifdef DEBUG + if (npv == NULL) + panic("pmap_remove: PA not in pv_tab"); +#endif + ste = npv->pv_ptste; + ptpmap = npv->pv_ptpmap; + pv->pv_next = npv->pv_next; + pmap_free_pv(npv); + pv = pa_to_pvh(pa); + } + /* + * If this was a PT page we must also remove the + * mapping from the associated segment table. + */ + if (ste) { +#ifdef DEBUG + if (pmapdebug & (PDB_REMOVE|PDB_PTPAGE)) + printf("remove: ste was %x@%x pte was %x@%x\n", + *ste, ste, opte, pmap_pte(pmap, va)); +#endif +#if defined(M68040) || defined(M68060) + if (mmutype <= MMU_68040) { + st_entry_t *este = &ste[NPTEPG/SG4_LEV3SIZE]; + + while (ste < este) + *ste++ = SG_NV; +#ifdef DEBUG + ste -= NPTEPG/SG4_LEV3SIZE; +#endif + } else +#endif + *ste = SG_NV; + /* + * If it was a user PT page, we decrement the + * reference count on the segment table as well, + * freeing it if it is now empty. + */ + if (ptpmap != pmap_kernel()) { +#ifdef DEBUG + if (pmapdebug & (PDB_REMOVE|PDB_SEGTAB)) + printf("remove: stab %x, refcnt %d\n", + ptpmap->pm_stab, ptpmap->pm_sref - 1); + if ((pmapdebug & PDB_PARANOIA) && + ptpmap->pm_stab != (st_entry_t *)trunc_page(ste)) + panic("remove: bogus ste"); +#endif + if (--(ptpmap->pm_sref) == 0) { +#ifdef DEBUG + if (pmapdebug&(PDB_REMOVE|PDB_SEGTAB)) + printf("remove: free stab %x\n", + ptpmap->pm_stab); +#endif + uvm_km_free_wakeup(st_map, + (vm_offset_t)ptpmap->pm_stab, + M68K_STSIZE); + ptpmap->pm_stab = Segtabzero; + ptpmap->pm_stpa = Segtabzeropa; +#if defined(M68040) || defined(M68060) + if (mmutype <= MMU_68040) + ptpmap->pm_stfree = protostfree; +#endif + /* + * XXX may have changed segment table + * pointer for current process so + * update now to reload hardware. + */ + if (active_user_pmap(ptpmap)) + PMAP_ACTIVATE(ptpmap, 1); + } +#ifdef DEBUG + else if (ptpmap->pm_sref < 0) + panic("remove: sref < 0"); +#endif + } +#if 0 + /* + * XXX this should be unnecessary as we have been + * flushing individual mappings as we go. + */ + if (ptpmap == pmap_kernel()) + TBIAS(); + else + TBIAU(); +#endif + pv->pv_flags &= ~PV_PTPAGE; + ptpmap->pm_ptpages--; + } + /* + * Update saved attributes for managed page + */ + *pa_to_attribute(pa) |= bits; + splx(s); +} + +/* static */ +boolean_t +pmap_testbit(pa, bit) + register vm_offset_t pa; + int bit; +{ + register struct pv_entry *pv; + register pt_entry_t *pte; + int s; + + if (PAGE_IS_MANAGED(pa) == 0) + return(FALSE); + + pv = pa_to_pvh(pa); + s = splimp(); + /* + * Check saved info first + */ + if (*pa_to_attribute(pa) & bit) { + splx(s); + return(TRUE); + } + /* + * Not found, check current mappings returning + * immediately if found. + */ + if (pv->pv_pmap != NULL) { + for (; pv; pv = pv->pv_next) { + pte = pmap_pte(pv->pv_pmap, pv->pv_va); + if (*pte & bit) { + splx(s); + return(TRUE); + } + } + } + splx(s); + return(FALSE); +} + +/* static */ +void +pmap_changebit(pa, bit, setem) + register vm_offset_t pa; + int bit; + boolean_t setem; +{ + register struct pv_entry *pv; + register pt_entry_t *pte, npte; + vm_offset_t va; + int s; + boolean_t firstpage = TRUE; + +#ifdef DEBUG + if (pmapdebug & PDB_BITS) + printf("pmap_changebit(%x, %x, %s)\n", + pa, bit, setem ? "set" : "clear"); +#endif + if (PAGE_IS_MANAGED(pa) == 0) + return; + + pv = pa_to_pvh(pa); + s = splimp(); + /* + * Clear saved attributes (modify, reference) + */ + if (!setem) + *pa_to_attribute(pa) &= ~bit; + /* + * Loop over all current mappings setting/clearing as appropos + * If setting RO do we need to clear the VAC? + */ + if (pv->pv_pmap != NULL) { +#ifdef DEBUG + int toflush = 0; +#endif + for (; pv; pv = pv->pv_next) { +#ifdef DEBUG + toflush |= (pv->pv_pmap == pmap_kernel()) ? 2 : 1; +#endif + va = pv->pv_va; + + /* + * XXX don't write protect pager mappings + */ + if (bit == PG_RO) { + if (va >= uvm.pager_sva && va < uvm.pager_eva) + continue; + } + + pte = pmap_pte(pv->pv_pmap, va); + if (setem) + npte = *pte | bit; + else + npte = *pte & ~bit; + if (*pte != npte) { +#if defined(M68040) || defined(M68060) + /* + * If we are changing caching status or + * protection make sure the caches are + * flushed (but only once). + */ + if (firstpage && mmutype <= MMU_68040 && + (bit == PG_RO && setem || + (bit & PG_CMASK))) { + firstpage = FALSE; + DCFP(pa); + ICPP(pa); + } +#endif + *pte = npte; + if (active_pmap(pv->pv_pmap)) + TBIS(va); + } + } + } + splx(s); +} + +/* static */ +void +pmap_enter_ptpage(pmap, va) + register pmap_t pmap; + register vm_offset_t va; +{ + vm_offset_t ptpa; + register struct pv_entry *pv; +#ifdef M68060 + u_int stpa; +#endif + st_entry_t *ste; + int s; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_ENTER|PDB_PTPAGE)) + printf("pmap_enter_ptpage: pmap %x, va %x\n", pmap, va); +#endif + /* + * Allocate a segment table if necessary. Note that it is allocated + * from a private map and not pt_map. This keeps user page tables + * aligned on segment boundaries in the kernel address space. + * The segment table is wired down. It will be freed whenever the + * reference count drops to zero. + */ + if (pmap->pm_stab == Segtabzero) { + pmap->pm_stab = (st_entry_t *) + uvm_km_zalloc(st_map, M68K_STSIZE); + pmap_extract(pmap_kernel(), (vm_offset_t)pmap->pm_stab, + (paddr_t *)&pmap->pm_stpa); +#if defined(M68040) || defined(M68060) + if (mmutype <= MMU_68040) { +#ifdef DEBUG + if (dowriteback && dokwriteback) +#endif +#if defined(M68060) + stpa = (u_int)pmap->pm_stpa; + if (mmutype == MMU_68060) { + while (stpa < (u_int)pmap->pm_stpa + + M68K_STSIZE) { + pmap_changebit(stpa, PG_CCB, 0); + pmap_changebit(stpa, PG_CI, 1); + stpa += NBPG; + } + DCIS(); /* XXX */ + } + else +#endif + pmap_changebit((vm_offset_t)pmap->pm_stpa, PG_CCB, 0); + pmap->pm_stfree = protostfree; + } +#endif + /* + * XXX may have changed segment table pointer for current + * process so update now to reload hardware. + */ + if (active_user_pmap(pmap)) + PMAP_ACTIVATE(pmap, 1); +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB)) + printf("enter: pmap %x stab %x(%x)\n", + pmap, pmap->pm_stab, pmap->pm_stpa); +#endif + } + + ste = pmap_ste(pmap, va); +#if defined(M68040) || defined(M68060) + /* + * Allocate level 2 descriptor block if necessary + */ + if (mmutype <= MMU_68040) { + if (*ste == SG_NV) { + int ix; + caddr_t addr; + + ix = bmtol2(pmap->pm_stfree); + if (ix == -1) + panic("enter: out of address space"); /* XXX */ + pmap->pm_stfree &= ~l2tobm(ix); + addr = (caddr_t)&pmap->pm_stab[ix*SG4_LEV2SIZE]; + bzero(addr, SG4_LEV2SIZE*sizeof(st_entry_t)); + addr = (caddr_t)&pmap->pm_stpa[ix*SG4_LEV2SIZE]; + *ste = (u_int)addr | SG_RW | SG_U | SG_V; +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB)) + printf("enter: alloc ste2 %d(%x)\n", ix, addr); +#endif + } + ste = pmap_ste2(pmap, va); + /* + * Since a level 2 descriptor maps a block of SG4_LEV3SIZE + * level 3 descriptors, we need a chunk of NPTEPG/SG4_LEV3SIZE + * (16) such descriptors (NBPG/SG4_LEV3SIZE bytes) to map a + * PT page--the unit of allocation. We set `ste' to point + * to the first entry of that chunk which is validated in its + * entirety below. + */ + ste = (st_entry_t *)((int)ste & ~(NBPG/SG4_LEV3SIZE-1)); +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB)) + printf("enter: ste2 %x (%x)\n", + pmap_ste2(pmap, va), ste); +#endif + } +#endif + va = trunc_page((vm_offset_t)pmap_pte(pmap, va)); + + /* + * In the kernel we allocate a page from the kernel PT page + * free list and map it into the kernel page table map (via + * pmap_enter). + */ + if (pmap == pmap_kernel()) { + register struct kpt_page *kpt; + + s = splimp(); + if ((kpt = kpt_free_list) == (struct kpt_page *)0) { + /* + * No PT pages available. + * Try once to free up unused ones. + */ +#ifdef DEBUG + if (pmapdebug & PDB_COLLECT) + printf("enter: no KPT pages, collecting...\n"); +#endif + pmap_collect(pmap_kernel()); + if ((kpt = kpt_free_list) == (struct kpt_page *)0) + panic("pmap_enter_ptpage: can't get KPT page"); + } + kpt_free_list = kpt->kpt_next; + kpt->kpt_next = kpt_used_list; + kpt_used_list = kpt; + ptpa = kpt->kpt_pa; + bzero((caddr_t)kpt->kpt_va, NBPG); + pmap_enter(pmap, va, ptpa, VM_PROT_DEFAULT, VM_PROT_DEFAULT|PMAP_WIRED); +#if defined(M68060) + if (mmutype == MMU_68060) { + pmap_changebit(ptpa, PG_CCB, 0); + pmap_changebit(ptpa, PG_CI, 1); + DCIS(); + } +#endif +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE)) { + int ix = pmap_ste(pmap, va) - pmap_ste(pmap, 0); + + printf("enter: add &Sysptmap[%d]: %x (KPT page %x)\n", + ix, Sysptmap[ix], kpt->kpt_va); + } +#endif + splx(s); + } + /* + * For user processes we just simulate a fault on that location + * letting the VM system allocate a zero-filled page. + */ + else { + /* + * Count the segment table reference now so that we won't + * lose the segment table when low on memory. + */ + pmap->pm_sref++; +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE)) + printf("enter: about to fault UPT pg at %x\n", va); +#endif + if (uvm_fault_wire(pt_map, va, va + PAGE_SIZE, + VM_PROT_READ|VM_PROT_WRITE)) + panic("pmap_enter: uvm_fault failed"); + pmap_extract(pmap_kernel(), va, &ptpa); + } +#if defined(M68040) || defined(M68060) + /* + * Turn off copyback caching of page table pages, + * could get ugly otherwise. + */ +#ifdef DEBUG + if (dowriteback && dokwriteback) +#endif + if (mmutype <= MMU_68040) { + pt_entry_t *pte = pmap_pte(pmap_kernel(), va); +#ifdef DEBUG + if ((pmapdebug & PDB_PARANOIA) && (*pte & PG_CCB) == 0) + printf("%s PT no CCB: kva=%x ptpa=%x pte@%x=%x\n", + pmap == pmap_kernel() ? "Kernel" : "User", + va, ptpa, pte, *pte); +#endif + pmap_changebit(ptpa, PG_CCB, 0); +#ifdef M68060 + if (mmutype == MMU_68060) { + pmap_changebit(ptpa, PG_CI, 1); + DCIS(); + } +#endif + } +#endif + /* + * Locate the PV entry in the kernel for this PT page and + * record the STE address. This is so that we can invalidate + * the STE when we remove the mapping for the page. + */ + pv = pa_to_pvh(ptpa); + s = splimp(); + if (pv) { + pv->pv_flags |= PV_PTPAGE; + do { + if (pv->pv_pmap == pmap_kernel() && pv->pv_va == va) + break; + } while (pv = pv->pv_next); + } +#ifdef DEBUG + if (pv == NULL) { + pv = pa_to_pvh(ptpa); + if (pv) { + printf("pv->pv_next = %x\n", pv->pv_next); + do { + printf("pmap %x va %x ptste %x ptpmap %x flags %x\n", + pv->pv_pmap, pv->pv_va, pv->pv_ptste, pv->pv_ptpmap, + pv->pv_flags); + if (pv->pv_pmap == pmap_kernel() && pv->pv_va == va) + break; + } while (pv = pv->pv_next); + } else + printf("pv at ptpa is 0\n"); + panic("pmap_enter_ptpage: PT page not entered"); + } +#endif + pv->pv_ptste = ste; + pv->pv_ptpmap = pmap; +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE)) + printf("enter: new PT page at PA %x, ste at %x\n", ptpa, ste); +#endif + + /* + * Map the new PT page into the segment table. + * Also increment the reference count on the segment table if this + * was a user page table page. Note that we don't use vm_map_pageable + * to keep the count like we do for PT pages, this is mostly because + * it would be difficult to identify ST pages in pmap_pageable to + * release them. We also avoid the overhead of vm_map_pageable. + */ +#if defined(M68040) || defined(M68060) + if (mmutype <= MMU_68040) { + st_entry_t *este; + + for (este = &ste[NPTEPG/SG4_LEV3SIZE]; ste < este; ste++) { + *ste = ptpa | SG_U | SG_RW | SG_V; + ptpa += SG4_LEV3SIZE * sizeof(st_entry_t); + } + } else +#endif + *ste = (ptpa & SG_FRAME) | SG_RW | SG_V; + if (pmap != pmap_kernel()) { +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB)) + printf("enter: stab %x refcnt %d\n", + pmap->pm_stab, pmap->pm_sref); +#endif + } +#if 0 + /* + * Flush stale TLB info. + */ + if (pmap == pmap_kernel()) + TBIAS(); + else + TBIAU(); +#endif + pmap->pm_ptpages++; + splx(s); +} + +/* + * pmap_ptpage_addref: + * + * Add a reference to the specified PT page. + */ +void +pmap_ptpage_addref(ptpva) + vaddr_t ptpva; +{ + struct vm_page *m; + + simple_lock(&uvm.kernel_object->vmobjlock); + m = uvm_pagelookup(uvm.kernel_object, ptpva - vm_map_min(kernel_map)); + m->wire_count++; + simple_unlock(&uvm.kernel_object->vmobjlock); +} + +/* + * pmap_ptpage_delref: + * + * Delete a reference to the specified PT page. + */ +int +pmap_ptpage_delref(ptpva) + vaddr_t ptpva; +{ + struct vm_page *m; + int rv; + + simple_lock(&uvm.kernel_object->vmobjlock); + m = uvm_pagelookup(uvm.kernel_object, ptpva - vm_map_min(kernel_map)); + rv = --m->wire_count; + simple_unlock(&uvm.kernel_object->vmobjlock); + return (rv); +} + +#ifdef DEBUG +/* static */ +void +pmap_pvdump(pa) + vm_offset_t pa; +{ + register struct pv_entry *pv; + + printf("pa %x", pa); + for (pv = pa_to_pvh(pa); pv; pv = pv->pv_next) + printf(" -> pmap %x, va %x, ptste %x, ptpmap %x, flags %x", + pv->pv_pmap, pv->pv_va, pv->pv_ptste, pv->pv_ptpmap, + pv->pv_flags); + printf("\n"); +} + +/* static */ +void +pmap_check_wiring(str, va) + char *str; + vm_offset_t va; +{ + struct vm_map_entry *entry; + register int count; + register pt_entry_t *pte; + + va = trunc_page(va); + if (!pmap_ste_v(pmap_kernel(), va) || + !pmap_pte_v(pmap_pte(pmap_kernel(), va))) + return; + if (!uvm_map_lookup_entry(pt_map, va, &entry)) { + printf("wired_check: entry for %lx not found\n", va); + return; + } + count = 0; + for (pte = (pt_entry_t *)va; pte < (pt_entry_t *)(va + NBPG); pte++) + if (*pte) + count++; + if (entry->wired_count != count) + printf("*%s*: %x: w%d/a%d\n", + str, va, entry->wired_count, count); +} +#endif + +void +pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot) +{ + pmap_enter(pmap_kernel(), va, pa, prot, VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED); +} + +void +pmap_kremove(vaddr_t va, vsize_t len) +{ + for (len >>= PAGE_SHIFT; len > 0; len--, va += PAGE_SIZE) { + pmap_remove(pmap_kernel(), va, va + PAGE_SIZE); + } +} diff --git a/sys/arch/mvme68k/mvme68k/pmap_bootstrap.c b/sys/arch/mvme68k/mvme68k/pmap_bootstrap.c index 1bdeb80b05c..1f30a142fa4 100644 --- a/sys/arch/mvme68k/mvme68k/pmap_bootstrap.c +++ b/sys/arch/mvme68k/mvme68k/pmap_bootstrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pmap_bootstrap.c,v 1.11 2001/12/14 21:44:05 miod Exp $ */ +/* $OpenBSD: pmap_bootstrap.c,v 1.12 2001/12/20 19:02:29 miod Exp $ */ /* * Copyright (c) 1995 Theo de Raadt @@ -91,6 +91,7 @@ extern pt_entry_t *Sysptmap, *Sysmap; extern int maxmem, physmem; extern vm_offset_t avail_start, avail_end, virtual_avail, virtual_end; extern vm_size_t mem_size; +extern int protection_codes[]; /* * Special purpose kernel virtual addresses, used for mapping @@ -399,6 +400,25 @@ register vm_offset_t firstpa; RELOC(virtual_end, vm_offset_t) = VM_MAX_KERNEL_ADDRESS; /* + * Initialize protection array. + * XXX don't use a switch statement, it might produce an + * absolute "jmp" table. + */ + { + register int *kp; + + kp = &RELOC(protection_codes, int); + kp[VM_PROT_NONE|VM_PROT_NONE|VM_PROT_NONE] = 0; + kp[VM_PROT_READ|VM_PROT_NONE|VM_PROT_NONE] = PG_RO; + kp[VM_PROT_READ|VM_PROT_NONE|VM_PROT_EXECUTE] = PG_RO; + kp[VM_PROT_NONE|VM_PROT_NONE|VM_PROT_EXECUTE] = PG_RO; + kp[VM_PROT_NONE|VM_PROT_WRITE|VM_PROT_NONE] = PG_RW; + kp[VM_PROT_NONE|VM_PROT_WRITE|VM_PROT_EXECUTE] = PG_RW; + kp[VM_PROT_READ|VM_PROT_WRITE|VM_PROT_NONE] = PG_RW; + kp[VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE] = PG_RW; + } + + /* * Kernel page/segment table allocated in locore, * just initialize pointers. */ @@ -803,6 +823,25 @@ register vm_offset_t firstpa; RELOC(virtual_end, vm_offset_t) = VM_MAX_KERNEL_ADDRESS; /* + * Initialize protection array. + * XXX don't use a switch statement, it might produce an + * absolute "jmp" table. + */ + { + register int *kp; + + kp = &RELOC(protection_codes, int); + kp[VM_PROT_NONE|VM_PROT_NONE|VM_PROT_NONE] = 0; + kp[VM_PROT_READ|VM_PROT_NONE|VM_PROT_NONE] = PG_RO; + kp[VM_PROT_READ|VM_PROT_NONE|VM_PROT_EXECUTE] = PG_RO; + kp[VM_PROT_NONE|VM_PROT_NONE|VM_PROT_EXECUTE] = PG_RO; + kp[VM_PROT_NONE|VM_PROT_WRITE|VM_PROT_NONE] = PG_RW; + kp[VM_PROT_NONE|VM_PROT_WRITE|VM_PROT_EXECUTE] = PG_RW; + kp[VM_PROT_READ|VM_PROT_WRITE|VM_PROT_NONE] = PG_RW; + kp[VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE] = PG_RW; + } + + /* * Kernel page/segment table allocated in locore, * just initialize pointers. */ @@ -856,22 +895,3 @@ register vm_offset_t firstpa; RELOC(virtual_avail, vm_offset_t) = va; } } - -void -pmap_init_md() -{ - vaddr_t addr; - - /* - * mark as unavailable the regions which we have mapped in - * pmap_bootstrap(). - */ - addr = (vaddr_t) intiobase; - if (uvm_map(kernel_map, &addr, - m68k_ptob(iiomapsize+EIOMAPSIZE), - NULL, UVM_UNKNOWN_OFFSET, 0, - UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, - UVM_INH_NONE, UVM_ADV_RANDOM, - UVM_FLAG_FIXED))) - panic("pmap_init: bogons in the VM system!\n"); -} |