svn commit: r359160 - head/sys/powerpc/powerpc

Alfredo Dal'Ava Junior alfredo at FreeBSD.org
Fri Mar 20 11:51:09 UTC 2020


Author: alfredo
Date: Fri Mar 20 11:51:08 2020
New Revision: 359160
URL: https://svnweb.freebsd.org/changeset/base/359160

Log:
  [PowerPC] fix panic reading /dev/kmem on !DMAP machines
  
  This fixes /dev/kmem causing panic on machines not using DMAP.
  
  Found when running libkvm Kyua test case on QEMU VM with no
  Huge Pages support.
  
  Reviewed by:	jhibbits, luporl
  Approved by:	jhibbits (mentor)
  Sponsored by:	Eldorado Research Institute (eldorado.org.br)
  Differential Revision:	https://reviews.freebsd.org/D23776

Modified:
  head/sys/powerpc/powerpc/mem.c

Modified: head/sys/powerpc/powerpc/mem.c
==============================================================================
--- head/sys/powerpc/powerpc/mem.c	Fri Mar 20 05:12:16 2020	(r359159)
+++ head/sys/powerpc/powerpc/mem.c	Fri Mar 20 11:51:08 2020	(r359160)
@@ -98,9 +98,11 @@ memrw(struct cdev *dev, struct uio *uio, int flags)
 	struct vm_page m;
 	vm_page_t marr;
 	vm_size_t cnt;
+	ssize_t orig_resid;
 
 	cnt = 0;
 	error = 0;
+	orig_resid = uio->uio_resid;
 
 	while (uio->uio_resid > 0 && !error) {
 		iov = uio->uio_iov;
@@ -137,7 +139,8 @@ kmem_direct_mapped:	off = v & PAGE_MASK;
 		else if (dev2unit(dev) == CDEV_MINOR_KMEM) {
 			va = uio->uio_offset;
 
-			if ((va < VM_MIN_KERNEL_ADDRESS) || (va > virtual_end)) {
+			if (hw_direct_map &&
+			    ((va < VM_MIN_KERNEL_ADDRESS) || (va > virtual_end))) {
 				v = DMAP_TO_PHYS(va);
 				goto kmem_direct_mapped;
 			}
@@ -151,24 +154,34 @@ kmem_direct_mapped:	off = v & PAGE_MASK;
 			 * so that we don't create any zero-fill pages.
 			 */
 
-			for (; va < eva; va += PAGE_SIZE)
-				if (pmap_extract(kernel_pmap, va) == 0)
-					return (EFAULT);
+			for (; va < eva; va += PAGE_SIZE) {
+				if (pmap_extract(kernel_pmap, va) == 0) {
+					error = EFAULT;
+					break;
+				}
+			}
+			if (error != 0)
+				break;
 
 			prot = (uio->uio_rw == UIO_READ)
 			    ? VM_PROT_READ : VM_PROT_WRITE;
 
 			va = uio->uio_offset;
-			if (kernacc((void *) va, iov->iov_len, prot)
-			    == FALSE)
-				return (EFAULT);
+			if (((va >= VM_MIN_KERNEL_ADDRESS) && (va <= virtual_end)) &&
+			    !kernacc((void *) va, iov->iov_len, prot)) {
+				error = EFAULT;
+				break;
+			}
 
 			error = uiomove((void *)va, iov->iov_len, uio);
-
-			continue;
 		}
 	}
-
+	/*
+	 * Don't return error if any byte was written.  Read and write
+	 * can return error only if no i/o was performed.
+	 */
+	if (uio->uio_resid != orig_resid)
+		error = 0;
 	return (error);
 }
 


More information about the svn-src-all mailing list