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. */ }