Module Name: src
Committed By: nakayama
Date: Mon Dec 7 11:28:37 UTC 2009
Modified Files:
src/sys/arch/sparc64/sparc64: machdep.c
Log Message:
- fix corner case bugs around the segment offsets.
- make sure that on error condition we return "no valid mappings".
To generate a diff of this commit:
cvs rdiff -u -r1.249 -r1.250 src/sys/arch/sparc64/sparc64/machdep.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/sparc64/sparc64/machdep.c
diff -u src/sys/arch/sparc64/sparc64/machdep.c:1.249 src/sys/arch/sparc64/sparc64/machdep.c:1.250
--- src/sys/arch/sparc64/sparc64/machdep.c:1.249 Wed Dec 2 10:18:42 2009
+++ src/sys/arch/sparc64/sparc64/machdep.c Mon Dec 7 11:28:37 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: machdep.c,v 1.249 2009/12/02 10:18:42 nakayama Exp $ */
+/* $NetBSD: machdep.c,v 1.250 2009/12/07 11:28:37 nakayama Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
@@ -71,7 +71,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.249 2009/12/02 10:18:42 nakayama Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.250 2009/12/07 11:28:37 nakayama Exp $");
#include "opt_ddb.h"
#include "opt_multiprocessor.h"
@@ -1037,7 +1037,6 @@
/*
* We always use just one segment.
*/
- map->dm_mapsize = buflen;
i = 0;
map->dm_segs[i].ds_addr = 0UL;
map->dm_segs[i].ds_len = 0;
@@ -1049,23 +1048,24 @@
incr = min(sgsize, incr);
(void) pmap_extract(pmap_kernel(), vaddr, &pa);
- sgsize -= incr;
- vaddr += incr;
if (map->dm_segs[i].ds_len == 0)
map->dm_segs[i].ds_addr = pa;
if (pa == (map->dm_segs[i].ds_addr + map->dm_segs[i].ds_len)
&& ((map->dm_segs[i].ds_len + incr) <= map->dm_maxsegsz)) {
/* Hey, waddyaknow, they're contiguous */
map->dm_segs[i].ds_len += incr;
- incr = PAGE_SIZE;
- continue;
+ } else {
+ if (++i >= map->_dm_segcnt)
+ return (EFBIG);
+ map->dm_segs[i].ds_addr = pa;
+ map->dm_segs[i].ds_len = incr;
}
- if (++i >= map->_dm_segcnt)
- return (EFBIG);
- map->dm_segs[i].ds_addr = pa;
- map->dm_segs[i].ds_len = incr = PAGE_SIZE;
+ sgsize -= incr;
+ vaddr += incr;
+ incr = PAGE_SIZE;
}
map->dm_nsegs = i + 1;
+ map->dm_mapsize = buflen;
/* Mapping is bus dependent */
return (0);
}
@@ -1081,8 +1081,15 @@
int i;
size_t len;
+ /*
+ * Make sure that on error condition we return "no valid mappings".
+ */
+ map->dm_nsegs = 0;
KASSERT(map->dm_maxsegsz <= map->_dm_maxmaxsegsz);
+ if (m->m_pkthdr.len > map->_dm_size)
+ return EINVAL;
+
/* Record mbuf for *_unload */
map->_dm_type = _DM_TYPE_MBUF;
map->_dm_source = (void *)m;
@@ -1194,6 +1201,10 @@
struct proc *p = uio->uio_lwp->l_proc;
struct pmap *pm;
+ /*
+ * Make sure that on error condition we return "no valid mappings".
+ */
+ map->dm_nsegs = 0;
KASSERT(map->dm_maxsegsz <= map->_dm_maxmaxsegsz);
if (uio->uio_segflg == UIO_USERSPACE) {
@@ -1346,16 +1357,21 @@
if (offset < PAGE_SIZE) {
start = VM_PAGE_TO_PHYS(pg) + offset;
+ size -= offset;
if (size > len)
size = len;
cache_flush_phys(start, size, 0);
len -= size;
+ if (len == 0)
+ goto done;
+ offset = 0;
continue;
}
offset -= size;
}
}
}
+ done:
if (ops & BUS_DMASYNC_POSTWRITE) {
/* Nothing to do. Handled by the bus controller. */
}