svn commit: r263876 - in stable/9/sys: amd64/amd64 amd64/include kern sys vm
Konstantin Belousov
kib at FreeBSD.org
Fri Mar 28 15:38:56 UTC 2014
Author: kib
Date: Fri Mar 28 15:38:54 2014
New Revision: 263876
URL: http://svnweb.freebsd.org/changeset/base/263876
Log:
MFC r263475:
Fix two issues with /dev/mem access on amd64, both causing kernel page
faults.
First, for accesses to direct map region should check for the limit by
which direct map is instantiated.
Second, for accesses to the kernel map, use a new thread private flag
TDP_DEVMEMIO, which instructs vm_fault() to return error when fault
happens on the MAP_ENTRY_NOFAULT entry, instead of panicing.
MFC r263498:
Add change forgotten in r263475. Make dmaplimit accessible outside
amd64/pmap.c.
Modified:
stable/9/sys/amd64/amd64/mem.c
stable/9/sys/amd64/amd64/pmap.c
stable/9/sys/amd64/amd64/trap.c
stable/9/sys/amd64/include/pmap.h
stable/9/sys/kern/subr_trap.c
stable/9/sys/sys/proc.h
stable/9/sys/vm/vm_fault.c
Directory Properties:
stable/9/sys/ (props changed)
stable/9/sys/sys/ (props changed)
Modified: stable/9/sys/amd64/amd64/mem.c
==============================================================================
--- stable/9/sys/amd64/amd64/mem.c Fri Mar 28 15:38:38 2014 (r263875)
+++ stable/9/sys/amd64/amd64/mem.c Fri Mar 28 15:38:54 2014 (r263876)
@@ -76,14 +76,16 @@ MALLOC_DEFINE(M_MEMDESC, "memdesc", "mem
int
memrw(struct cdev *dev, struct uio *uio, int flags)
{
- int o;
- u_long c = 0, v;
struct iovec *iov;
- int error = 0;
+ u_long c, v;
+ int error, o, sflags;
vm_offset_t addr, eaddr;
GIANT_REQUIRED;
+ error = 0;
+ c = 0;
+ sflags = curthread_pflags_set(TDP_DEVMEMIO);
while (uio->uio_resid > 0 && error == 0) {
iov = uio->uio_iov;
if (iov->iov_len == 0) {
@@ -98,7 +100,15 @@ memrw(struct cdev *dev, struct uio *uio,
kmemphys:
o = v & PAGE_MASK;
c = min(uio->uio_resid, (u_int)(PAGE_SIZE - o));
- error = uiomove((void *)PHYS_TO_DMAP(v), (int)c, uio);
+ v = PHYS_TO_DMAP(v);
+ if (v < DMAP_MIN_ADDRESS ||
+ (v > DMAP_MIN_ADDRESS + dmaplimit &&
+ v <= DMAP_MAX_ADDRESS) ||
+ pmap_kextract(v) == 0) {
+ error = EFAULT;
+ goto ret;
+ }
+ error = uiomove((void *)v, (int)c, uio);
continue;
}
else if (dev2unit(dev) == CDEV_MINOR_KMEM) {
@@ -119,22 +129,30 @@ kmemphys:
addr = trunc_page(v);
eaddr = round_page(v + c);
- if (addr < VM_MIN_KERNEL_ADDRESS)
- return (EFAULT);
- for (; addr < eaddr; addr += PAGE_SIZE)
- if (pmap_extract(kernel_pmap, addr) == 0)
- return (EFAULT);
-
+ if (addr < VM_MIN_KERNEL_ADDRESS) {
+ error = EFAULT;
+ goto ret;
+ }
+ for (; addr < eaddr; addr += PAGE_SIZE) {
+ if (pmap_extract(kernel_pmap, addr) == 0) {
+ error = EFAULT;
+ goto ret;
+ }
+ }
if (!kernacc((caddr_t)(long)v, c,
uio->uio_rw == UIO_READ ?
- VM_PROT_READ : VM_PROT_WRITE))
- return (EFAULT);
+ VM_PROT_READ : VM_PROT_WRITE)) {
+ error = EFAULT;
+ goto ret;
+ }
error = uiomove((caddr_t)(long)v, (int)c, uio);
continue;
}
/* else panic! */
}
+ret:
+ curthread_pflags_restore(sflags);
return (error);
}
Modified: stable/9/sys/amd64/amd64/pmap.c
==============================================================================
--- stable/9/sys/amd64/amd64/pmap.c Fri Mar 28 15:38:38 2014 (r263875)
+++ stable/9/sys/amd64/amd64/pmap.c Fri Mar 28 15:38:54 2014 (r263876)
@@ -210,7 +210,7 @@ vm_offset_t virtual_avail; /* VA of firs
vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */
static int ndmpdp;
-static vm_paddr_t dmaplimit;
+vm_paddr_t dmaplimit;
vm_offset_t kernel_vm_end = VM_MIN_KERNEL_ADDRESS;
pt_entry_t pg_nx;
Modified: stable/9/sys/amd64/amd64/trap.c
==============================================================================
--- stable/9/sys/amd64/amd64/trap.c Fri Mar 28 15:38:38 2014 (r263875)
+++ stable/9/sys/amd64/amd64/trap.c Fri Mar 28 15:38:54 2014 (r263876)
@@ -785,6 +785,12 @@ nogo:
frame->tf_rip = (long)curpcb->pcb_onfault;
return (0);
}
+ if ((td->td_pflags & TDP_DEVMEMIO) != 0) {
+ KASSERT(curpcb->pcb_onfault != NULL,
+ ("/dev/mem without pcb_onfault"));
+ frame->tf_rip = (long)curpcb->pcb_onfault;
+ return (0);
+ }
trap_fatal(frame, eva);
return (-1);
}
Modified: stable/9/sys/amd64/include/pmap.h
==============================================================================
--- stable/9/sys/amd64/include/pmap.h Fri Mar 28 15:38:38 2014 (r263875)
+++ stable/9/sys/amd64/include/pmap.h Fri Mar 28 15:38:54 2014 (r263876)
@@ -280,6 +280,7 @@ extern vm_paddr_t phys_avail[];
extern vm_paddr_t dump_avail[];
extern vm_offset_t virtual_avail;
extern vm_offset_t virtual_end;
+extern vm_paddr_t dmaplimit;
#define pmap_page_get_memattr(m) ((vm_memattr_t)(m)->md.pat_mode)
#define pmap_page_is_write_mapped(m) (((m)->aflags & PGA_WRITEABLE) != 0)
Modified: stable/9/sys/kern/subr_trap.c
==============================================================================
--- stable/9/sys/kern/subr_trap.c Fri Mar 28 15:38:38 2014 (r263875)
+++ stable/9/sys/kern/subr_trap.c Fri Mar 28 15:38:54 2014 (r263876)
@@ -139,6 +139,8 @@ userret(struct thread *td, struct trapfr
sched_userret(td);
KASSERT(td->td_locks == 0,
("userret: Returning with %d locks held.", td->td_locks));
+ KASSERT((td->td_pflags & TDP_DEVMEMIO) == 0,
+ ("userret: Returning with /dev/mem i/o leaked"));
KASSERT(td->td_vp_reserv == 0,
("userret: Returning while holding vnode reservation"));
KASSERT((td->td_flags & TDF_SBDRY) == 0,
Modified: stable/9/sys/sys/proc.h
==============================================================================
--- stable/9/sys/sys/proc.h Fri Mar 28 15:38:38 2014 (r263875)
+++ stable/9/sys/sys/proc.h Fri Mar 28 15:38:54 2014 (r263876)
@@ -425,6 +425,7 @@ do { \
#define TDP_RESETSPUR 0x04000000 /* Reset spurious page fault history. */
#define TDP_NERRNO 0x08000000 /* Last errno is already in td_errno */
#define TDP_UIOHELD 0x10000000 /* Current uio has pages held in td_ma */
+#define TDP_DEVMEMIO 0x20000000 /* Accessing memory for /dev/mem */
/*
* Reasons that the current thread can not be run yet.
Modified: stable/9/sys/vm/vm_fault.c
==============================================================================
--- stable/9/sys/vm/vm_fault.c Fri Mar 28 15:38:38 2014 (r263875)
+++ stable/9/sys/vm/vm_fault.c Fri Mar 28 15:38:54 2014 (r263876)
@@ -282,6 +282,10 @@ RetryFault:;
map_generation = fs.map->timestamp;
if (fs.entry->eflags & MAP_ENTRY_NOFAULT) {
+ if ((curthread->td_pflags & TDP_DEVMEMIO) != 0) {
+ vm_map_unlock_read(fs.map);
+ return (KERN_FAILURE);
+ }
panic("vm_fault: fault on nofault entry, addr: %lx",
(u_long)vaddr);
}
More information about the svn-src-stable-9
mailing list