summaryrefslogtreecommitdiffstats
path: root/sys/ia64
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2014-07-02 23:12:56 +0000
committermarcel <marcel@FreeBSD.org>2014-07-02 23:12:56 +0000
commit69fcf37dcff34e2d7a0ae33364c143f015d8e745 (patch)
tree115b9e5f7999dc49e6ef43e71e6a36252ae3b4b8 /sys/ia64
parentee8a73303bef55593e41438b51ca8a50974ab4b9 (diff)
downloadFreeBSD-src-69fcf37dcff34e2d7a0ae33364c143f015d8e745.zip
FreeBSD-src-69fcf37dcff34e2d7a0ae33364c143f015d8e745.tar.gz
MFC r262726: When reading physical memory, make sure to access it using
the right memory attributes.
Diffstat (limited to 'sys/ia64')
-rw-r--r--sys/ia64/ia64/mem.c109
1 files changed, 58 insertions, 51 deletions
diff --git a/sys/ia64/ia64/mem.c b/sys/ia64/ia64/mem.c
index 70dcf7b..253e5d4 100644
--- a/sys/ia64/ia64/mem.c
+++ b/sys/ia64/ia64/mem.c
@@ -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, int flags)
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;
- }
+ if (phys) {
+ error = mem_phys2virt(ofs, rw, &ptr, &limit);
+ if (error)
+ return (error);
- c = min(iov->iov_len, MAXPHYS);
+ 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 offset, vm_paddr_t *paddr,
* 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);
}
OpenPOWER on IntegriCloud