diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc index 8581a986efa1..ed52bcb20ab2 100644 --- a/sys/conf/files.powerpc +++ b/sys/conf/files.powerpc @@ -91,6 +91,7 @@ libkern/ucmpdi2.c standard libkern/udivdi3.c standard libkern/umoddi3.c standard +powerpc/powerpc/mem.c optional mem powerpc/powerpc/mp_machdep.c optional smp powerpc/ofw/ofw_pci.c optional pci diff --git a/sys/powerpc/aim/mmu_oea.c b/sys/powerpc/aim/mmu_oea.c index 62bdcec898fc..08d727559612 100644 --- a/sys/powerpc/aim/mmu_oea.c +++ b/sys/powerpc/aim/mmu_oea.c @@ -2308,6 +2308,22 @@ pmap_bat_mapped(int idx, vm_offset_t pa, vm_size_t size) return (0); } +int +pmap_dev_direct_mapped(vm_offset_t pa, vm_size_t size) +{ + int i; + + /* + * This currently does not work for entries that + * overlap 256M BAT segments. + */ + + for(i = 0; i < 16; i++) + if (pmap_bat_mapped(i, pa, size) == 0) + return (0); + + return (EFAULT); +} /* * Map a set of physical memory pages into the kernel virtual diff --git a/sys/powerpc/aim/ofw_machdep.c b/sys/powerpc/aim/ofw_machdep.c index 15b04a00e73d..c00ca8695d7b 100644 --- a/sys/powerpc/aim/ofw_machdep.c +++ b/sys/powerpc/aim/ofw_machdep.c @@ -242,3 +242,16 @@ OF_getetheraddr(device_t dev, u_char *addr) node = ofw_pci_find_node(dev); OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); } + +int +mem_valid(vm_offset_t addr, int len) +{ + int i; + + for (i = 0; i < OFMEM_REGIONS; i++) + if ((addr >= OFmem[i].mr_start) + && (addr + len < OFmem[i].mr_start + OFmem[i].mr_size)) + return (0); + + return (EFAULT); +} diff --git a/sys/powerpc/conf/GENERIC b/sys/powerpc/conf/GENERIC index e89b1db62237..bbd5ca35621b 100644 --- a/sys/powerpc/conf/GENERIC +++ b/sys/powerpc/conf/GENERIC @@ -103,6 +103,7 @@ device fxp # Intel EtherExpress PRO/100B (82557, 82558) # Pseudo devices. device loop # Network loopback +device mem # Memory and kernel memory devices device random # Entropy device device ether # Ethernet support device sl # Kernel SLIP diff --git a/sys/powerpc/include/memdev.h b/sys/powerpc/include/memdev.h new file mode 100644 index 000000000000..69072d9889ca --- /dev/null +++ b/sys/powerpc/include/memdev.h @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2004 Mark R V Murray + * 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 + * in this position and unchanged. + * 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 AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#define CDEV_MAJOR 2 +#define CDEV_MINOR_MEM 0 +#define CDEV_MINOR_KMEM 1 + +d_open_t memopen; +d_read_t memrw; +#define memioctl (d_ioctl_t *)NULL +d_mmap_t memmmap; + +void dev_mem_md_init(void); + +MALLOC_DECLARE(M_MEMDEV); diff --git a/sys/powerpc/include/ofw_machdep.h b/sys/powerpc/include/ofw_machdep.h index 35b09b94f925..7f3aa0ea1638 100644 --- a/sys/powerpc/include/ofw_machdep.h +++ b/sys/powerpc/include/ofw_machdep.h @@ -31,5 +31,6 @@ #include void OF_getetheraddr(device_t dev, u_char *addr); +int mem_valid(vm_offset_t addr, int len); #endif /* _MACHINE_OFW_MACHDEP_H_ */ diff --git a/sys/powerpc/include/pmap.h b/sys/powerpc/include/pmap.h index d9013a98c7ed..16fc5c653711 100644 --- a/sys/powerpc/include/pmap.h +++ b/sys/powerpc/include/pmap.h @@ -82,6 +82,8 @@ 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); + #define vtophys(va) pmap_kextract(((vm_offset_t)(va))) extern vm_offset_t phys_avail[]; diff --git a/sys/powerpc/powerpc/mem.c b/sys/powerpc/powerpc/mem.c new file mode 100644 index 000000000000..c7f3020551e1 --- /dev/null +++ b/sys/powerpc/powerpc/mem.c @@ -0,0 +1,182 @@ +/*- + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department, and code derived from software contributed to + * Berkeley by William Jolitz. + * + * 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: Utah $Hdr: mem.c 1.13 89/10/08$ + * from: @(#)mem.c 7.2 (Berkeley) 5/9/91 + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Memory special file + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +struct mem_range_softc mem_range_softc; + +/* ARGSUSED */ +int +memrw(struct cdev *dev, struct uio *uio, int flags) +{ + struct iovec *iov; + int error = 0; + vm_offset_t va, eva, off, v; + vm_prot_t prot; + vm_size_t cnt; + + cnt = 0; + error = 0; + + GIANT_REQUIRED; + + while (uio->uio_resid > 0 && !error) { + iov = uio->uio_iov; + if (iov->iov_len == 0) { + uio->uio_iov++; + uio->uio_iovcnt--; + if (uio->uio_iovcnt < 0) + panic("memrw"); + continue; + } + if (minor(dev) == CDEV_MINOR_MEM) { +kmem_direct_mapped: v = uio->uio_offset; + + off = uio->uio_offset & PAGE_MASK; + cnt = PAGE_SIZE - ((vm_offset_t)iov->iov_base & + PAGE_MASK); + cnt = min(cnt, PAGE_SIZE - off); + cnt = min(cnt, iov->iov_len); + + if (mem_valid(v, cnt) + && pmap_dev_direct_mapped(v, cnt)) { + error = EFAULT; + break; + } + + uiomove((void *)v, cnt, uio); + break; + } + else if (minor(dev) == CDEV_MINOR_KMEM) { + va = uio->uio_offset; + + if ((va < VM_MIN_KERNEL_ADDRESS) + || (va > VM_MAX_KERNEL_ADDRESS)) + goto kmem_direct_mapped; + + va = trunc_page(uio->uio_offset); + eva = round_page(uio->uio_offset + + iov->iov_len); + + /* + * Make sure that all the pages are currently resident + * so that we don't create any zero-fill pages. + */ + + for (; va < eva; va += PAGE_SIZE) + if (pmap_extract(kernel_pmap, va) + == 0) + return (EFAULT); + + prot = (uio->uio_rw == UIO_READ) + ? VM_PROT_READ : VM_PROT_WRITE; + + va = uio->uio_offset; + if (kernacc((void *) va, iov->iov_len, prot) + == FALSE) + return (EFAULT); + + error = uiomove((void *)va, iov->iov_len, uio); + + continue; + } + } + + return (error); +} + +/* + * allow user processes to MMAP some memory sections + * instead of going through read/write + */ +int +memmmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int prot) +{ + /* + * /dev/mem is the only one that makes sense through this + * interface. For /dev/kmem any physaddr we return here + * could be transient and hence incorrect or invalid at + * a later time. + */ + if (minor(dev) != CDEV_MINOR_MEM) + return (-1); + + /* Only direct-mapped addresses. */ + if (mem_valid(offset, 0) + && pmap_dev_direct_mapped(offset, 0)) + return (EFAULT); + + *paddr = offset; + + return (0); +} + +void +dev_mem_md_init(void) +{ +} diff --git a/sys/powerpc/powerpc/mmu_oea.c b/sys/powerpc/powerpc/mmu_oea.c index 62bdcec898fc..08d727559612 100644 --- a/sys/powerpc/powerpc/mmu_oea.c +++ b/sys/powerpc/powerpc/mmu_oea.c @@ -2308,6 +2308,22 @@ pmap_bat_mapped(int idx, vm_offset_t pa, vm_size_t size) return (0); } +int +pmap_dev_direct_mapped(vm_offset_t pa, vm_size_t size) +{ + int i; + + /* + * This currently does not work for entries that + * overlap 256M BAT segments. + */ + + for(i = 0; i < 16; i++) + if (pmap_bat_mapped(i, pa, size) == 0) + return (0); + + return (EFAULT); +} /* * Map a set of physical memory pages into the kernel virtual diff --git a/sys/powerpc/powerpc/ofw_machdep.c b/sys/powerpc/powerpc/ofw_machdep.c index 15b04a00e73d..c00ca8695d7b 100644 --- a/sys/powerpc/powerpc/ofw_machdep.c +++ b/sys/powerpc/powerpc/ofw_machdep.c @@ -242,3 +242,16 @@ OF_getetheraddr(device_t dev, u_char *addr) node = ofw_pci_find_node(dev); OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); } + +int +mem_valid(vm_offset_t addr, int len) +{ + int i; + + for (i = 0; i < OFMEM_REGIONS; i++) + if ((addr >= OFmem[i].mr_start) + && (addr + len < OFmem[i].mr_start + OFmem[i].mr_size)) + return (0); + + return (EFAULT); +} diff --git a/sys/powerpc/powerpc/pmap.c b/sys/powerpc/powerpc/pmap.c index 62bdcec898fc..08d727559612 100644 --- a/sys/powerpc/powerpc/pmap.c +++ b/sys/powerpc/powerpc/pmap.c @@ -2308,6 +2308,22 @@ pmap_bat_mapped(int idx, vm_offset_t pa, vm_size_t size) return (0); } +int +pmap_dev_direct_mapped(vm_offset_t pa, vm_size_t size) +{ + int i; + + /* + * This currently does not work for entries that + * overlap 256M BAT segments. + */ + + for(i = 0; i < 16; i++) + if (pmap_bat_mapped(i, pa, size) == 0) + return (0); + + return (EFAULT); +} /* * Map a set of physical memory pages into the kernel virtual