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 */
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to