diff options
author | grehan <grehan@FreeBSD.org> | 2005-11-08 06:48:08 +0000 |
---|---|---|
committer | grehan <grehan@FreeBSD.org> | 2005-11-08 06:48:08 +0000 |
commit | eff5b98fc40055bf85d38836cdcfebf6486cf0d2 (patch) | |
tree | c090032365f12df1f06212e900d4fe33ca492b60 /sys/powerpc | |
parent | bf6d4253ee61e7325d3cd61086924ae203e9726c (diff) | |
download | FreeBSD-src-eff5b98fc40055bf85d38836cdcfebf6486cf0d2.zip FreeBSD-src-eff5b98fc40055bf85d38836cdcfebf6486cf0d2.tar.gz |
Insert a layer of indirection to the pmap code, using a kobj for
the interface. This allows run-time selection of MMU code, based
on CPU-type detection, or tunable-overrides when testing new code.
Pre-requisite for G5 support.
conf/files.powerpc
- remove pmap.c
- add mmu_if.h, mmu_oea.c, pmap_dispatch.c
powerpc/include/mmuvar.h
- definitions for MMU implementations
powerpc/include/pmap.h
- remove pmap_pte_spill declaration
- add pmap_mmu_install declaration
- size the phys_avail array
- pmap_bootstrapped is now global-scope
powerpc/powerpc/machdep.c
- call kobj_machdep_init early in the boot sequence to allow
kobj usage prior to SI_SUB_LOCK
- install the OEA pmap code. This will be moved to CPU-specific
init code in the future.
powerpc/powerpc/mmu_if.m
- Kobj MMU interface definitions
powerpc/powerpc/pmap_dispatch.c
- central dispatch for pmap calls
- contains the global mmu kobj and the routine to locate the
the mmu implementation and init the kobj
Diffstat (limited to 'sys/powerpc')
-rw-r--r-- | sys/powerpc/aim/machdep.c | 4 | ||||
-rw-r--r-- | sys/powerpc/include/mmuvar.h | 96 | ||||
-rw-r--r-- | sys/powerpc/include/pmap.h | 10 | ||||
-rw-r--r-- | sys/powerpc/powerpc/machdep.c | 4 | ||||
-rw-r--r-- | sys/powerpc/powerpc/mmu_if.m | 758 | ||||
-rw-r--r-- | sys/powerpc/powerpc/pmap_dispatch.c | 380 |
6 files changed, 1248 insertions, 4 deletions
diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index d27d48f..e7d28b6 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -110,6 +110,7 @@ __FBSDID("$FreeBSD$"); #include <machine/fpu.h> #include <machine/md_var.h> #include <machine/metadata.h> +#include <machine/mmuvar.h> #include <machine/pcb.h> #include <machine/powerpc.h> #include <machine/reg.h> @@ -317,6 +318,8 @@ powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp) kdb_init(); + kobj_machdep_init(); + /* * XXX: Initialize the interrupt tables. * Disable translation in case the vector area @@ -358,6 +361,7 @@ powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp) /* * Initialise virtual memory. */ + pmap_mmu_install(MMU_TYPE_OEA, 0); /* XXX temporary */ pmap_bootstrap(startkernel, endkernel); /* diff --git a/sys/powerpc/include/mmuvar.h b/sys/powerpc/include/mmuvar.h new file mode 100644 index 0000000..fc2f8d5 --- /dev/null +++ b/sys/powerpc/include/mmuvar.h @@ -0,0 +1,96 @@ +/*- + * Copyright (c) 2005 Peter Grehan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_MMUVAR_H_ +#define _MACHINE_MMUVAR_H_ + +/* + * A PowerPC MMU implementation is declared with a kernel object and + * an associated method table, similar to a device driver. + * + * e.g. + * + * static mmu_method_t ppc8xx_methods[] = { + * MMUMETHOD(mmu_change_wiring, ppc8xx_mmu_change_wiring), + * MMUMETHOD(mmu_clear_modify, ppc8xx_mmu_clear_modify), + * MMUMETHOD(mmu_clear_reference, ppc8xx_mmu_clear_reference), + * ... + * MMUMETHOD(mmu_dev_direct_mapped, ppc8xx_mmu_dev_direct_mapped), + * { 0, 0 } + * }; + * + * static mmu_def_t ppc8xx_mmu = { + * "ppc8xx", + * ppc8xx_methods, + * sizeof(ppc8xx_mmu_softc), // or 0 if no softc + * }; + * + * MMU_DEF(ppc8xx_mmu); + */ + +#include <sys/kobj.h> + +struct mmu_kobj { + /* + * An MMU instance is a kernel object + */ + KOBJ_FIELDS; + + /* + * Utility elements that an instance may use + */ + struct mtx mmu_mtx; /* available for instance use */ + void *mmu_iptr; /* instance data pointer */ + + /* + * Opaque data that can be overlaid with an instance-private + * structure. MMU code can test that this is large enough at + * compile time with a sizeof() test againt it's softc. There + * is also a run-time test when the MMU kernel object is + * registered. + */ +#define MMU_OPAQUESZ 64 + u_int mmu_opaque[MMU_OPAQUESZ]; +}; + +typedef struct mmu_kobj *mmu_t; +typedef struct kobj_class mmu_def_t; +#define mmu_method_t kobj_method_t + +#define MMUMETHOD KOBJMETHOD + +#define MMU_DEF(name) DATA_SET(mmu_set, name) + +/* + * Known MMU names + */ +#define MMU_TYPE_OEA "mmu_oea" /* 32-bit OEA */ +#define MMU_TYPE_G5 "mmu_g5" /* 64-bit bridge (ibm 970) */ +#define MMU_TYPE_8xx "mmu_8xx" /* 8xx quicc TLB */ + +#endif /* _MACHINE_MMUVAR_H_ */ diff --git a/sys/powerpc/include/pmap.h b/sys/powerpc/include/pmap.h index e28042c..57c6f61 100644 --- a/sys/powerpc/include/pmap.h +++ b/sys/powerpc/include/pmap.h @@ -94,19 +94,21 @@ void *pmap_mapdev(vm_offset_t, vm_size_t); void pmap_unmapdev(vm_offset_t, vm_size_t); void pmap_deactivate(struct thread *); vm_offset_t pmap_kextract(vm_offset_t); - -int pmap_pte_spill(vm_offset_t); - int pmap_dev_direct_mapped(vm_offset_t, vm_size_t); +boolean_t pmap_mmu_install(char *name, int prio); + #define vtophys(va) pmap_kextract(((vm_offset_t)(va))) -extern vm_offset_t phys_avail[]; +#define PHYS_AVAIL_SZ 128 +extern vm_offset_t phys_avail[PHYS_AVAIL_SZ]; extern vm_offset_t virtual_avail; extern vm_offset_t virtual_end; extern vm_offset_t msgbuf_phys; +extern int pmap_bootstrapped; + #endif #endif /* !_MACHINE_PMAP_H_ */ diff --git a/sys/powerpc/powerpc/machdep.c b/sys/powerpc/powerpc/machdep.c index d27d48f..e7d28b6 100644 --- a/sys/powerpc/powerpc/machdep.c +++ b/sys/powerpc/powerpc/machdep.c @@ -110,6 +110,7 @@ __FBSDID("$FreeBSD$"); #include <machine/fpu.h> #include <machine/md_var.h> #include <machine/metadata.h> +#include <machine/mmuvar.h> #include <machine/pcb.h> #include <machine/powerpc.h> #include <machine/reg.h> @@ -317,6 +318,8 @@ powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp) kdb_init(); + kobj_machdep_init(); + /* * XXX: Initialize the interrupt tables. * Disable translation in case the vector area @@ -358,6 +361,7 @@ powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp) /* * Initialise virtual memory. */ + pmap_mmu_install(MMU_TYPE_OEA, 0); /* XXX temporary */ pmap_bootstrap(startkernel, endkernel); /* diff --git a/sys/powerpc/powerpc/mmu_if.m b/sys/powerpc/powerpc/mmu_if.m new file mode 100644 index 0000000..f816d49 --- /dev/null +++ b/sys/powerpc/powerpc/mmu_if.m @@ -0,0 +1,758 @@ +#- +# Copyright (c) 2005 Peter Grehan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +# +# $FreeBSD$ +# + +#include <sys/param.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/systm.h> + +#include <vm/vm.h> +#include <vm/vm_page.h> + +#include <machine/mmuvar.h> + +/** + * @defgroup MMU mmu - KObj methods for PowerPC MMU implementations + * @brief A set of methods required by all MMU implementations. These + * are basically direct call-thru's from the pmap machine-dependent + * code. + * Thanks to Bruce M Simpson's pmap man pages for routine descriptions. + *@{ + */ + +INTERFACE mmu; + +# +# Default implementations of some methods +# +CODE { + static void mmu_null_copy(mmu_t mmu, pmap_t dst_pmap, pmap_t src_pmap, + vm_offset_t dst_addr, vm_size_t len, vm_offset_t src_addr) + { + return; + } + + static void mmu_null_growkernel(mmu_t mmu, vm_offset_t addr) + { + return; + } + + static void mmu_null_init(mmu_t mmu) + { + return; + } + + static void mmu_null_init2(mmu_t mmu) + { + return; + } + + static boolean_t mmu_null_is_prefaultable(mmu_t mmu, pmap_t pmap, + vm_offset_t va) + { + return (FALSE); + } + + static void mmu_null_object_init_pt(mmu_t mmu, pmap_t pmap, + vm_offset_t addr, vm_object_t object, vm_pindex_t index, + vm_size_t size) + { + return; + } + + static void mmu_null_page_init(mmu_t mmu, vm_page_t m) + { + return; + } + + static void mmu_null_remove_pages(mmu_t mmu, pmap_t pmap, + vm_offset_t start, vm_offset_t end) + { + return; + } + + static int mmu_null_mincore(mmu_t mmu, pmap_t pmap, vm_offset_t addr) + { + return (0); + } + + static void mmu_null_deactivate(struct thread *td) + { + return; + } + + static vm_offset_t mmu_null_addr_hint(mmu_t mmu, vm_object_t object, + vm_offset_t va, vm_size_t size) + { + return (va); + } +}; + + +/** + * @brief Change the wiring attribute for the page in the given physical + * map and virtual address. + * + * @param _pmap physical map of page + * @param _va page virtual address + * @param _wired TRUE to increment wired count, FALSE to decrement + */ +METHOD void change_wiring { + mmu_t _mmu; + pmap_t _pmap; + vm_offset_t _va; + boolean_t _wired; +}; + + +/** + * @brief Clear the 'modified' bit on the given physical page + * + * @param _pg physical page + */ +METHOD void clear_modify { + mmu_t _mmu; + vm_page_t _pg; +}; + + +/** + * @brief Clear the 'referenced' bit on the given physical page + * + * @param _pg physical page + */ +METHOD void clear_reference { + mmu_t _mmu; + vm_page_t _pg; +}; + + +/** + * @brief Copy the address range given by the source physical map, virtual + * address and length to the destination physical map and virtual address. + * This routine is optional (xxx default null implementation ?) + * + * @param _dst_pmap destination physical map + * @param _src_pmap source physical map + * @param _dst_addr destination virtual address + * @param _len size of range + * @param _src_addr source virtual address + */ +METHOD void copy { + mmu_t _mmu; + pmap_t _dst_pmap; + pmap_t _src_pmap; + vm_offset_t _dst_addr; + vm_size_t _len; + vm_offset_t _src_addr; +} DEFAULT mmu_null_copy; + + +/** + * @brief Copy the source physical page to the destination physical page + * + * @param _src source physical page + * @param _dst destination physical page + */ +METHOD void copy_page { + mmu_t _mmu; + vm_page_t _src; + vm_page_t _dst; +}; + + +/** + * @brief Create a mapping between a virtual/physical address pair in the + * passed physical map with the specified protection and wiring + * + * @param _pmap physical map + * @param _va mapping virtual address + * @param _p mapping physical page + * @param _prot mapping page protection + * @param _wired TRUE if page will be wired + */ +METHOD void enter { + mmu_t _mmu; + pmap_t _pmap; + vm_offset_t _va; + vm_page_t _p; + vm_prot_t _prot; + boolean_t _wired; +}; + + +/** + * @brief A faster entry point for page mapping where it is possible + * to short-circuit some of the tests in pmap_enter. + * + * @param _pmap physical map (and also currently active pmap) + * @param _va mapping virtual address + * @param _pg mapping physical page + * @param _prot new page protection - used to see if page is exec. + * @param _mpte ??? + * + * @retval NULL (possibly a hint for future calls ?) + */ +METHOD vm_page_t enter_quick { + mmu_t _mmu; + pmap_t _pmap; + vm_offset_t _va; + vm_page_t _pg; + vm_prot_t _prot; + vm_page_t _mpte; +}; + + +/** + * @brief Reverse map the given virtual address, returning the physical + * page associated with the address if a mapping exists. + * + * @param _pmap physical map + * @param _va mapping virtual address + * + * @retval 0 No mapping found + * @retval addr The mapping physical address + */ +METHOD vm_paddr_t extract { + mmu_t _mmu; + pmap_t _pmap; + vm_offset_t _va; +}; + + +/** + * @brief Reverse map the given virtual address, returning the + * physical page if found. The page must be held (by calling + * vm_page_hold) if the page protection matches the given protection + * + * @param _pmap physical map + * @param _va mapping virtual address + * @param _prot protection used to determine if physical page + * should be locked + * + * @retval NULL No mapping found + * @retval page Pointer to physical page. Held if protections match + */ +METHOD vm_page_t extract_and_hold { + mmu_t _mmu; + pmap_t _pmap; + vm_offset_t _va; + vm_prot_t _prot; +}; + + +/** + * @brief Increase kernel virtual address space to the given virtual address. + * Not really required for PowerPC, so optional unless the MMU implementation + * can use it. + * + * @param _va new upper limit for kernel virtual address space + */ +METHOD void growkernel { + mmu_t _mmu; + vm_offset_t _va; +} DEFAULT mmu_null_growkernel; + + +/** + * @brief Called from vm_mem_init. Zone allocation is available at + * this stage so a convenient time to create zones. This routine is + * for MMU-implementation convenience and is optional. + */ +METHOD void init { + mmu_t _mmu; +} DEFAULT mmu_null_init; + + +/** + * @brief Called from vm_init2/proc0_init, so can be used as a last-chance + * init before process scheduling starts. This routine is optional. + */ +METHOD void init2 { + mmu_t _mmu; +} DEFAULT mmu_null_init2; + + +/** + * @brief Return if the page has been marked by MMU hardware to have been + * modified + * + * @param _pg physical page to test + * + * @retval boolean TRUE if page has been modified + */ +METHOD boolean_t is_modified { + mmu_t _mmu; + vm_page_t _pg; +}; + + +/** + * @brief Return whether the specified virtual address is a candidate to be + * prefaulted in. This routine is optional. + * + * @param _pmap physical map + * @param _va virtual address to test + * + * @retval boolean TRUE if the address is a candidate. + */ +METHOD boolean_t is_prefaultable { + mmu_t _mmu; + pmap_t _pmap; + vm_offset_t _va; +} DEFAULT mmu_null_is_prefaultable; + + +/** + * @brief Return a count of referenced bits for a page, clearing those bits. + * Not all referenced bits need to be cleared, but it is necessary that 0 + * only be returned when there are none set. + * + * @params _m physical page + * + * @retval int count of referenced bits + */ +METHOD boolean_t ts_referenced { + mmu_t _mmu; + vm_page_t _pg; +}; + + +/** + * @brief Map the requested physical address range into kernel virtual + * address space. The value in _virt is taken as a hint. The virtual + * address of the range is returned, or NULL if the mapping could not + * be created. The range can be direct-mapped if that is supported. + * + * @param *_virt Hint for start virtual address, and also return + * value + * @param _start physical address range start + * @param _end physical address range end + * @param _prot protection of range (currently ignored) + * + * @retval NULL could not map the area + * @retval addr, *_virt mapping start virtual address + */ +METHOD vm_offset_t map { + mmu_t _mmu; + vm_offset_t *_virt; + vm_paddr_t _start; + vm_paddr_t _end; + int _prot; +}; + + +/** + * @brief Used to create a contiguous set of read-only mappings for a + * given object to try and eliminate a cascade of on-demand faults as + * the object is accessed sequentially. This routine is optional. + * + * @param _pmap physical map + * @param _addr mapping start virtual address + * @param _object device-backed V.M. object to be mapped + * @param _pindex page-index within object of mapping start + * @param _size size in bytes of mapping + */ +METHOD void object_init_pt { + mmu_t _mmu; + pmap_t _pmap; + vm_offset_t _addr; + vm_object_t _object; + vm_pindex_t _pindex; + vm_size_t _size; +} DEFAULT mmu_null_object_init_pt; + + +/** + * @brief Used to determine if the specified page has a mapping for the + * given physical map, by scanning the list of reverse-mappings from the + * page. The list is scanned to a maximum of 16 entries. + * + * @param _pmap physical map + * @param _pg physical page + * + * @retval bool TRUE if the physical map was found in the first 16 + * reverse-map list entries off the physical page. + */ +METHOD boolean_t page_exists_quick { + mmu_t _mmu; + pmap_t _pmap; + vm_page_t _pg; +}; + + +/** + * @brief Initialise the machine-dependent section of the physical page + * data structure. This routine is optional. + * + * @param _pg physical page + */ +METHOD void page_init { + mmu_t _mmu; + vm_page_t _pg; +} DEFAULT mmu_null_page_init; + + +/** + * @brief Lower the protection to the given value for all mappings of the + * given physical page. + * + * @param _pg physical page + * @param _prot updated page protection + */ +METHOD void page_protect { + mmu_t _mmu; + vm_page_t _pg; + vm_prot_t _prot; +}; + + +/** + * @brief Initialise a physical map data structure + * + * @param _pmap physical map + */ +METHOD void pinit { + mmu_t _mmu; + pmap_t _pmap; +}; + + +/** + * @brief Initialise the physical map for process 0, the initial process + * in the system. + * XXX default to pinit ? + * + * @param _pmap physical map + */ +METHOD void pinit0 { + mmu_t _mmu; + pmap_t _pmap; +}; + + +/** + * @brief Set the protection for physical pages in the given virtual address + * range to the given value. + * + * @param _pmap physical map + * @param _start virtual range start + * @param _end virtual range end + * @param _prot new page protection + */ +METHOD void protect { + mmu_t _mmu; + pmap_t _pmap; + vm_offset_t _start; + vm_offset_t _end; + vm_prot_t _prot; +}; + + +/** + * @brief Create a mapping in kernel virtual address space for the given array + * of wired physical pages. + * + * @param _start mapping virtual address start + * @param *_m array of physical page pointers + * @param _count array elements + */ +METHOD void qenter { + mmu_t _mmu; + vm_offset_t _start; + vm_page_t *_pg; + int _count; +}; + + +/** + * @brief Remove the temporary mappings created by qenter. + * + * @param _start mapping virtual address start + * @param _count number of pages in mapping + */ +METHOD void qremove { + mmu_t _mmu; + vm_offset_t _start; + int _count; +}; + + +/** + * @brief Release per-pmap resources, e.g. mutexes, allocated memory etc. There + * should be no existing mappings for the physical map at this point + * + * @param _pmap physical map + */ +METHOD void release { + mmu_t _mmu; + pmap_t _pmap; +}; + + +/** + * @brief Remove all mappings in the given physical map for the start/end + * virtual address range. The range will be page-aligned. + * + * @param _pmap physical map + * @param _start mapping virtual address start + * @param _end mapping virtual address end + */ +METHOD void remove { + mmu_t _mmu; + pmap_t _pmap; + vm_offset_t _start; + vm_offset_t _end; +}; + + +/** + * @brief Traverse the reverse-map list off the given physical page and + * remove all mappings. Clear the PG_WRITEABLE attribute from the page. + * + * @param _pg physical page + */ +METHOD void remove_all { + mmu_t _mmu; + vm_page_t _pg; +}; + + +/** + * @brief Remove all mappings in the given start/end virtual address range + * for the given physical map. Similar to the remove method, but it used + * when tearing down all mappings in an address space. This method is + * optional, since pmap_remove will be called for each valid vm_map in + * the address space later. + * + * @param _pmap physical map + * @param _start mapping virtual address start + * @param _end mapping virtual address end + */ +METHOD void remove_pages { + mmu_t _mmu; + pmap_t _pmap; + vm_offset_t _start; + vm_offset_t _end; +} DEFAULT mmu_null_remove_pages; + + +/** + * @brief Zero a physical page. It is not assumed that the page is mapped, + * so a temporary (or direct) mapping may need to be used. + * + * @param _pg physical page + */ +METHOD void zero_page { + mmu_t _mmu; + vm_page_t _pg; +}; + + +/** + * @brief Zero a portion of a physical page, starting at a given offset and + * for a given size (multiples of 512 bytes for 4k pages). + * + * @param _pg physical page + * @param _off byte offset from start of page + * @param _size size of area to zero + */ +METHOD void zero_page_area { + mmu_t _mmu; + vm_page_t _pg; + int _off; + int _size; +}; + + +/** + * @brief Called from the idle loop to zero pages. XXX I think locking + * constraints might be different here compared to zero_page. + * + * @param _pg physical page + */ +METHOD void zero_page_idle { + mmu_t _mmu; + vm_page_t _pg; +}; + + +/** + * @brief Extract mincore(2) information from a mapping. This routine is + * optional and is an optimisation: the mincore code will call is_modified + * and ts_referenced if no result is returned. + * + * @param _pmap physical map + * @param _addr page virtual address + * + * @retval 0 no result + * @retval non-zero mincore(2) flag values + */ +METHOD int mincore { + mmu_t _mmu; + pmap_t _pmap; + vm_offset_t _addr; +} DEFAULT mmu_null_mincore; + + +/** + * @brief Perform any operations required to allow a physical map to be used + * before it's address space is accessed. + * + * @param _td thread associated with physical map + */ +METHOD void activate { + mmu_t _mmu; + struct thread *_td; +}; + +/** + * @brief Perform any operations required to deactivate a physical map, + * for instance as it is context-switched out. + * + * @param _td thread associated with physical map + */ +METHOD void deactivate { + mmu_t _mmu; + struct thread *_td; +} DEFAULT mmu_null_deactivate; + +/** + * @brief Return a hint for the best virtual address to map a tentative + * virtual address range in a given VM object. The default is to just + * return the given tentative start address. + * + * @param _obj VM backing object + * @param _addr initial guess at virtual address + * @param _size size of virtual address range + */ +METHOD vm_offset_t addr_hint { + mmu_t _mmu; + vm_object_t _obj; + vm_offset_t _addr; + vm_size_t _size; +} DEFAULT mmu_null_addr_hint; + + + + +/** + * INTERNAL INTERFACES + */ + +/** + * @brief Bootstrap the VM system. At the completion of this routine, the + * kernel will be running in it's own address space with full control over + * paging. + * + * @param _start start of reserved memory (obsolete ???) + * @param _end end of reserved memory (obsolete ???) + * XXX I think the intent of these was to allow + * the memory used by kernel text+data+bss and + * loader variables/load-time kld's to be carved out + * of available physical mem. + * + */ +METHOD void bootstrap { + mmu_t _mmu; + vm_offset_t _start; + vm_offset_t _end; +}; + + +/** + * @brief Create a kernel mapping for a given physical address range. + * Called by bus code on behalf of device drivers. The mapping does not + * have to be a virtual address: it can be a direct-mapped physical address + * if that is supported by the MMU. + * + * @param _pa start physical address + * @param _size size in bytes of mapping + * + * @retval addr address of mapping. + */ +METHOD void * mapdev { + mmu_t _mmu; + vm_offset_t _pa; + vm_size_t _size; +}; + + +/** + * @brief Remove the mapping created by mapdev. Called when a driver + * is unloaded. + * + * @param _va Mapping address returned from mapdev + * @param _size size in bytes of mapping + */ +METHOD void unmapdev { + mmu_t _mmu; + vm_offset_t _va; + vm_size_t _size; +}; + + +/** + * @brief Reverse-map a kernel virtual address + * + * @param _va kernel virtual address to reverse-map + * + * @retval pa physical address corresponding to mapping + */ +METHOD vm_offset_t kextract { + mmu_t _mmu; + vm_offset_t _va; +}; + + +/** + * @brief Map a wired page into kernel virtual address space + * + * @param _va mapping virtual address + * @param _pa mapping physical address + */ +METHOD void kenter { + mmu_t _mmu; + vm_offset_t _va; + vm_offset_t _pa; +}; + + +/** + * @brief Determine if the given physical address range has been direct-mapped. + * + * @param _pa physical address start + * @param _size physical address range size + * + * @retval bool TRUE if the range is direct-mapped. + */ +METHOD boolean_t dev_direct_mapped { + mmu_t _mmu; + vm_offset_t _pa; + vm_size_t _size; +}; diff --git a/sys/powerpc/powerpc/pmap_dispatch.c b/sys/powerpc/powerpc/pmap_dispatch.c new file mode 100644 index 0000000..19cb74c --- /dev/null +++ b/sys/powerpc/powerpc/pmap_dispatch.c @@ -0,0 +1,380 @@ +/*- + * Copyright (c) 2005 Peter Grehan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Dispatch MI pmap calls to the appropriate MMU implementation + * through a previously registered kernel object. + * + * Before pmap_bootstrap() can be called, a CPU module must have + * called pmap_mmu_install(). This may be called multiple times: + * the highest priority call will be installed as the default + * MMU handler when pmap_bootstrap() is called. + * + * It is required that kobj_machdep_init() be called before + * pmap_bootstrap() to allow the kobj subsystem to initialise. This + * in turn requires that mutex_init() has been called. + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/systm.h> + +#include <vm/vm.h> +#include <vm/vm_page.h> + +#include <machine/mmuvar.h> + +#include "mmu_if.h" + +static mmu_def_t *mmu_def_impl; +static mmu_t mmu_obj; +static struct mmu_kobj mmu_kernel_obj; +static struct kobj_ops mmu_kernel_kops; + +/* + * pmap globals + */ +struct pmap kernel_pmap_store; + +struct msgbuf *msgbufp; +vm_offset_t msgbuf_phys; + +vm_offset_t avail_start; +vm_offset_t avail_end; +vm_offset_t kernel_vm_end; +vm_offset_t phys_avail[PHYS_AVAIL_SZ]; +vm_offset_t virtual_avail; +vm_offset_t virtual_end; + +int pmap_pagedaemon_waken; +int pmap_bootstrapped; + +void +pmap_change_wiring(pmap_t pmap, vm_offset_t va, boolean_t wired) +{ + MMU_CHANGE_WIRING(mmu_obj, pmap, va, wired); +} + +void +pmap_clear_modify(vm_page_t m) +{ + MMU_CLEAR_MODIFY(mmu_obj, m); +} + +void +pmap_clear_reference(vm_page_t m) +{ + MMU_CLEAR_REFERENCE(mmu_obj, m); +} + +void +pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, + vm_size_t len, vm_offset_t src_addr) +{ + MMU_COPY(mmu_obj, dst_pmap, src_pmap, dst_addr, len, src_addr); +} + +void +pmap_copy_page(vm_page_t src, vm_page_t dst) +{ + MMU_COPY_PAGE(mmu_obj, src, dst); +} + +void +pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t p, vm_prot_t prot, + boolean_t wired) +{ + MMU_ENTER(mmu_obj, pmap, va, p, prot, wired); +} + +vm_page_t +pmap_enter_quick(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, + vm_page_t mpte) +{ + return (MMU_ENTER_QUICK(mmu_obj, pmap, va, m, prot, mpte)); +} + +vm_paddr_t +pmap_extract(pmap_t pmap, vm_offset_t va) +{ + return (MMU_EXTRACT(mmu_obj, pmap, va)); +} + +vm_page_t +pmap_extract_and_hold(pmap_t pmap, vm_offset_t va, vm_prot_t prot) +{ + return (MMU_EXTRACT_AND_HOLD(mmu_obj, pmap, va, prot)); +} + +void +pmap_growkernel(vm_offset_t va) +{ + MMU_GROWKERNEL(mmu_obj, va); +} + +void +pmap_init(void) +{ + MMU_INIT(mmu_obj); +} + +void +pmap_init2(void) +{ + MMU_INIT2(mmu_obj); +} + +boolean_t +pmap_is_modified(vm_page_t m) +{ + return (MMU_IS_MODIFIED(mmu_obj, m)); +} + +boolean_t +pmap_is_prefaultable(pmap_t pmap, vm_offset_t va) +{ + return (MMU_IS_PREFAULTABLE(mmu_obj, pmap, va)); +} + +boolean_t +pmap_ts_referenced(vm_page_t m) +{ + return (MMU_TS_REFERENCED(mmu_obj, m)); +} + +vm_offset_t +pmap_map(vm_offset_t *virt, vm_paddr_t start, vm_paddr_t end, int prot) +{ + return (MMU_MAP(mmu_obj, virt, start, end, prot)); +} + +void +pmap_object_init_pt(pmap_t pmap, vm_offset_t addr, vm_object_t object, + vm_pindex_t pindex, vm_size_t size) +{ + MMU_OBJECT_INIT_PT(mmu_obj, pmap, addr, object, pindex, size); +} + +boolean_t +pmap_page_exists_quick(pmap_t pmap, vm_page_t m) +{ + return (MMU_PAGE_EXISTS_QUICK(mmu_obj, pmap, m)); +} + +void +pmap_page_init(vm_page_t m) +{ + MMU_PAGE_INIT(mmu_obj, m); +} + +void +pmap_page_protect(vm_page_t m, vm_prot_t prot) +{ + MMU_PAGE_PROTECT(mmu_obj, m, prot); +} + +void +pmap_pinit(pmap_t pmap) +{ + MMU_PINIT(mmu_obj, pmap); +} + +void +pmap_pinit0(pmap_t pmap) +{ + MMU_PINIT0(mmu_obj, pmap); +} + +void +pmap_protect(pmap_t pmap, vm_offset_t start, vm_offset_t end, vm_prot_t prot) +{ + MMU_PROTECT(mmu_obj, pmap, start, end, prot); +} + +void +pmap_qenter(vm_offset_t start, vm_page_t *m, int count) +{ + MMU_QENTER(mmu_obj, start, m, count); +} + +void +pmap_qremove(vm_offset_t start, int count) +{ + MMU_QREMOVE(mmu_obj, start, count); +} + +void +pmap_release(pmap_t pmap) +{ + MMU_RELEASE(mmu_obj, pmap); +} + +void +pmap_remove(pmap_t pmap, vm_offset_t start, vm_offset_t end) +{ + MMU_REMOVE(mmu_obj, pmap, start, end); +} + +void +pmap_remove_all(vm_page_t m) +{ + MMU_REMOVE_ALL(mmu_obj, m); +} + +void +pmap_remove_pages(pmap_t pmap, vm_offset_t start, vm_offset_t end) +{ + MMU_REMOVE_PAGES(mmu_obj, pmap, start, end); +} + +void +pmap_zero_page(vm_page_t m) +{ + MMU_ZERO_PAGE(mmu_obj, m); +} + +void +pmap_zero_page_area(vm_page_t m, int off, int size) +{ + MMU_ZERO_PAGE_AREA(mmu_obj, m, off, size); +} + +void +pmap_zero_page_idle(vm_page_t m) +{ + MMU_ZERO_PAGE_IDLE(mmu_obj, m); +} + +int +pmap_mincore(pmap_t pmap, vm_offset_t addr) +{ + return (MMU_MINCORE(mmu_obj, pmap, addr)); +} + +void +pmap_activate(struct thread *td) +{ + MMU_ACTIVATE(mmu_obj, td); +} + +void +pmap_deactivate(struct thread *td) +{ + MMU_DEACTIVATE(mmu_obj, td); +} + +vm_offset_t +pmap_addr_hint(vm_object_t obj, vm_offset_t addr, vm_size_t size) +{ + return (MMU_ADDR_HINT(mmu_obj, obj, addr, size)); +} + + + +/* + * Routines used in machine-dependent code + */ +void +pmap_bootstrap(vm_offset_t start, vm_offset_t end) +{ + mmu_obj = &mmu_kernel_obj; + + /* + * Take care of compiling the selected class, and + * then statically initialise the MMU object + */ + kobj_class_compile_static(mmu_def_impl, &mmu_kernel_kops); + kobj_init((kobj_t)mmu_obj, mmu_def_impl); + + MMU_BOOTSTRAP(mmu_obj, start, end); +} + +void * +pmap_mapdev(vm_offset_t pa, vm_size_t size) +{ + return (MMU_MAPDEV(mmu_obj, pa, size)); +} + +void +pmap_unmapdev(vm_offset_t va, vm_size_t size) +{ + MMU_UNMAPDEV(mmu_obj, va, size); +} + +vm_offset_t +pmap_kextract(vm_offset_t va) +{ + return (MMU_KEXTRACT(mmu_obj, va)); +} + +void +pmap_kenter(vm_offset_t va, vm_offset_t pa) +{ + MMU_KENTER(mmu_obj, va, pa); +} + +boolean_t +pmap_dev_direct_mapped(vm_offset_t pa, vm_size_t size) +{ + return (MMU_DEV_DIRECT_MAPPED(mmu_obj, pa, size)); +} + + +/* + * MMU install routines. Highest priority wins, equal priority also + * overrides allowing last-set to win. + */ +SET_DECLARE(mmu_set, mmu_def_t); + +boolean_t +pmap_mmu_install(char *name, int prio) +{ + mmu_def_t **mmupp, *mmup; + static int curr_prio = 0; + + /* + * Try and locate the MMU kobj corresponding to the name + */ + SET_FOREACH(mmupp, mmu_set) { + mmup = *mmupp; + + if (mmup->name && + !strcmp(mmup->name, name) && + prio >= curr_prio) { + curr_prio = prio; + mmu_def_impl = mmup; + return (TRUE); + } + } + + return (FALSE); +} |