From owner-svn-src-head@freebsd.org Tue Dec 27 10:17:58 2016 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 5A071C8FEBE; Tue, 27 Dec 2016 10:17:58 +0000 (UTC) (envelope-from avg@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 34A8D1AC1; Tue, 27 Dec 2016 10:17:58 +0000 (UTC) (envelope-from avg@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id uBRAHvsv026774; Tue, 27 Dec 2016 10:17:57 GMT (envelope-from avg@FreeBSD.org) Received: (from avg@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id uBRAHv1N026771; Tue, 27 Dec 2016 10:17:57 GMT (envelope-from avg@FreeBSD.org) Message-Id: <201612271017.uBRAHv1N026771@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: avg set sender to avg@FreeBSD.org using -f From: Andriy Gapon Date: Tue, 27 Dec 2016 10:17:57 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r310630 - in head: include lib/libkvm X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 27 Dec 2016 10:17:58 -0000 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 */