]> xenbits.xensource.com Git - people/julieng/freebsd.git/commitdiff
Add memrw. This has had minimal testing, and will likely panic the kernel
authorandrew <andrew@FreeBSD.org>
Fri, 31 Jul 2015 13:39:51 +0000 (13:39 +0000)
committerandrew <andrew@FreeBSD.org>
Fri, 31 Jul 2015 13:39:51 +0000 (13:39 +0000)
when trying to read data from outside the DMAP region. I expect this panic
to be from within uiomove_fromphys, which needs to grow support to support
such addresses.

Obtained from: ABT Systems Ltd
Sponsored by: The FreeBSD Foundation

sys/arm64/arm64/mem.c

index 373d0bf18c6ac3d323042ad606b20717b1f49468..481ef8842e922e85e5d1dd64e6758f56ca2ef252 100644 (file)
@@ -33,15 +33,84 @@ __FBSDID("$FreeBSD$");
 #include <sys/conf.h>
 #include <sys/malloc.h>
 #include <sys/memrange.h>
+#include <sys/uio.h>
 
 #include <machine/memdev.h>
+#include <machine/vmparam.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_page.h>
 
 struct mem_range_softc mem_range_softc;
 
 int
 memrw(struct cdev *dev, struct uio *uio, int flags)
 {
+       struct iovec *iov;
+       struct vm_page m;
+       vm_page_t marr;
+       vm_offset_t off, v;
+       u_int cnt;
+       int error;
+
+       error = 0;
+
+       while (uio->uio_resid > 0 && error == 0) {
+               iov = uio->uio_iov;
+               if (iov->iov_len == 0) {
+                       uio->uio_iov++;
+                       uio->uio_iovcnt--;
+                       if (uio->uio_iovcnt < 0)
+                               panic("memrw");
+                       continue;
+               }
+
+               v = uio->uio_offset;
+               off = v & PAGE_MASK;
+               cnt = ulmin(iov->iov_len, PAGE_SIZE - (u_int)off);
+               if (cnt == 0)
+                       continue;
+
+               switch(dev2unit(dev)) {
+               case CDEV_MINOR_KMEM:
+                       /* If the address is in the DMAP just copy it */
+                       if (VIRT_IN_DMAP(v)) {
+                               error = uiomove((void *)v, cnt, uio);
+                               break;
+                       }
+
+                       if (!kernacc((void *)v, cnt, uio->uio_rw == UIO_READ ?
+                           VM_PROT_READ : VM_PROT_WRITE)) {
+                               error = EFAULT;
+                               break;
+                       }
+
+                       /* Get the physical address to read */
+                       v = pmap_extract(kernel_pmap, v);
+                       if (v == 0) {
+                               error = EFAULT;
+                               break;
+                       }
+
+                       /* FALLTHROUGH */
+               case CDEV_MINOR_MEM:
+                       /* If within the DMAP use this to copy from */
+                       if (PHYS_IN_DMAP(v)) {
+                               v = PHYS_TO_DMAP(v);
+                               error = uiomove((void *)v, cnt, uio);
+                               break;
+                       }
+
+                       /* Have uiomove_fromphys handle the data */
+                       m.phys_addr = trunc_page(v);
+                       marr = &m;
+                       uiomove_fromphys(&marr, off, cnt, uio);
+                       break;
+               }
+       }
 
-       panic("ARM64TODO: memrw");
+       return (error);
 }