diff options
author | avg <avg@FreeBSD.org> | 2017-01-18 14:13:28 +0000 |
---|---|---|
committer | avg <avg@FreeBSD.org> | 2017-01-18 14:13:28 +0000 |
commit | fefedac602874fa19643279757c8069e48c5e97b (patch) | |
tree | 99865ea3dbfb592781e8ab0380a14589a6549586 /lib/libkvm | |
parent | 932a15f5a8fefeb697d2dcd8d08dcbc3c1dcc6aa (diff) | |
download | FreeBSD-src-fefedac602874fa19643279757c8069e48c5e97b.zip FreeBSD-src-fefedac602874fa19643279757c8069e48c5e97b.tar.gz |
MFC r310630: libkvm: support access to vmm guest memory, allow writes to
fwmem and vmm
Sponsored by: Panzura
Diffstat (limited to 'lib/libkvm')
-rw-r--r-- | lib/libkvm/kvm.c | 54 | ||||
-rw-r--r-- | lib/libkvm/kvm_private.h | 1 |
2 files changed, 48 insertions, 7 deletions
diff --git a/lib/libkvm/kvm.c b/lib/libkvm/kvm.c index 5ad8dcc..c8c34f2 100644 --- a/lib/libkvm/kvm.c +++ b/lib/libkvm/kvm.c @@ -429,8 +429,10 @@ _kvm_open(kvm_t *kd, const char *uf, const char *mf, int flag, char *errout) 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) { @@ -439,8 +441,11 @@ _kvm_open(kvm_t *kd, const char *uf, const char *mf, int flag, char *errout) } 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; @@ -866,6 +871,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)) { /* @@ -883,12 +897,38 @@ kvm_write(kvm_t *kd, u_long kva, const void *buf, size_t len) } 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 diff --git a/lib/libkvm/kvm_private.h b/lib/libkvm/kvm_private.h index 78b4845..3a31120 100644 --- a/lib/libkvm/kvm_private.h +++ b/lib/libkvm/kvm_private.h @@ -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 */ |