Date: Tue, 4 Mar 2014 03:19:36 +0000 (UTC) From: Marcel Moolenaar <marcel@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r262726 - head/sys/ia64/ia64 Message-ID: <201403040319.s243JaNt074630@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201403040319.s243JaNt074630>