svn commit: r262726 - head/sys/ia64/ia64

Marcel Moolenaar marcel at FreeBSD.org
Tue Mar 4 03:19:36 UTC 2014


Author: marcel
Date: Tue Mar  4 03:19:36 2014
New Revision: 262726
URL: http://svnweb.freebsd.org/changeset/base/262726

Log:
  When reading physical memory, make sure to access it using the right
  memory attributes. The same applies to the mmap(2) interface. Not
  doing so results in machine checks.
  
  We find the memory attributes in the EFI memory map, as queried by
  mem_phys2virt().

Modified:
  head/sys/ia64/ia64/mem.c

Modified: head/sys/ia64/ia64/mem.c
==============================================================================
--- head/sys/ia64/ia64/mem.c	Tue Mar  4 03:19:26 2014	(r262725)
+++ head/sys/ia64/ia64/mem.c	Tue Mar  4 03:19:36 2014	(r262726)
@@ -47,19 +47,11 @@ __FBSDID("$FreeBSD$");
 #include <sys/conf.h>
 #include <sys/fcntl.h>
 #include <sys/kernel.h>
-#include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/memrange.h>
-#include <sys/module.h>
-#include <sys/msgbuf.h>
-#include <sys/mutex.h>
-#include <sys/proc.h>
-#include <sys/signalvar.h>
 #include <sys/systm.h>
 #include <sys/uio.h>
-
-#include <machine/cpu.h>
-#include <machine/frame.h>
+#include <machine/efi.h>
 
 #include <vm/vm.h>
 #include <vm/pmap.h>
@@ -69,10 +61,25 @@ __FBSDID("$FreeBSD$");
 
 struct mem_range_softc mem_range_softc;
 
-static __inline int
-ia64_pa_access(vm_offset_t pa)
+static int
+mem_phys2virt(vm_offset_t offset, int prot, void **ptr, u_long *limit)
 {
-	return (VM_PROT_READ|VM_PROT_WRITE);
+	struct efi_md *md;
+
+	if (prot & ~(VM_PROT_READ | VM_PROT_WRITE))
+		return (EPERM);
+
+	md = efi_md_find(offset);
+	if (md == NULL)
+		return (EFAULT);
+
+	if (md->md_type == EFI_MD_TYPE_BAD)
+		return (EIO);
+
+	*ptr = (void *)((md->md_attr & EFI_MD_ATTR_WB)
+	    ? IA64_PHYS_TO_RR7(offset) : IA64_PHYS_TO_RR6(offset));
+	*limit = (md->md_pages * EFI_PAGE_SIZE) - (offset - md->md_phys);
+	return (0);
 }
 
 /* ARGSUSED */
@@ -80,10 +87,15 @@ int
 memrw(struct cdev *dev, struct uio *uio, int flags)
 {
 	struct iovec *iov;
-	vm_offset_t addr, eaddr, o, v;
-	int c, error, rw;
+	off_t ofs;
+	vm_offset_t addr;
+	void *ptr;
+	u_long limit;
+	int count, error, phys, rw;
 
 	error = 0;
+	rw = (uio->uio_rw == UIO_READ) ? VM_PROT_READ : VM_PROT_WRITE;
+
 	while (uio->uio_resid > 0 && !error) {
 		iov = uio->uio_iov;
 		if (iov->iov_len == 0) {
@@ -94,51 +106,41 @@ memrw(struct cdev *dev, struct uio *uio,
 			continue;
 		}
 
-		if (dev2unit(dev) == CDEV_MINOR_MEM) {
-			v = uio->uio_offset;
-kmemphys:
-			/* Allow reads only in RAM. */
-			rw = (uio->uio_rw == UIO_READ)
-			    ? VM_PROT_READ : VM_PROT_WRITE;
-			if ((ia64_pa_access(v) & rw) != rw) {
-				error = EFAULT;
-				c = 0;
-				break;
-			}
+		ofs = uio->uio_offset;
 
-			o = uio->uio_offset & PAGE_MASK;
-			c = min(uio->uio_resid, (int)(PAGE_SIZE - o));
-			error = uiomove((caddr_t)IA64_PHYS_TO_RR7(v), c, uio);
-			continue;
+		phys = (dev2unit(dev) == CDEV_MINOR_MEM) ? 1 : 0;
+		if (phys == 0 && ofs >= IA64_RR_BASE(6)) {
+			ofs = IA64_RR_MASK(ofs);
+			phys++;
 		}
-		else if (dev2unit(dev) == CDEV_MINOR_KMEM) {
-			v = uio->uio_offset;
-
-			if (v >= IA64_RR_BASE(6)) {
-				v = IA64_RR_MASK(v);
-				goto kmemphys;
-			}
 
-			c = min(iov->iov_len, MAXPHYS);
+		if (phys) {
+			error = mem_phys2virt(ofs, rw, &ptr, &limit);
+			if (error)
+				return (error);
+
+			count = min(uio->uio_resid, limit);
+			error = uiomove(ptr, count, uio);
+		} else {
+			ptr = (void *)ofs;
+			count = iov->iov_len;
 
 			/*
 			 * Make sure that all of the pages are currently
 			 * resident so that we don't create any zero-fill
 			 * pages.
 			 */
-			addr = trunc_page(v);
-			eaddr = round_page(v + c);
+			limit = round_page(ofs + count);
+			addr = trunc_page(ofs);
 			if (addr < VM_MAXUSER_ADDRESS)
-				return (EFAULT);
-			for (; addr < eaddr; addr += PAGE_SIZE) {
+				return (EINVAL);
+			for (; addr < limit; addr += PAGE_SIZE) {
 				if (pmap_kextract(addr) == 0)
 					return (EFAULT);
 			}
-			if (!kernacc((caddr_t)v, c, (uio->uio_rw == UIO_READ)
-			    ? VM_PROT_READ : VM_PROT_WRITE))
+			if (!kernacc(ptr, count, rw))
 				return (EFAULT);
-			error = uiomove((caddr_t)v, c, uio);
-			continue;
+			error = uiomove(ptr, count, uio);
 		}
 		/* else panic! */
 	}
@@ -153,6 +155,10 @@ int
 memmmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
     int prot, vm_memattr_t *memattr)
 {
+	void *ptr;
+	u_long limit;
+	int error;
+
 	/*
 	 * /dev/mem is the only one that makes sense through this
 	 * interface.  For /dev/kmem any physaddr we return here
@@ -160,13 +166,14 @@ memmmap(struct cdev *dev, vm_ooffset_t o
 	 * a later time.
 	 */
 	if (dev2unit(dev) != CDEV_MINOR_MEM)
-		return (-1);
+		return (ENXIO);
 
-	/*
-	 * Allow access only in RAM.
-	 */
-	if ((prot & ia64_pa_access(atop((vm_offset_t)offset))) != prot)
-		return (-1);
-	*paddr = IA64_PHYS_TO_RR7(offset);
+	error = mem_phys2virt(offset, prot, &ptr, &limit);
+	if (error)
+		return (error);
+
+	*paddr = offset;
+	*memattr = ((uintptr_t)ptr >= IA64_RR_BASE(7)) ?
+	    VM_MEMATTR_WRITE_BACK : VM_MEMATTR_UNCACHEABLE;
 	return (0);
 }


More information about the svn-src-head mailing list