Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 27 Dec 2016 10:17:57 +0000 (UTC)
From:      Andriy Gapon <avg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r310630 - in head: include lib/libkvm
Message-ID:  <201612271017.uBRAHv1N026771@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: avg
Date: Tue Dec 27 10:17:56 2016
New Revision: 310630
URL: https://svnweb.freebsd.org/changeset/base/310630

Log:
  libkvm: support access to vmm guest memory, allow writes to fwmem and vmm
  
  This change consists of two parts:
  - allow libkvm to recognize /dev/vmm/* character devices as devices that
    provide access to the physical memory of a system (similarly to /dev/fwmem*)
  - allow libkvm to recognize that /dev/vmm/* and /dev/fwmem* devices provide
    access to the physical memory of live remote systems and, thus, the memory
    is writable
  
  As a result, it should be possible to run commands like
  $ kgdb -w /path/to/kernel /dev/fwmem0.0
  $ kgdb /path/to/kernel /dev/vmm/guest
  
  Reviewed by:	kib, jhb
  MFC after:	2 weeks
  Relnotes:	yes
  Sponsored by:	Panzura
  Differential Revision: https://reviews.freebsd.org/D8679

Modified:
  head/include/paths.h
  head/lib/libkvm/kvm.c
  head/lib/libkvm/kvm_private.h

Modified: head/include/paths.h
==============================================================================
--- head/include/paths.h	Tue Dec 27 09:40:07 2016	(r310629)
+++ head/include/paths.h	Tue Dec 27 10:17:56 2016	(r310630)
@@ -99,6 +99,7 @@
 #define	_PATH_VARDB	"/var/db/"
 #define	_PATH_VARRUN	"/var/run/"
 #define	_PATH_VARTMP	"/var/tmp/"
+#define	_PATH_DEVVMM	"/dev/vmm/"
 #define	_PATH_YP	"/var/yp/"
 #define	_PATH_UUCPLOCK	"/var/spool/lock/"
 

Modified: head/lib/libkvm/kvm.c
==============================================================================
--- head/lib/libkvm/kvm.c	Tue Dec 27 09:40:07 2016	(r310629)
+++ head/lib/libkvm/kvm.c	Tue Dec 27 10:17:56 2016	(r310630)
@@ -167,8 +167,10 @@ _kvm_open(kvm_t *kd, const char *uf, con
 			return (kd);
 		}
 	}
+
 	/*
-	 * This is a crash dump.
+	 * This is either a crash dump or a remote live system with its physical
+	 * memory fully accessible via a special device.
 	 * Open the namelist fd and determine the architecture.
 	 */
 	if ((kd->nlfd = open(uf, O_RDONLY | O_CLOEXEC, 0)) < 0) {
@@ -177,8 +179,11 @@ _kvm_open(kvm_t *kd, const char *uf, con
 	}
 	if (_kvm_read_kernel_ehdr(kd) < 0)
 		goto failed;
-	if (strncmp(mf, _PATH_FWMEM, strlen(_PATH_FWMEM)) == 0)
+	if (strncmp(mf, _PATH_FWMEM, strlen(_PATH_FWMEM)) == 0 ||
+	    strncmp(mf, _PATH_DEVVMM, strlen(_PATH_DEVVMM)) == 0) {
 		kd->rawdump = 1;
+		kd->writable = 1;
+	}
 	SET_FOREACH(parch, kvm_arch) {
 		if ((*parch)->ka_probe(kd)) {
 			kd->arch = *parch;
@@ -405,6 +410,15 @@ ssize_t
 kvm_write(kvm_t *kd, u_long kva, const void *buf, size_t len)
 {
 	int cc;
+	ssize_t cw;
+	off_t pa;
+	const char *cp;
+
+	if (!ISALIVE(kd) && !kd->writable) {
+		_kvm_err(kd, kd->program,
+		    "kvm_write not implemented for dead kernels");
+		return (-1);
+	}
 
 	if (ISALIVE(kd)) {
 		/*
@@ -422,12 +436,38 @@ kvm_write(kvm_t *kd, u_long kva, const v
 		} else if ((size_t)cc < len)
 			_kvm_err(kd, kd->program, "short write");
 		return (cc);
-	} else {
-		_kvm_err(kd, kd->program,
-		    "kvm_write not implemented for dead kernels");
-		return (-1);
 	}
-	/* NOTREACHED */
+
+	cp = buf;
+	while (len > 0) {
+		cc = kd->arch->ka_kvatop(kd, kva, &pa);
+		if (cc == 0)
+			return (-1);
+		if (cc > (ssize_t)len)
+			cc = len;
+		errno = 0;
+		if (lseek(kd->pmfd, pa, 0) == -1 && errno != 0) {
+			_kvm_syserr(kd, 0, _PATH_MEM);
+			break;
+		}
+		cw = write(kd->pmfd, cp, cc);
+		if (cw < 0) {
+			_kvm_syserr(kd, kd->program, "kvm_write");
+			break;
+		}
+		/*
+		 * If ka_kvatop returns a bogus value or our core file is
+		 * truncated, we might wind up seeking beyond the end of the
+		 * core file in which case the read will return 0 (EOF).
+		 */
+		if (cw == 0)
+			break;
+		cp += cw;
+		kva += cw;
+		len -= cw;
+	}
+
+	return (cp - (char *)buf);
 }
 
 int

Modified: head/lib/libkvm/kvm_private.h
==============================================================================
--- head/lib/libkvm/kvm_private.h	Tue Dec 27 09:40:07 2016	(r310629)
+++ head/lib/libkvm/kvm_private.h	Tue Dec 27 10:17:56 2016	(r310630)
@@ -78,6 +78,7 @@ struct __kvm {
 	 */
 	struct vmstate *vmst;
 	int	rawdump;	/* raw dump format */
+	int	writable;	/* physical memory is writable */
 
 	int		vnet_initialized;	/* vnet fields set up */
 	kvaddr_t	vnet_start;	/* start of kernel's vnet region */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201612271017.uBRAHv1N026771>