diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 2002-03-25 19:41:53 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 2002-03-25 19:41:53 +0000 |
commit | dfe9e355fa24ab89bea2422ed30adbb14a9f346a (patch) | |
tree | b05d47dcf1be2340fd308ab17bc52a517e62d5f0 | |
parent | 524ea1ff688b62505f9eca4883805f4d96e1d82c (diff) |
revert the pmap stuff to 0221, so we can boot
-rw-r--r-- | sys/arch/amiga/amiga/amiga_init.c | 13 | ||||
-rw-r--r-- | sys/arch/amiga/amiga/locore.s | 93 | ||||
-rw-r--r-- | sys/arch/amiga/amiga/pmap.c | 2586 | ||||
-rw-r--r-- | sys/arch/amiga/amiga/pmap_bootstrap.c | 248 | ||||
-rw-r--r-- | sys/arch/amiga/conf/files.amiga | 5 | ||||
-rw-r--r-- | sys/arch/amiga/include/cpu.h | 4 | ||||
-rw-r--r-- | sys/arch/amiga/include/param.h | 11 | ||||
-rw-r--r-- | sys/arch/amiga/include/pmap.h | 141 | ||||
-rw-r--r-- | sys/arch/amiga/include/pte.h | 89 |
9 files changed, 2913 insertions, 277 deletions
diff --git a/sys/arch/amiga/amiga/amiga_init.c b/sys/arch/amiga/amiga/amiga_init.c index 0b6ceb42fd6..055ec6a2649 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.27 2002/03/14 03:15:51 millert Exp $ */ +/* $OpenBSD: amiga_init.c,v 1.28 2002/03/25 19:41:03 niklas 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; @@ -580,7 +585,9 @@ start_c(id, fphystart, fphysize, cphysize, esym_addr, flags, inh_sync) for (; i < vstart; i += NBPG, pg_proto += NBPG) *pg++ = pg_proto; - pg_proto = (pg_proto & ~PG_CI) | PG_CCB; + pg_proto = (pg_proto & ~PG_CI); + 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 470ff38b540..86912aec29a 100644 --- a/sys/arch/amiga/amiga/locore.s +++ b/sys/arch/amiga/amiga/locore.s @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.s,v 1.39 2002/02/23 00:31:09 miod Exp $ */ +/* $OpenBSD: locore.s,v 1.40 2002/03/25 19:41:03 niklas Exp $ */ /* $NetBSD: locore.s,v 1.89 1997/07/17 16:22:54 is Exp $ */ /* @@ -1249,7 +1249,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 @@ -1303,7 +1303,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 @@ -1357,7 +1357,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 @@ -1392,12 +1392,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..bc48d49d47c --- /dev/null +++ b/sys/arch/amiga/amiga/pmap.c @@ -0,0 +1,2586 @@ +/* $OpenBSD: pmap.c,v 1.48 2002/03/25 19:41:52 niklas 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()\n"); +#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 c976bd95f61..00000000000 --- a/sys/arch/amiga/amiga/pmap_bootstrap.c +++ /dev/null @@ -1,248 +0,0 @@ -/* $OpenBSD: pmap_bootstrap.c,v 1.5 2002/03/14 01:26:28 millert 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(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 fb267fd3d4b..b88c91a9948 100644 --- a/sys/arch/amiga/conf/files.amiga +++ b/sys/arch/amiga/conf/files.amiga @@ -1,4 +1,4 @@ -# $OpenBSD: files.amiga,v 1.48 2002/02/23 00:31:11 miod Exp $ +# $OpenBSD: files.amiga,v 1.49 2002/03/25 19:41:03 niklas 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 593ae380243..6683ebdf766 100644 --- a/sys/arch/amiga/include/cpu.h +++ b/sys/arch/amiga/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.19 2002/03/14 01:26:29 millert Exp $ */ +/* $OpenBSD: cpu.h,v 1.20 2002/03/25 19:41:03 niklas 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(vm_offset_t); void doboot(void) __attribute__((__noreturn__)); void loadustp(int); void m68881_save(struct fpframe *); void m68881_restore(struct fpframe *); +void physcopyseg(vm_offset_t, vm_offset_t); u_int probeva(u_int, u_int); void proc_trampoline(void); void savectx(struct pcb *); diff --git a/sys/arch/amiga/include/param.h b/sys/arch/amiga/include/param.h index d8b14cda588..17d7df92519 100644 --- a/sys/arch/amiga/include/param.h +++ b/sys/arch/amiga/include/param.h @@ -1,4 +1,4 @@ -/* $OpenBSD: param.h,v 1.21 2002/03/14 01:26:29 millert Exp $ */ +/* $OpenBSD: param.h,v 1.22 2002/03/25 19:41:03 niklas 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 f2db397362d..29c519d04e0 100644 --- a/sys/arch/amiga/include/pmap.h +++ b/sys/arch/amiga/include/pmap.h @@ -1,13 +1,142 @@ -/* $OpenBSD: pmap.h,v 1.13 2002/03/14 01:26:29 millert Exp $ */ +/* $OpenBSD: pmap.h,v 1.14 2002/03/25 19:41:03 niklas 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(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 fbde5180950..f1396694259 100644 --- a/sys/arch/amiga/include/pte.h +++ b/sys/arch/amiga/include/pte.h @@ -1,4 +1,5 @@ -/* $OpenBSD: pte.h,v 1.6 2002/02/23 00:31:11 miod Exp $ */ +/* $OpenBSD: pte.h,v 1.7 2002/03/25 19:41:03 niklas Exp $ */ +/* $NetBSD: pte.h,v 1.14 1995/09/29 13:52:09 chopps Exp $ */ /* * Copyright (c) 1988 University of Utah. @@ -44,8 +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 @@ -60,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 \ @@ -72,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_ */ +#endif /* !_MACHINE_PTE_H_ */ |